Work around use after free in httpd(8)
authortb <tb@openbsd.org>
Wed, 12 Jul 2023 12:37:27 +0000 (12:37 +0000)
committertb <tb@openbsd.org>
Wed, 12 Jul 2023 12:37:27 +0000 (12:37 +0000)
A malformed HTTP request can cause httpd in fastcgi mode to crash due to a
use-after-free. This is an awful hack, but it's good enough until someone
figures out the correct way of dealing with server_close() here.

"this will do the trick for now" claudio
ok beck deraadt

usr.sbin/httpd/httpd.h
usr.sbin/httpd/server.c
usr.sbin/httpd/server_fcgi.c

index 6cef91a..1e2ccb9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: httpd.h,v 1.162 2022/10/24 15:02:01 jmc Exp $ */
+/*     $OpenBSD: httpd.h,v 1.163 2023/07/12 12:37:27 tb Exp $  */
 
 /*
  * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -352,6 +352,7 @@ struct client {
        int                      clt_inflight;
        struct range_data        clt_ranges;
        struct fcgi_data         clt_fcgi;
+       const char              *clt_fcgi_error;
        char                    *clt_remote_user;
        struct evbuffer         *clt_srvevb;
 
index 90a47d6..6999b08 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server.c,v 1.126 2021/07/14 13:33:57 kn Exp $ */
+/*     $OpenBSD: server.c,v 1.127 2023/07/12 12:37:27 tb Exp $ */
 
 /*
  * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
@@ -1300,6 +1300,11 @@ server_close(struct client *clt, const char *msg)
 {
        struct server           *srv = clt->clt_srv;
 
+       if (clt->clt_fcgi_error != NULL) {
+               clt->clt_fcgi_error = msg;
+               return;
+       }
+
        SPLAY_REMOVE(client_tree, &srv->srv_clients, clt);
 
        /* free the HTTP descriptors incl. headers */
index 073ab34..d2c7d8a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_fcgi.c,v 1.95 2022/08/15 12:29:17 claudio Exp $        */
+/*     $OpenBSD: server_fcgi.c,v 1.96 2023/07/12 12:37:28 tb Exp $     */
 
 /*
  * Copyright (c) 2014 Florian Obser <florian@openbsd.org>
@@ -372,7 +372,18 @@ server_fcgi(struct httpd *env, struct client *clt)
            srv_conf->timeout.tv_sec, srv_conf->timeout.tv_sec);
        bufferevent_enable(clt->clt_srvbev, EV_READ|EV_WRITE);
        if (clt->clt_toread != 0) {
+               /*
+                * XXX - Work around UAF: server_read_httpcontent() can call
+                * server_close(), normally freeing clt. If clt->clt_fcgi_error
+                * changed, call server_close() via server_abort_http().
+                */
+               clt->clt_fcgi_error = "";
                server_read_httpcontent(clt->clt_bev, clt);
+               errstr = clt->clt_fcgi_error;
+               clt->clt_fcgi_error = NULL;
+               if (errstr[0] != '\0')
+                       goto fail;
+               errstr = NULL;
                bufferevent_enable(clt->clt_bev, EV_READ);
        } else {
                bufferevent_disable(clt->clt_bev, EV_READ);