From 7aef7fa9fae09d23be09dd34cb23927735fa155f Mon Sep 17 00:00:00 2001 From: rsadowski Date: Wed, 3 Jun 2026 19:25:06 +0000 Subject: [PATCH] httpd: reject obs-fold with 400 (RFC 9112 5.2) Replace silent kv_extend normalisation with an unconditional 400. RFC 9112 5.2 explicitly permits rejection; it is the safer choice over SP replacement, which hides parser ambiguity downstream. Reported by Stuart Thomas, OK kirill@ --- usr.sbin/httpd/httpd.c | 21 +-------------------- usr.sbin/httpd/httpd.h | 3 +-- usr.sbin/httpd/server_http.c | 33 ++++++++++++--------------------- 3 files changed, 14 insertions(+), 43 deletions(-) diff --git a/usr.sbin/httpd/httpd.c b/usr.sbin/httpd/httpd.c index b3a6b83f0d2..d0188f6acb8 100644 --- a/usr.sbin/httpd/httpd.c +++ b/usr.sbin/httpd/httpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.c,v 1.78 2026/05/11 22:33:10 kirill Exp $ */ +/* $OpenBSD: httpd.c,v 1.79 2026/06/03 19:25:06 rsadowski Exp $ */ /* * Copyright (c) 2014 Reyk Floeter @@ -1023,25 +1023,6 @@ kv_delete(struct kvtree *keys, struct kv *kv) free(kv); } -struct kv * -kv_extend(struct kvtree *keys, struct kv *kv, char *value) -{ - char *newvalue; - - if (kv == NULL) { - return (NULL); - } else if (kv->kv_value != NULL) { - if (asprintf(&newvalue, "%s%s", kv->kv_value, value) == -1) - return (NULL); - - free(kv->kv_value); - kv->kv_value = newvalue; - } else if ((kv->kv_value = strdup(value)) == NULL) - return (NULL); - - return (kv); -} - void kv_purge(struct kvtree *keys) { diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index af36aec7d59..12122c618ec 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.h,v 1.173 2026/06/01 09:28:42 claudio Exp $ */ +/* $OpenBSD: httpd.h,v 1.174 2026/06/03 19:25:06 rsadowski Exp $ */ /* * Copyright (c) 2006 - 2015 Reyk Floeter @@ -740,7 +740,6 @@ int kv_set(struct kv *, char *, ...) int kv_setkey(struct kv *, char *, ...) __attribute__((__format__ (printf, 2, 3))); void kv_delete(struct kvtree *, struct kv *); -struct kv *kv_extend(struct kvtree *, struct kv *, char *); void kv_purge(struct kvtree *); void kv_free(struct kv *); struct kv *kv_find(struct kvtree *, struct kv *); diff --git a/usr.sbin/httpd/server_http.c b/usr.sbin/httpd/server_http.c index dd7bac10561..0a600cdfd98 100644 --- a/usr.sbin/httpd/server_http.c +++ b/usr.sbin/httpd/server_http.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server_http.c,v 1.163 2026/06/01 09:28:42 claudio Exp $ */ +/* $OpenBSD: server_http.c,v 1.164 2026/06/03 19:25:06 rsadowski Exp $ */ /* * Copyright (c) 2020 Matthias Pressfreund @@ -284,31 +284,22 @@ server_read_http(struct bufferevent *bev, void *arg) */ if (++clt->clt_line == 1) value = strchr(key, ' '); - else if (*key == ' ' || *key == '\t') - /* Multiline headers wrap with a space or tab */ - value = NULL; + else if (*key == ' ' || *key == '\t') { + /* + * RFC 9112 section 5.2 permits unconditional rejection + */ + server_abort_http(clt, 400, "malformed"); + goto abort; + } else { - /* Not a multiline header, should have a : */ value = strchr(key, ':'); - if (value == NULL) { - server_abort_http(clt, 400, "malformed"); - goto abort; - } } + if (value == NULL) { - if (clt->clt_line == 1) { - server_abort_http(clt, 400, "malformed"); - goto abort; - } - - /* Append line to the last header, if present */ - if (kv_extend(&desc->http_headers, - desc->http_lastheader, line) == NULL) - goto fail; - - free(line); - continue; + server_abort_http(clt, 400, "malformed"); + goto abort; } + if (*value == ':') { *value++ = '\0'; value += strspn(value, " \t\r\n");