File httpd-2.2.x-bnc741243-CVE-2012-0031-scoreboard_handling.diff of Package apache2.openSUSE_12.1_Update
http://www.halfdog.net/Security/2011/ApacheScoreboardInvalidFreeOnShutdown/
(credits: halfdog)
upstream changeset: https://svn.apache.org/viewvc?view=revision&revision=1230065
not implemented from upstream due to binary incompatibility:
change of struct global_score
The change below is sufficient to fix the bug.
This vulnerability is rated low impact.
Tue Feb 14 02:37:14 CET 2012
Roman.
diff -rNU 30 ../httpd-2.2.21-o/server/scoreboard.c ./server/scoreboard.c
--- ../httpd-2.2.21-o/server/scoreboard.c 2010-10-07 18:56:54.000000000 +0200
+++ ./server/scoreboard.c 2012-02-14 02:35:30.000000000 +0100
@@ -14,60 +14,61 @@
* limitations under the License.
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_portable.h"
#include "apr_lib.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
#if APR_HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include "ap_config.h"
#include "httpd.h"
#include "http_log.h"
#include "http_main.h"
#include "http_core.h"
#include "http_config.h"
#include "ap_mpm.h"
#include "mpm.h"
#include "scoreboard.h"
AP_DECLARE_DATA scoreboard *ap_scoreboard_image = NULL;
AP_DECLARE_DATA const char *ap_scoreboard_fname = NULL;
AP_DECLARE_DATA int ap_extended_status = 0;
AP_DECLARE_DATA int ap_mod_status_reqtail = 0;
+static ap_scoreboard_e scoreboard_type;
#if APR_HAS_SHARED_MEMORY
#include "apr_shm.h"
#ifndef WIN32
static /* but must be exported to mpm_winnt */
#endif
apr_shm_t *ap_scoreboard_shm = NULL;
#endif
APR_HOOK_STRUCT(
APR_HOOK_LINK(pre_mpm)
)
AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_mpm,
(apr_pool_t *p, ap_scoreboard_e sb_type),
(p, sb_type),OK,DECLINED)
static APR_OPTIONAL_FN_TYPE(ap_proxy_lb_workers)
*proxy_lb_workers;
struct ap_sb_handle_t {
int child_num;
int thread_num;
};
static int server_limit, thread_limit, lb_limit;
static apr_size_t scoreboard_size;
@@ -223,61 +224,61 @@
/* If detach is non-zero, this is a seperate child process,
* if zero, it is a forked child.
*/
apr_status_t ap_reopen_scoreboard(apr_pool_t *p, apr_shm_t **shm, int detached)
{
#if APR_HAS_SHARED_MEMORY
if (!detached) {
return APR_SUCCESS;
}
if (apr_shm_size_get(ap_scoreboard_shm) < scoreboard_size) {
ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
"Fatal error: shared scoreboard too small for child!");
apr_shm_detach(ap_scoreboard_shm);
ap_scoreboard_shm = NULL;
return APR_EINVAL;
}
/* everything will be cleared shortly */
if (*shm) {
*shm = ap_scoreboard_shm;
}
#endif
return APR_SUCCESS;
}
apr_status_t ap_cleanup_scoreboard(void *d)
{
if (ap_scoreboard_image == NULL) {
return APR_SUCCESS;
}
- if (ap_scoreboard_image->global->sb_type == SB_SHARED) {
+ if (scoreboard_type == SB_SHARED) {
ap_cleanup_shared_mem(NULL);
}
else {
free(ap_scoreboard_image->global);
free(ap_scoreboard_image);
ap_scoreboard_image = NULL;
}
return APR_SUCCESS;
}
/* Create or reinit an existing scoreboard. The MPM can control whether
* the scoreboard is shared across multiple processes or not
*/
int ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e sb_type)
{
int i;
#if APR_HAS_SHARED_MEMORY
apr_status_t rv;
#endif
if (ap_scoreboard_image) {
ap_scoreboard_image->global->restart_time = apr_time_now();
memset(ap_scoreboard_image->parent, 0,
sizeof(process_score) * server_limit);
for (i = 0; i < server_limit; i++) {
memset(ap_scoreboard_image->servers[i], 0,
sizeof(worker_score) * thread_limit);
}
/* Clean up the lb workers data */
if (lb_limit) {
@@ -286,60 +287,61 @@
}
return OK;
}
ap_calc_scoreboard_size();
#if APR_HAS_SHARED_MEMORY
if (sb_type == SB_SHARED) {
void *sb_shared;
rv = open_scoreboard(p);
if (rv || !(sb_shared = apr_shm_baseaddr_get(ap_scoreboard_shm))) {
return HTTP_INTERNAL_SERVER_ERROR;
}
memset(sb_shared, 0, scoreboard_size);
ap_init_scoreboard(sb_shared);
}
else
#endif
{
/* A simple malloc will suffice */
void *sb_mem = calloc(1, scoreboard_size);
if (sb_mem == NULL) {
ap_log_error(APLOG_MARK, APLOG_CRIT, 0, NULL,
"(%d)%s: cannot allocate scoreboard",
errno, strerror(errno));
return HTTP_INTERNAL_SERVER_ERROR;
}
ap_init_scoreboard(sb_mem);
}
ap_scoreboard_image->global->sb_type = sb_type;
+ scoreboard_type = sb_type;
ap_scoreboard_image->global->running_generation = 0;
ap_scoreboard_image->global->restart_time = apr_time_now();
apr_pool_cleanup_register(p, NULL, ap_cleanup_scoreboard, apr_pool_cleanup_null);
return OK;
}
/* Routines called to deal with the scoreboard image
* --- note that we do *not* need write locks, since update_child_status
* only updates a *single* record in place, and only one process writes to
* a given scoreboard slot at a time (either the child process owning that
* slot, or the parent, noting that the child has died).
*
* As a final note --- setting the score entry to getpid() is always safe,
* since when the parent is writing an entry, it's only noting SERVER_DEAD
* anyway.
*/
AP_DECLARE(int) ap_exists_scoreboard_image(void)
{
return (ap_scoreboard_image ? 1 : 0);
}
AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r)
{
worker_score *ws;
if (!sb)
return;