On Wed, 21 Oct 2026 16:09:28 +0200,
Rafael Sadowski <[email protected]> wrote:
>
> On Wed Oct 21, 2026 at 09:24:42AM +0200, Rafael Sadowski wrote:
> > On Tue Oct 20, 2026 at 05:35:53PM -0700, James J. Lippard wrote:
> > > I have multiple servers listening on the same host and port and using
> > > "ticket lifetime default" in their tls config blocks. Now httpd
> > > crashes out on the first ticket rekey with:
> > >
> > > httpd[6452]: fatal in server: proc_dispatch: server 2 got invalid imsg 23
> > > peerid -1 from parent 1
> > >
> > > The parent starts a rekey timer for every non-location TLS server
> > > block and sends IMSG_TLSTICKET_REKEY with that block's id. In the
> > > server processes, blocks sharing a socket are merged, the first
> > > becomes the struct server and the rest are attached as srv_hosts.
> > > server_byid() only searches the top-level servers, so the rekey for
> > > any merged block finds nothing. In OpenBSD 7.9 those misses were
> > > ignored:
> > >
> > > srv = server_byid(key.tt_id);
> > > if (srv) {
> > > tls_config_add_ticket_key(...);
> > > }
> > >
> > > but in 8.0 it returns -1 which proc_dispatch() reports as "invalid imsg"
> > > and turns into fatalx(). Using -vv the line before the fatal is
> > > the "invalid sever id" (typo in source) message; here's a patch that
> > > makes it non-fatal again":
> > >
> > > Index: usr.sbin/httpd/server.c
> > > ===================================================================
> > > RCS file: /cvs/src/usr.sbin/httpd/server.c,v
> > > diff -u -p -r1.143 server.c
> > > --- usr.sbin/httpd/server.c 15 Oct 2026 10:59:00 -0000 1.143
> > > +++ usr.sbin/httpd/server.c 20 Oct 2026 00:00:00 -0000
> > > @@ -1425,8 +1425,14 @@ server_dispatch_parent(int fd, struct pr
> > > memcpy(&key, imsg->data, sizeof(key));
> > > /* apply to the right server */
> > > if ((srv = server_byid(key.tt_id)) == NULL) {
> > > - log_debug("%s: invalid sever id", __func__);
> > > - return (-1);
> > > + /*
> > > + * Not a listening server, but a name-based host
> > > + * merged onto another server's socket; their shared
> > > + * TLS context is rekeyed via the listening server.
> > > + */
> > > + log_debug("%s: ignoring rekey for server id %u",
> > > + __func__, key.tt_id);
> > > + break;
> > > }
> > > if (tls_config_add_ticket_key(srv->srv_tls_config,
> > > key.tt_keyrev, key.tt_key, sizeof(key.tt_key)) == -1) {
> >
> > Hi James,
> >
> > thanks for the report and the patch.
> >
> > I think the stricter imsg handling in 8.0 found a real problem. The TLS
> > config is per socket, not per server block. Only the first server on a
> > socket sets up the tls_config. For the other virtual servers only the
> > cert/key (for SNI) is used, so their "ticket lifetime" has no effect.
> >
> > This also means: if the first server has no ticket lifetime but a later
> > one has, tickets are disabled for the whole socket, without any warning.
> > Welcome to the httpd.conf/parse.y madness where everything is valid!
> >
> > So I would do this in two steps:
> >
> > 1) Replace the return (-1) with your patch, so httpd does not crash.
> >
> > 2) Make the config stricter: warn (or fail) in parse.y if servers on
> > the same socket have different TLS settings, start rekey timers only
> > for the listening server, and document in httpd.conf(5) that these
> > TLS options apply per socket.
> >
> > kirill@ are you ok with this?
> >
> > Rafael
> >
>
> "Small" correction to my last mail: parse.y already rejects different
> ticket settings on the same address/port, so no new check is needed there.
> I blame this one too often!
>
> I think the better fix is in the parent. It starts a rekey timer for
> every TLS server, but only the first server on an address/port gets a
> struct server in the server processes. The diff below starts the timer
> ONLY for that one.
>
> Tested with two TLS servers on the same socket: the "ignoring rekey"
> messages from James' diff are gone. What I believe is the right
> solution.
>
> It annoys me that this bug made it into version 8.0, but the problem
> actually reveals the real flaw.
>
> OK?
>
ok Kirill@
> diff --git a/httpd.c b/httpd.c
> index abfbb5c..6ca2e24 100644
> --- a/httpd.c
> +++ b/httpd.c
> @@ -298,7 +298,8 @@ parent_configure(struct httpd *env)
> continue;
> /* start the rekey of the tls ticket keys */
> if (srv->srv_conf.flags & SRVFLAG_TLS &&
> - srv->srv_conf.tls_ticket_lifetime)
> + srv->srv_conf.tls_ticket_lifetime &&
> + server_match(srv, 0) == srv)
> parent_tls_ticket_rekey_start(srv);
> if (config_setserver(env, srv) == -1)
> fatal("send server");
>
--
wbr, Kirill