Attached is a patch for the mmap bucket cleanup issue.  The caveats are
that it only works if:

 - if the apr_mmap_t passed to apr_bucket_mmap_create/make is the owner of
   the mmaped region, the mmap buckets code assumes complete
   responsibility for it.  In particular, external code should NEVER call
   apr_mmap_delete or apr_mmap_dup (transferring ownership) on that
   apr_mmap_t after it's been placed in the bucket.

 - if the apr_mmap_t passed to apr_bucket_mmap_create/make is NOT the
   owner of the mmaped region, then the creator of the bucket is
   absolutely guaranteeing us that the apr_mmap_t will live longer than
   the bucket.

I think this matches the existing semantics, so it shouldn't be that big a
deal.  HOWEVER, note that this patch causes two of the apache/limits.t
tests (7 and 9) to fail with an assertion pop, though I think this
represents a legitimate bug in Apache.  Basically, the buckets code now
enforces the fact that you absolutely positively CANNOT access an mmap
bucket except to delete it after the apr_mmap_t in it gets cleaned up.

--Cliff


This backtrace is from test 7 of limits.t:

Program received signal SIGABRT, Aborted.
0x403139d1 in kill () from /lib/libc.so.6
(gdb) bt
#0  0x403139d1 in kill () from /lib/libc.so.6
#1  0x402d9c9e in pthread_kill () from /lib/libpthread.so.0
#2  0x402da16d in raise () from /lib/libpthread.so.0
#3  0x40314e31 in abort () from /lib/libc.so.6
#4  0x806a329 in ap_log_assert (szExp=0x80a34db "readbytes > 0",
    szFile=0x80a33a4 "http_protocol.c", nLine=886) at log.c:642
#5  0x805f157 in ap_http_filter (f=0x819e4b8, b=0x819eaa8,
    mode=AP_MODE_GETLINE, block=APR_BLOCK_READ, readbytes=0)
    at http_protocol.c:886
#6  0x8073142 in ap_get_brigade (next=0x819e4b8, bb=0x819eaa8,
    mode=AP_MODE_GETLINE, block=APR_BLOCK_READ, readbytes=0)
    at util_filter.c:507
#7  0x807c58a in net_time_filter (f=0x819dd50, b=0x819eaa8,
    mode=AP_MODE_GETLINE, block=APR_BLOCK_READ, readbytes=0) at
core.c:3278
#8  0x8073142 in ap_get_brigade (next=0x819dd50, bb=0x819eaa8,
    mode=AP_MODE_GETLINE, block=APR_BLOCK_READ, readbytes=0)
    at util_filter.c:507
#9  0x807450b in ap_rgetline_core (s=0xbfffcd98, n=30, read=0xbfffcd90,
    r=0x819d5b0, fold=0) at protocol.c:222
#10 0x8074b24 in ap_getline (s=0xbfffcdc8 "\016", n=30, r=0x819d5b0,
fold=0)
    at protocol.c:538
#11 0x805ef2c in ap_http_filter (f=0x819e4b8, b=0x819dd30,
    mode=AP_MODE_READBYTES, block=APR_BLOCK_READ, readbytes=8192)
    at http_protocol.c:835
#12 0x8073142 in ap_get_brigade (next=0x819e4b8, bb=0x819dd30,
    mode=AP_MODE_READBYTES, block=APR_BLOCK_READ, readbytes=8192)
    at util_filter.c:507
#13 0x807c58a in net_time_filter (f=0x819dd50, b=0x819dd30,
    mode=AP_MODE_READBYTES, block=APR_BLOCK_READ, readbytes=8192)
    at core.c:3278
#14 0x8073142 in ap_get_brigade (next=0x819dd50, bb=0x819dd30,
    mode=AP_MODE_READBYTES, block=APR_BLOCK_READ, readbytes=8192)
    at util_filter.c:507
#15 0x8060640 in ap_get_client_block (r=0x819d5b0, buffer=0xbfffcf78
"\004",
    bufsiz=8192) at http_protocol.c:1663
#16 0x80608d8 in ap_discard_request_body (r=0x819d5b0) at
http_protocol.c:1757
#17 0x807c074 in default_handler (r=0x819d5b0) at core.c:3166
#18 0x8065f81 in ap_run_handler (r=0x819d5b0) at config.c:193
#19 0x80666be in ap_invoke_handler (r=0x819d5b0) at config.c:373
#20 0x8062e18 in ap_process_request (r=0x819d5b0) at http_request.c:261
#21 0x805d77e in ap_process_http_connection (c=0x8193658) at
http_core.c:291
#22 0x8070bc1 in ap_run_process_connection (c=0x8193658) at
connection.c:85
#23 0x8070fb0 in ap_process_connection (c=0x8193658, csd=0x8193588)
    at connection.c:207
#24 0x8064737 in child_main (child_num_arg=0) at prefork.c:671
#25 0x806481d in make_child (s=0x80bfff0, slot=0) at prefork.c:711
#26 0x8064954 in startup_children (number_to_start=2) at prefork.c:783
#27 0x8064d86 in ap_mpm_run (_pconf=0x80be2a0, plog=0x80e8348,
s=0x80bfff0)
    at prefork.c:999
#28 0x806b6c3 in main (argc=7, argv=0xbffff2e4) at main.c:632


--------------------------------------------------------------
   Cliff Woolley
   [EMAIL PROTECTED]
   Charlottesville, VA

Index: apr_buckets_mmap.c
===================================================================
RCS file: /home/cvs/apr-util/buckets/apr_buckets_mmap.c,v
retrieving revision 1.49
diff -u -d -r1.49 apr_buckets_mmap.c
--- apr_buckets_mmap.c  18 Apr 2002 18:34:27 -0000      1.49
+++ apr_buckets_mmap.c  18 Apr 2002 20:29:53 -0000
@@ -63,6 +63,11 @@
     apr_status_t ok;
     void *addr;
     
+    if (!m->mmap) {
+        /* due to cleanup issues we have no choice but to check this */
+        return APR_EINVAL;
+    }
+
     ok = apr_mmap_offset(&addr, m->mmap, b->start);
     if (ok != APR_SUCCESS) {
         return ok;
@@ -72,14 +77,27 @@
     return APR_SUCCESS;
 }
 
+static apr_status_t mmap_bucket_cleanup(void *data)
+{
+    /* the mmap has disappeared out from under us.  we have no choice
+     * but to invalidate this bucket.  from now on, all you can do to this
+     * bucket is destroy it, not read from it.
+     */
+    apr_bucket_mmap *m = data;
+
+    m->mmap = NULL;
+    return APR_SUCCESS;
+}
+
 static void mmap_bucket_destroy(void *data)
 {
     apr_bucket_mmap *m = data;
 
     if (apr_bucket_shared_destroy(m)) {
-        /* if we are the owner of the mmaped region, apr_mmap_delete will
-         * munmap it for us.  if we're not, it's essentially a noop. */
-        apr_mmap_delete(m->mmap);
+        if (m->mmap && m->mmap->is_owner) {
+            apr_pool_cleanup_kill(m->mmap->cntxt, m, mmap_bucket_cleanup);
+            apr_mmap_delete(m->mmap);
+        }
         apr_bucket_free(m);
     }
 }
@@ -96,6 +114,11 @@
     m = apr_bucket_alloc(sizeof(*m), b->list);
     m->mmap = mm;
 
+    if (mm->is_owner) {
+        apr_pool_cleanup_register(mm->cntxt, m, mmap_bucket_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+
     b = apr_bucket_shared_make(b, m, start, length);
     b->type = &apr_bucket_type_mmap;
 
@@ -123,6 +146,11 @@
     apr_mmap_t *new_mm;
     apr_status_t ok;
 
+    if (!mm) {
+        /* due to cleanup issues we have no choice but to check this */
+        return APR_EINVAL;
+    }
+
     if (apr_pool_is_ancestor(mm->cntxt, p)) {
         return APR_SUCCESS;
     }
@@ -131,7 +159,14 @@
     if (ok != APR_SUCCESS) {
         return ok;
     }
+    
     m->mmap = new_mm;
+    if (new_mm->is_owner) {
+        apr_pool_cleanup_kill(mm->cntxt, m, mmap_bucket_cleanup);
+        apr_pool_cleanup_register(new_mm->cntxt, m, mmap_bucket_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+
     return APR_SUCCESS;
 }
 

Reply via email to