SECURITY: CVE-2009-2412 (cve.mitre.org)
Fix overflow in rmm, where size alignment was taking place.

Reported by: Matt Lewis <[email protected]>

* misc/apr_rmm.c
 (apr_rmm_malloc, apr_rmm_calloc, apr_rmm_realloc): Check for overflow after aligning size.

SEE ALSO: apr-1.x-CVE-2009-2412.patch

Index: misc/apr_rmm.c
===================================================================
--- misc/apr_rmm.c      (revision 800339)
+++ misc/apr_rmm.c      (working copy)
@@ -306,13 +306,17 @@

APU_DECLARE(apr_rmm_off_t) apr_rmm_malloc(apr_rmm_t *rmm, apr_size_t reqsize)
{
+    apr_size_t size;
    apr_rmm_off_t this;

-    reqsize = APR_ALIGN_DEFAULT(reqsize) + RMM_BLOCK_SIZE;
+    size = APR_ALIGN_DEFAULT(reqsize) + RMM_BLOCK_SIZE;
+    if (size < reqsize) {
+        return 0;
+    }

    APR_ANYLOCK_LOCK(&rmm->lock);

-    this = find_block_of_size(rmm, reqsize);
+    this = find_block_of_size(rmm, size);

    if (this) {
        move_block(rmm, this, 0);
@@ -325,18 +329,22 @@

APU_DECLARE(apr_rmm_off_t) apr_rmm_calloc(apr_rmm_t *rmm, apr_size_t reqsize)
{
+    apr_size_t size;
    apr_rmm_off_t this;

-    reqsize = APR_ALIGN_DEFAULT(reqsize) + RMM_BLOCK_SIZE;
+    size = APR_ALIGN_DEFAULT(reqsize) + RMM_BLOCK_SIZE;
+    if (size < reqsize) {
+        return 0;
+    }

    APR_ANYLOCK_LOCK(&rmm->lock);

-    this = find_block_of_size(rmm, reqsize);
+    this = find_block_of_size(rmm, size);

    if (this) {
        move_block(rmm, this, 0);
        this += RMM_BLOCK_SIZE;
-        memset((char*)rmm->base + this, 0, reqsize - RMM_BLOCK_SIZE);
+        memset((char*)rmm->base + this, 0, size - RMM_BLOCK_SIZE);
    }

    APR_ANYLOCK_UNLOCK(&rmm->lock);
@@ -349,16 +357,19 @@
    apr_rmm_off_t this;
    apr_rmm_off_t old;
    struct rmm_block_t *blk;
-    apr_size_t oldsize;
+    apr_size_t size, oldsize;

    if (!entity) {
        return apr_rmm_malloc(rmm, reqsize);
    }

-    reqsize = APR_ALIGN_DEFAULT(reqsize);
+    size = APR_ALIGN_DEFAULT(reqsize);
+    if (size < reqsize) {
+        return 0;
+    }
    old = apr_rmm_offset_get(rmm, entity);

-    if ((this = apr_rmm_malloc(rmm, reqsize)) == 0) {
+    if ((this = apr_rmm_malloc(rmm, size)) == 0) {
        return 0;
    }

@@ -366,7 +377,7 @@
    oldsize = blk->size;

    memcpy(apr_rmm_addr_get(rmm, this),
-           apr_rmm_addr_get(rmm, old), oldsize < reqsize ? oldsize : reqsize);
+           apr_rmm_addr_get(rmm, old), oldsize < size ? oldsize : size);
    apr_rmm_free(rmm, old);

    return this;