I'm filing this bug here, so that it might get noticed before the next release
cycle and cause no more noise on tech@. Plus, the last diff I sent to tech@ was
the wrong one anyway. Whoops.

In server_http.c, the wrong server config struct is checked in the queue for
maxrequestbody. The code is only comparing to the first entry in the queue.

Attached is the diff I'm using on current. Original notice:
https://marc.info/?l=openbsd-tech&m=153255699713565&w=2

Hopefully, someone can decide the best way to progress.

Thanks and have a good day.

Tracey
Index: src/usr.sbin/httpd/httpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
retrieving revision 1.142
diff -u -p -u -r1.142 httpd.h
--- src/usr.sbin/httpd/httpd.h  11 Oct 2018 09:52:22 -0000      1.142
+++ src/usr.sbin/httpd/httpd.h  29 Oct 2018 17:11:55 -0000
@@ -691,6 +691,8 @@ const char *
 char   *server_http_parsehost(char *, char *, size_t, int *);
 ssize_t         server_http_time(time_t, char *, size_t);
 int     server_log_http(struct client *, unsigned int, size_t);
+int     server_check_config(struct server_config *, struct client *,
+           struct kv *, char *);
 
 /* server_file.c */
 int     server_file(struct httpd *, struct client *);
Index: src/usr.sbin/httpd/server_http.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v
retrieving revision 1.126
diff -u -p -u -r1.126 server_http.c
--- src/usr.sbin/httpd/server_http.c    15 Oct 2018 08:16:17 -0000      1.126
+++ src/usr.sbin/httpd/server_http.c    29 Oct 2018 17:11:55 -0000
@@ -197,6 +197,7 @@ done:
 void
 server_read_http(struct bufferevent *bev, void *arg)
 {
+       char                     hostname[HOST_NAME_MAX+1];
        struct client           *clt = arg;
        struct server_config    *srv_conf = clt->clt_srv_conf;
        struct http_descriptor  *desc = clt->clt_descreq;
@@ -204,7 +205,7 @@ server_read_http(struct bufferevent *bev
        char                    *line = NULL, *key, *value;
        const char              *errstr;
        size_t                   size, linelen;
-       struct kv               *hdr = NULL;
+       struct kv               *hdr = NULL, kv_key, *host;
 
        getmonotime(&clt->clt_tv_last);
 
@@ -344,6 +345,15 @@ server_read_http(struct bufferevent *bev
                                goto abort;
                        }
 
+                       kv_key.kv_key = "Host";
+                       if ((host = kv_find(&desc->http_headers, &kv_key)) !=
+                           NULL && host->kv_value == NULL)
+                               host = NULL;
+
+                       if (server_check_config(srv_conf, clt, host,
+                           hostname))
+                               goto fail;
+
                        /*
                         * Need to read data from the client after the
                         * HTTP header.
@@ -1183,10 +1193,7 @@ server_response(struct httpd *httpd, str
        struct server           *srv = clt->clt_srv;
        struct server_config    *srv_conf = &srv->srv_conf;
        struct kv               *kv, key, *host;
-       struct str_find          sm;
-       int                      portval = -1, ret;
-       char                    *hostval, *query;
-       const char              *errstr = NULL;
+       char                    *query;
 
        /* Decode the URL */
        if (desc->http_path == NULL ||
@@ -1234,58 +1241,8 @@ server_response(struct httpd *httpd, str
        if (clt->clt_pipelining && clt->clt_toread > 0)
                clt->clt_persist = 0;
 
-       /*
-        * Do we have a Host header and matching configuration?
-        * XXX the Host can also appear in the URL path.
-        */
-       if (host != NULL) {
-               if ((hostval = server_http_parsehost(host->kv_value,
-                   hostname, sizeof(hostname), &portval)) == NULL)
-                       goto fail;
-
-               TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
-#ifdef DEBUG
-                       if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
-                               DPRINTF("%s: virtual host \"%s:%u\""
-                                   " host \"%s\" (\"%s\")",
-                                   __func__, srv_conf->name,
-                                   ntohs(srv_conf->port), host->kv_value,
-                                   hostname);
-                       }
-#endif
-                       if (srv_conf->flags & SRVFLAG_LOCATION)
-                               continue;
-                       else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
-                               str_find(hostname, srv_conf->name,
-                                   &sm, 1, &errstr);
-                               ret = errstr == NULL ? 0 : -1;
-                       } else {
-                               ret = fnmatch(srv_conf->name,
-                                   hostname, FNM_CASEFOLD);
-                       }
-                       if (ret == 0 &&
-                           (portval == -1 ||
-                           (portval != -1 && portval == srv_conf->port))) {
-                               /* Replace host configuration */
-                               clt->clt_srv_conf = srv_conf;
-                               srv_conf = NULL;
-                               break;
-                       }
-               }
-       }
-
-       if (srv_conf != NULL) {
-               /* Use the actual server IP address */
-               if (server_http_host(&clt->clt_srv_ss, hostname,
-                   sizeof(hostname)) == NULL)
-                       goto fail;
-       } else {
-               /* Host header was valid and found */
-               if (strlcpy(hostname, host->kv_value, sizeof(hostname)) >=
-                   sizeof(hostname))
-                       goto fail;
-               srv_conf = clt->clt_srv_conf;
-       }
+       if (server_check_config(srv_conf, clt, host, hostname))
+               goto fail;
 
        if ((desc->http_host = strdup(hostname)) == NULL)
                goto fail;
@@ -1764,4 +1721,69 @@ done:
        free(agent_v);
 
        return (ret);
+}
+
+int
+server_check_config(struct server_config *srv_conf, struct client *clt,
+    struct kv *host, char *hostname)
+{
+       struct server           *srv = clt->clt_srv;
+       struct str_find          sm;
+       size_t                   len = HOST_NAME_MAX+1;
+       int                      portval = -1, ret;
+       char                    *hostval;
+       const char              *errstr = NULL;
+
+       /*
+        * Do we have a Host header and matching configuration?
+        * XXX the Host can also appear in the URL path.
+        */
+       if (host != NULL) {
+               if ((hostval = server_http_parsehost(host->kv_value,
+                   hostname, len, &portval)) == NULL)
+                       return(-1);
+
+               TAILQ_FOREACH(srv_conf, &srv->srv_hosts, entry) {
+#ifdef DEBUG
+                       if ((srv_conf->flags & SRVFLAG_LOCATION) == 0) {
+                               DPRINTF("%s: virtual host \"%s:%u\""
+                                   " host \"%s\" (\"%s\")",
+                                   __func__, srv_conf->name,
+                                   ntohs(srv_conf->port), host->kv_value,
+                                   hostname);
+                       }
+#endif
+                       if (srv_conf->flags & SRVFLAG_LOCATION)
+                               continue;
+                       else if (srv_conf->flags & SRVFLAG_SERVER_MATCH) {
+                               str_find(hostname, srv_conf->name,
+                                   &sm, 1, &errstr);
+                               ret = errstr == NULL ? 0 : -1;
+                       } else {
+                               ret = fnmatch(srv_conf->name,
+                                   hostname, FNM_CASEFOLD);
+                       }
+                       if (ret == 0 &&
+                           (portval == -1 ||
+                           (portval != -1 && portval == srv_conf->port))) {
+                               /* Replace host configuration */
+                               clt->clt_srv_conf = srv_conf;
+                               srv_conf = NULL;
+                               break;
+                       }
+               }
+       }
+
+       if (srv_conf != NULL) {
+               /* Use the actual server IP address */
+               if (server_http_host(&clt->clt_srv_ss, hostname,
+                   len) == NULL)
+                       return(-1);
+       } else {
+               /* Host header was valid and found */
+               if (strlcpy(hostname, host->kv_value, len) >= len)
+                       return(-1);
+               srv_conf = clt->clt_srv_conf;
+       }
+       return(0);
 }

Reply via email to