Bug 68278 - memcpy from NULL in apr_brigade_flatten when using mod_proxy_fcgi
Summary: memcpy from NULL in apr_brigade_flatten when using mod_proxy_fcgi
Alias: None
Product: APR
Classification: Unclassified
Component: APR-util (show other bugs)
Version: HEAD
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ---
Assignee: Apache Portable Runtime bugs mailinglist
Depends on:
Reported: 2023-12-03 00:17 UTC by benjamin.p.kallus.gr
Modified: 2023-12-19 12:40 UTC (History)
1 user (show)


Note You need to log in before you can comment on or make changes to this bug.
Description benjamin.p.kallus.gr 2023-12-03 00:17:48 UTC
glibc declares the dest and src parameters to memcpy as nonnull using a GCC extension attribute:
(from glibc string.h:43)
> extern void *memcpy (void *__restrict __dest, const void *__restrict __src,
>                      size_t __n) __THROW __nonnull ((1, 2));

Passing NULL as a nonnull argument is bad because the compiler will optimize away checks for NULL on arguments declared nonnull, which may have unexpected consequences.
It's also undefined behavior. See https://stackoverflow.com/questions/5243012/is-it-guaranteed-to-be-safe-to-perform-memcpy0-0-0 for discussion of this issue.

The following are steps to reproduce the bug. I have verified that this bug is present in both a fresh build of trunk, as well as the `apache2` package from the Debian Bookworm repositories. These steps assume that you're using x86_64.

0. Acquire a Debian Bookworm system:
> docker run --rm -it debian:bookworm-slim bash
1. Make a directory in which to build httpd:
> mkdir /app && cd /app
2. Update, install dependencies, then check out httpd and apr:
> apt -y update && apt -y upgrade && apt -y install ncat gdb python3 autoconf libtool libtool-bin libexpat1-dev libpcre3-dev clang subversion make php-fpm && svn co "https://svn.apache.org/repos/asf/httpd/httpd/trunk" httpd && cd httpd/srclib && svn co "https://svn.apache.org/repos/asf/apr/apr/trunk" apr
3. Configure and build httpd and apr:
> cd /app/httpd && ./buildconf && ./configure && make -j$(nproc) CFLAGS='-g' && make install
4. Change the php-fpm config to listen on instead of a UDS.
> sed -i 's/^listen = \/run\/php\/.*/listen =' /etc/php/8.2/fpm/pool.d/www.conf
5. Copy the following into your filesystem as `/var/www/index.php`:
> <?php
>   echo "hello world";
> ?>
6. Copy the following into your filesystem as `/usr/local/apache2/conf/httpd.conf`:
> ServerRoot "/usr/local/apache2"
> Listen 80
> User daemon
> Group daemon
> LoadModule authz_core_module modules/mod_authz_core.so
> LoadModule unixd_module modules/mod_unixd.so
> LoadModule rewrite_module modules/mod_rewrite.so
> LoadModule proxy_module modules/mod_proxy.so
> LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
> ServerName apache
> <VirtualHost *:80>
>     DocumentRoot /var/www
>     SetHandler "proxy:fcgi://"
>     RewriteEngine On
>     RewriteCond %{REQUEST_FILENAME} !-f
>     RewriteCond %{REQUEST_FILENAME} !-d
>     RewriteRule ^(.*)$ /index.php [L,QSA]
> </VirtualHost>
7. Start php-fpm:
> php-fpm8.2
8. Start httpd under gdb, set the appropriate breakpoints, and print out the second (src) argument to memcpy when the second breakpoint hits:
> gdb -ex "b apr_brigade_flatten" -ex 'r -X' -ex 'b memcpy' -ex 'c' -ex 'print $rsi' /usr/local/apache2/bin/httpd
9. From another terminal, send a request to the server:
> printf 'GET / HTTP/1.1\r\nHost: whatever\r\nConnection: close\r\n\r\n' | ncat localhost 80
10. Observe that second argument to memcpy is null in gdb:
> Thread 3 "httpd" hit Breakpoint 1, apr_brigade_flatten (bb=bb@entry=0x7feeac00f0a0,
>     c=c@entry=0x7feeb92eba10 "", len=len@entry=0x7feeb92eb9b8) at buckets/apr_brigade.c:258
> 258     for (b = APR_BRIGADE_FIRST(bb);
> Breakpoint 2 at 0x7feeb9c97cc0: memcpy. (4 locations)
> Continuing.
> Thread 3 "httpd" hit Breakpoint 2.3, __memcpy_avx_unaligned_erms ()
>     at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:264
> 264 ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S: No such file or directory.
> $1 = 0

This bug was found with UBSan.
Comment 1 benjamin.p.kallus.gr 2023-12-03 17:11:15 UTC
Here's a backtrace:
> #0  __memcpy_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:264
> #1  0x00007f884dd55eb1 in apr_brigade_flatten (bb=bb@entry=0x7f884000f060, c=<optimized out>,
>     c@entry=0x7f884d24ca10 "", len=len@entry=0x7f884d24c9b8) at buckets/apr_brigade.c:281
> #2  0x00007f884daa93ef in dispatch (conn=conn@entry=0x7f8840008c50, conf=conf@entry=0x55d1b1d63f28,
>     r=r@entry=0x7f8840004c30, setaside_pool=0x7f884000cc48, err=err@entry=0x7f884d24eb30,
>     bad_request=bad_request@entry=0x7f884d24eac4, has_responded=0x7f884d24eac8,
>     input_brigade=<optimized out>, request_id=1) at mod_proxy_fcgi.c:645
> #3  0x00007f884daaadce in fcgi_do_request (origin=0x0, p=<optimized out>, uri=<optimized out>,
>     url=<optimized out>, input_brigade=0x7f88400066a0, server_portstr=0x7f884d24eb10 "",
>     conf=<optimized out>, conn=0x7f8840008c50, r=0x7f8840004c30) at mod_proxy_fcgi.c:1007
> #4  proxy_fcgi_handler (r=0x7f8840004c30, worker=<optimized out>, conf=<optimized out>,
>     url=<optimized out>, proxyname=<optimized out>, proxyport=<optimized out>) at mod_proxy_fcgi.c:1221
> #5  0x00007f884dabcb43 in proxy_run_scheme_handler (r=r@entry=0x7f8840004c30, worker=0x55d1b1d6bba0,
>     conf=conf@entry=0x55d1b1d63010, url=0x7f88400065ae "fcgi://",
>     proxyhost=proxyhost@entry=0x0, proxyport=proxyport@entry=0) at mod_proxy.c:3529
> #6  0x00007f884dabebf9 in proxy_handler (r=0x7f8840004c30) at mod_proxy.c:1548
> #7  0x000055d1b16dff50 in ap_run_handler (r=r@entry=0x7f8840004c30) at config.c:169
> #8  0x000055d1b16e0536 in ap_invoke_handler (r=r@entry=0x7f8840004c30) at config.c:443
> #9  0x000055d1b16cfad7 in ap_process_async_request (r=r@entry=0x7f8840004c30) at http_request.c:450
> #10 0x000055d1b16cb4dc in ap_process_http_async_connection (c=0x7f87c8000fa0) at http_core.c:159
> #11 ap_process_http_connection (c=0x7f87c8000fa0) at http_core.c:250
> #12 0x000055d1b16ee930 in ap_run_process_connection (c=c@entry=0x7f87c8000fa0) at connection.c:43
> #13 0x000055d1b16ddab6 in process_socket (thd=thd@entry=0x7f8848000d10, p=<optimized out>,
>     sock=<optimized out>, cs=<optimized out>, my_child_num=my_child_num@entry=0,
>     my_thread_num=my_thread_num@entry=0) at event.c:1129
> #14 0x000055d1b16de2e2 in worker_thread (thd=0x7f8848000d10, dummy=<optimized out>) at event.c:2488
> #15 0x00007f884dd908af in dummy_worker (opaque=0x7f8848000d10) at threadproc/unix/thread.c:165
> #16 0x00007f884dbe6044 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
> #17 0x00007f884dc65880 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100
Comment 2 Joe Orton 2023-12-19 11:34:03 UTC
Fixed in r1914766 and back to apr-util 1.6.x in r1914766 - thanks again for the patch.

Did you trigger a crash with this (outside of e.g. ubsan)?
Comment 3 Joe Orton 2023-12-19 11:35:11 UTC
Failed c&p. Fixed in apr-util 1.6.x in r1914775
Comment 4 benjamin.p.kallus.gr 2023-12-19 12:40:52 UTC
(In reply to Joe Orton from comment #2)
> Fixed in r1914766 and back to apr-util 1.6.x in r1914766 - thanks again for
> the patch.

Sure thing!

> Did you trigger a crash with this (outside of e.g. ubsan)?

No crash; just UBSan.