commit afc41fe08300310c8fc6ef0007438e5a8b5907fe from: deraadt date: Wed Nov 12 11:24:04 2025 UTC Systopia team at UBC found 5 info leaks in the private privsep protocol between httpd programs, and provided a fix. ok claudio benno florian commit - 8dcab0e2df9c42f05eed6ffb1422d251ca15cb71 commit + afc41fe08300310c8fc6ef0007438e5a8b5907fe blob - b4a8e734d614e15488d6d70d4f26c72cce07fb48 blob + cdb04f1eb0e6eb9a341ed47e3194baaca28fb0d0 --- config.c +++ config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.65 2024/01/17 08:22:40 claudio Exp $ */ +/* $OpenBSD: config.c,v 1.66 2025/11/12 11:24:04 deraadt Exp $ */ /* * Copyright (c) 2011 - 2015 Reyk Floeter @@ -158,6 +158,49 @@ config_getcfg(struct httpd *env, struct imsg *imsg) return (0); } +/* + * struct server_config is an internal data structure + * in privileged compartment containing both data and + * pointers, which is dangerously copied as a whole. + * + * This helper function clears all the pointer + * fields in struct server_config while preserving + * other data, avoiding pointers being accidentally + * send to unprivileged compartments, breaking + * inter-compartment ASLR. + */ +static void +clear_config_server_ptrs(struct server_config *cfg) +{ + cfg->default_type.media_encoding = NULL; + + /* clear all fields expanded from RB_ENTRY */ + memset(&cfg->default_type.media_entry, 0, + sizeof(cfg->default_type.media_entry)); + + cfg->tls_ca = NULL; + cfg->tls_ca_file = NULL; + cfg->tls_cert = NULL; + cfg->tls_cert_file = NULL; + cfg->tls_crl = NULL; + cfg->tls_crl_file = NULL; + cfg->tls_key = NULL; + cfg->tls_key_file = NULL; + cfg->tls_ocsp_staple = NULL; + cfg->tls_ocsp_staple_file = NULL; + + cfg->logaccess = NULL; + cfg->logerror = NULL; + cfg->auth = NULL; + cfg->return_uri = NULL; + + /* clear TAILQ_HEAD */ + memset(&cfg->fcgiparams, 0, sizeof(cfg->fcgiparams)); + + /* clear TAILQ_ENTRY */ + memset(&cfg->entry, 0, sizeof(cfg->entry)); +} + int config_setserver(struct httpd *env, struct server *srv) { @@ -187,6 +230,9 @@ config_setserver(struct httpd *env, struct server *srv memcpy(&s, &srv->srv_conf, sizeof(s)); + /* since s is a local, it is safe to clear its pointers directly */ + clear_config_server_ptrs(&s); + c = 0; iov[c].iov_base = &s; iov[c++].iov_len = sizeof(s); @@ -821,6 +867,7 @@ config_setmedia(struct httpd *env, struct media_type * struct privsep *ps = env->sc_ps; int id; unsigned int what; + struct media_type mt; for (id = 0; id < PROC_MAX; id++) { what = ps->ps_what[id]; @@ -831,7 +878,12 @@ config_setmedia(struct httpd *env, struct media_type * DPRINTF("%s: sending media \"%s\" to %s", __func__, media->media_name, ps->ps_title[id]); - proc_compose(ps, id, IMSG_CFG_MEDIA, media, sizeof(*media)); + /* Send a cleaned-up copy */ + memcpy(&mt, media, sizeof(*media)); + mt.media_encoding = NULL; + memset(&mt.media_entry, 0, sizeof(mt.media_entry)); + + proc_compose(ps, id, IMSG_CFG_MEDIA, &mt, sizeof(mt)); } return (0); @@ -866,6 +918,7 @@ int config_setauth(struct httpd *env, struct auth *auth) { struct privsep *ps = env->sc_ps; + struct auth auth_payload; /* pointer-free payload */ int id; unsigned int what; @@ -878,7 +931,14 @@ config_setauth(struct httpd *env, struct auth *auth) DPRINTF("%s: sending auth \"%s[%u]\" to %s", __func__, auth->auth_htpasswd, auth->auth_id, ps->ps_title[id]); - proc_compose(ps, id, IMSG_CFG_AUTH, auth, sizeof(*auth)); + + /* memcpy to avoid modifying auth directly */ + memcpy(&auth_payload, auth, sizeof(*auth)); + + /* clear pointers */ + memset(&auth_payload.auth_entry, 0, sizeof(auth_payload.auth_entry)); + + proc_compose(ps, id, IMSG_CFG_AUTH, &auth_payload, sizeof(auth_payload)); } return (0); blob - 686f41c88d033c81bd8971bf6344ee84a6524e82 blob + ab78dd9d1d1e1cf0212ac7877e018d79dd9c8ab9 --- httpd.c +++ httpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: httpd.c,v 1.74 2024/04/08 12:45:18 tobhe Exp $ */ +/* $OpenBSD: httpd.c,v 1.75 2025/11/12 11:24:04 deraadt Exp $ */ /* * Copyright (c) 2014 Reyk Floeter @@ -278,6 +278,8 @@ parent_configure(struct httpd *env) struct media_type *media; struct auth *auth; + memset(&cf, 0, sizeof(cf)); + RB_FOREACH(media, mediatypes, env->sc_mediatypes) { if (config_setmedia(env, media) == -1) fatal("send media"); blob - 302a4e63ed69fe989e4f6e0e3b326ed0f775d7a1 blob + d565e61d727d98a0d09ed2a19fd08e608aff3298 --- parse.y +++ parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.128 2022/02/27 20:30:30 bluhm Exp $ */ +/* $OpenBSD: parse.y,v 1.129 2025/11/12 11:24:04 deraadt Exp $ */ /* * Copyright (c) 2020 Matthias Pressfreund @@ -1896,6 +1896,7 @@ load_config(const char *filename, struct httpd *x_conf struct media_type m; int i; + memset(&m, 0, sizeof(m)); conf = x_conf; conf->sc_flags = 0;