From b37c095aa39bb2c01754673dec50a684a536db24 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Tue, 6 Oct 2026 16:43:39 +1100 Subject: [PATCH] disable features when post-auth sshd runs as root On platforms that require root privilege for the post-authentication sshd-session process (e.g. OpenServer 5, QNX 6), disable and restrict a number of features that assume user privilege. This includes GatewayPorts, StreamLocalForwarding and -R forwardings binding to ports <1024 --- channels.c | 8 ++++++++ defines.h | 16 ++++++++++++++++ servconf.c | 12 ++++++++++++ sshd-session.c | 20 +++----------------- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/channels.c b/channels.c index ad380dbe4..abae44b92 100644 --- a/channels.c +++ b/channels.c @@ -4344,6 +4344,14 @@ check_rfwd_permission(struct ssh *ssh, struct Forward *fwd) u_int i, permit, permit_adm = 1; struct permission *perm; +#ifdef SKIP_PRIVDROP + if (fwd->listen_path != NULL) + return 0; + if (allowed_open->listen_port != FWD_PERMIT_ANY_PORT && + allowed_open->listen_port < 1024) + return 0; +#endif + /* XXX apply GatewayPorts override before checking? */ permit = pset->all_permitted; diff --git a/defines.h b/defines.h index 634db453e..c0b9ad549 100644 --- a/defines.h +++ b/defines.h @@ -1007,4 +1007,20 @@ struct winsize { # endif #endif +/* + * Hack for systems that don't support FD passing: retain privileges + * in the post-auth privsep process so it can allocate PTYs directly. + * + * Instead of doing what we did <= 9.7, which was to disable post-auth + * privsep entirely, we run with temporarily_use_uid, restoring root + * only to allocate ptys or in the child to permanently change UID. + * + * Cygwin doesn't need to drop privs here although it doesn't support + * fd passing, as AFAIK PTY allocation on this platform doesn't require + * special privileges to begin with. + */ +#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN) +# define SKIP_PRIVDROP 1 +#endif + #endif /* _DEFINES_H */ diff --git a/servconf.c b/servconf.c index b49e9e97c..044043b74 100644 --- a/servconf.c +++ b/servconf.c @@ -273,6 +273,18 @@ fill_default_server_options(ServerOptions *options) { u_int i; + /* Portable-specific overrides */ +#ifdef SKIP_PRIVDROP + if (options->allow_streamlocal_forwarding != -1 && + options->allow_streamlocal_forwarding != FORWARD_DENY) + logit("StreamlocalForwarding is not supported on this system"); + options->allow_streamlocal_forwarding = 0; + if (options->fwd_opts.gateway_ports != -1 && + options->fwd_opts.gateway_ports == 0) + logit("GatewayPorts is not supported on this system"); + options->fwd_opts.gateway_ports = 0; +#endif + #define SSHCONF_INT(var, conf, flags, ms, def, cp) \ if (options->var == -1) \ options->var = def; diff --git a/sshd-session.c b/sshd-session.c index 7d7bbb40d..1af9bcf4c 100644 --- a/sshd-session.c +++ b/sshd-session.c @@ -371,21 +371,6 @@ privsep_preauth(struct ssh *ssh) static void privsep_postauth(struct ssh *ssh, Authctxt *authctxt) { - int skip_privdrop = 0; - - /* - * Hack for systems that don't support FD passing: retain privileges - * in the post-auth privsep process so it can allocate PTYs directly. - * This is basically equivalent to what we did <= 9.7, which was to - * disable post-auth privsep entirely. - * Cygwin doesn't need to drop privs here although it doesn't support - * fd passing, as AFAIK PTY allocation on this platform doesn't require - * special privileges to begin with. - */ -#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN) - skip_privdrop = 1; -#endif - /* New socket pair */ monitor_reinit(pmonitor); @@ -412,9 +397,10 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) reseed_prngs(); +#ifndef SKIP_PRIVDROP /* Drop privileges */ - if (!skip_privdrop) - do_setusercontext(authctxt->pw); + do_setusercontext(authctxt->pw); +#endif /* It is safe now to apply the key state */ monitor_apply_keystate(ssh, pmonitor);