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;
openSUSE Build Service is sponsored by