You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by jc...@apache.org on 2016/12/06 17:07:19 UTC

svn commit: r1772919 - in /httpd/httpd/trunk: CHANGES modules/aaa/mod_auth_digest.c

Author: jchampion
Date: Tue Dec  6 17:07:19 2016
New Revision: 1772919

URL: http://svn.apache.org/viewvc?rev=1772919&view=rev
Log:
mod_auth_digest: fix segfaults during shared memory exhaustion

The apr_rmm_addr_get/apr_rmm_malloc() combination did not correctly
check for a malloc failure, leading to crashes when we ran out of the
limited space provided by AuthDigestShmemSize. This patch replaces all
these calls with a helper function that performs this check.

Additionally, fix a NULL-check bug during entry garbage collection.

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/modules/aaa/mod_auth_digest.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=1772919&r1=1772918&r2=1772919&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Tue Dec  6 17:07:19 2016
@@ -1,6 +1,11 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.5.0
 
+  *) SECURITY: CVE-2016-2161 (cve.mitre.org)
+     mod_auth_digest: Prevent segfaults during client entry allocation when the
+     shared memory space is exhausted. [Maksim Malyutin <m.malyutin dsec.ru>,
+     Eric Covener, Jacob Champion]
+
   *) SECURITY: CVE-2016-0736 (cve.mitre.org)
      mod_session_crypto: Authenticate the session data/cookie with a
      MAC (SipHash) to prevent deciphering or tampering with a padding

Modified: httpd/httpd/trunk/modules/aaa/mod_auth_digest.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/aaa/mod_auth_digest.c?rev=1772919&r1=1772918&r2=1772919&view=diff
==============================================================================
--- httpd/httpd/trunk/modules/aaa/mod_auth_digest.c (original)
+++ httpd/httpd/trunk/modules/aaa/mod_auth_digest.c Tue Dec  6 17:07:19 2016
@@ -230,6 +230,26 @@ static void log_error_and_cleanup(char *
     cleanup_tables(NULL);
 }
 
+/* RMM helper functions that behave like single-step malloc/free. */
+
+static void *rmm_malloc(apr_rmm_t *rmm, apr_size_t size)
+{
+    apr_rmm_off_t offset = apr_rmm_malloc(rmm, size);
+
+    if (!offset) {
+        return NULL;
+    }
+
+    return apr_rmm_addr_get(rmm, offset);
+}
+
+static apr_status_t rmm_free(apr_rmm_t *rmm, void *alloc)
+{
+    apr_rmm_off_t offset = apr_rmm_offset_get(rmm, alloc);
+
+    return apr_rmm_free(rmm, offset);
+}
+
 #if APR_HAS_SHARED_MEMORY
 
 static int initialize_tables(server_rec *s, apr_pool_t *ctx)
@@ -277,8 +297,8 @@ static int initialize_tables(server_rec
         return !OK;
     }
 
-    client_list = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*client_list) +
-                                                          sizeof(client_entry*)*num_buckets));
+    client_list = rmm_malloc(client_rmm, sizeof(*client_list) +
+                                         sizeof(client_entry *) * num_buckets);
     if (!client_list) {
         log_error_and_cleanup("failed to allocate shared memory", -1, s);
         return !OK;
@@ -300,7 +320,7 @@ static int initialize_tables(server_rec
 
     /* setup opaque */
 
-    opaque_cntr = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*opaque_cntr)));
+    opaque_cntr = rmm_malloc(client_rmm, sizeof(*opaque_cntr));
     if (opaque_cntr == NULL) {
         log_error_and_cleanup("failed to allocate shared memory", -1, s);
         return !OK;
@@ -317,7 +337,7 @@ static int initialize_tables(server_rec
 
     /* setup one-time-nonce counter */
 
-    otn_counter = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*otn_counter)));
+    otn_counter = rmm_malloc(client_rmm, sizeof(*otn_counter));
     if (otn_counter == NULL) {
         log_error_and_cleanup("failed to allocate shared memory", -1, s);
         return !OK;
@@ -775,7 +795,7 @@ static client_entry *get_client(unsigned
  * last entry in each bucket and updates the counters. Returns the
  * number of removed entries.
  */
-static long gc(void)
+static long gc(server_rec *s)
 {
     client_entry *entry, *prev;
     unsigned long num_removed = 0, idx;
@@ -785,6 +805,12 @@ static long gc(void)
     for (idx = 0; idx < client_list->tbl_len; idx++) {
         entry = client_list->table[idx];
         prev  = NULL;
+
+        if (!entry) {
+            /* This bucket is empty. */
+            continue;
+        }
+
         while (entry->next) {   /* find last entry */
             prev  = entry;
             entry = entry->next;
@@ -796,8 +822,16 @@ static long gc(void)
             client_list->table[idx] = NULL;
         }
         if (entry) {                    /* remove entry */
-            apr_rmm_free(client_rmm, apr_rmm_offset_get(client_rmm, entry));
+            apr_status_t err;
+
+            err = rmm_free(client_rmm, entry);
             num_removed++;
+
+            if (err) {
+                /* Nothing we can really do but log... */
+                ap_log_error(APLOG_MARK, APLOG_ERR, err, s, APLOGNO()
+                             "Failed to free auth_digest client allocation");
+            }
         }
     }
 
@@ -831,16 +865,16 @@ static client_entry *add_client(unsigned
 
     /* try to allocate a new entry */
 
-    entry = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(client_entry)));
+    entry = rmm_malloc(client_rmm, sizeof(client_entry));
     if (!entry) {
-        long num_removed = gc();
+        long num_removed = gc(s);
         ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01766)
                      "gc'd %ld client entries. Total new clients: "
                      "%ld; Total removed clients: %ld; Total renewed clients: "
                      "%ld", num_removed,
                      client_list->num_created - client_list->num_renewed,
                      client_list->num_removed, client_list->num_renewed);
-        entry = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(client_entry)));
+        entry = rmm_malloc(client_rmm, sizeof(client_entry));
         if (!entry) {
             ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01767)
                          "unable to allocate new auth_digest client");