summaryrefslogtreecommitdiffstats
path: root/modules/aaa/mod_auth_digest.c
diff options
context:
space:
mode:
authorJacob Champion <jchampion@apache.org>2016-12-06 18:07:19 +0100
committerJacob Champion <jchampion@apache.org>2016-12-06 18:07:19 +0100
commit4354842828c7f9133238d11a6279960986d1bd5e (patch)
tree5638fdd9b9c591558a58a7153307e38b304352b4 /modules/aaa/mod_auth_digest.c
parentmod_session_crypto: follow up to r1772812: CHANGES entry. (diff)
downloadapache2-4354842828c7f9133238d11a6279960986d1bd5e.tar.xz
apache2-4354842828c7f9133238d11a6279960986d1bd5e.zip
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. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1772919 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to '')
-rw-r--r--modules/aaa/mod_auth_digest.c52
1 files changed, 43 insertions, 9 deletions
diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c
index d9b6f3410f..a7140e28ca 100644
--- a/modules/aaa/mod_auth_digest.c
+++ b/modules/aaa/mod_auth_digest.c
@@ -230,6 +230,26 @@ static void log_error_and_cleanup(char *msg, apr_status_t sts, server_rec *s)
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 *s, apr_pool_t *ctx)
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 *s, apr_pool_t *ctx)
/* 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 *s, apr_pool_t *ctx)
/* 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 long key, const request_rec *r)
* 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 long key, client_entry *info,
/* 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");