Project

General

Profile

Actions

Bug #3114

closed

Use-after-free bug in mod_alias

Added by LoneFox about 3 years ago. Updated about 3 years ago.

Status:
Fixed
Priority:
Normal
Category:
mod_alias
Target version:
ASK QUESTIONS IN Forums:
No

Description

I've been getting random 404 errors on my server, where same request sometimes works and sometimes not. I believe this started with lighttpd version 1.4.59, but became much more common (and therefore much more annoying) after updating to 1.4.60.

Enabling debug logging revealed a corrupted path:

(response.c.495) -- logical -> physical
(response.c.497) Doc-Root     : /var/www/
(response.c.499) Basedir      : /usr/lib/git-core/git-http-backend
(response.c.501) Rel-Path     : /git/Paradise/ports/git-upload-pack
(response.c.503) Path         : /usr/lib/git-core/git-http-backendp,\xec\x95adise/ports/git-upload-pack

I managed to find the origin and fix it. The problem is that buffer_string_prepare_append() reallocates the buffer and makes uri_ptr invalid, which then causes the memmove() below to copy garbage.
diff -bur lighttpd-1.4.61-orig/src/mod_alias.c lighttpd-1.4.61/src/mod_alias.c
--- lighttpd-1.4.61-orig/src/mod_alias.c    2021-10-29 01:58:31.000000000 +0300
+++ lighttpd-1.4.61/src/mod_alias.c    2021-10-29 13:28:34.000000000 +0300
@@ -128,7 +128,7 @@
     if (0 == path_len || path_len < basedir_len) return HANDLER_GO_ON;

     const uint32_t uri_len = path_len - basedir_len;
-    const char * const uri_ptr = r->physical.path.ptr + basedir_len;
+    char * uri_ptr = r->physical.path.ptr + basedir_len;
     data_string * const ds = (data_string *)
       (!r->conf.force_lowercase_filenames
         ? array_match_key_prefix_klen(aliases, uri_ptr, uri_len)
@@ -159,8 +159,10 @@
      * (though resulting r->physical.basedir would not be a dir))*/
     if (vlen != basedir_len + alias_len) {
         const uint32_t nlen = vlen + uri_len - alias_len;
-        if (path_len + buffer_string_space(&r->physical.path) < nlen)
+        if (path_len + buffer_string_space(&r->physical.path) < nlen) {
             buffer_string_prepare_append(&r->physical.path, nlen - path_len);
+            uri_ptr = r->physical.path.ptr + basedir_len;
+        }
         memmove(r->physical.path.ptr + vlen,
                 uri_ptr + alias_len, uri_len - alias_len);
         buffer_truncate(&r->physical.path, nlen);

Actions #1

Updated by gstrauss about 3 years ago

  • Target version changed from 1.4.xx to 1.4.62

Yikes! You are correct. Thank you for tracking that down.

The bug is in commit 62a874df which was introduced in lighttpd 1.4.59.

Actions #2

Updated by gstrauss about 3 years ago

  • Status changed from New to Patch Pending

Your patch will be part of lighttpd 1.4.62. (This issue will auto-close when the patch hits lighttpd git master branch)

For others who need a workaround before lighttpd 1.4.62 is available, lighttpd mod_magnet can be used as a substitute. See lua mod_alias for sample lua code.

Actions #3

Updated by gstrauss about 3 years ago

  • Status changed from Patch Pending to Fixed
Actions

Also available in: Atom