wolfsshd: fail closed when a per-connection privilege drop fails#1067
Open
yosuke-wolfssl wants to merge 1 commit into
Open
wolfsshd: fail closed when a per-connection privilege drop fails#1067yosuke-wolfssl wants to merge 1 commit into
yosuke-wolfssl wants to merge 1 commit into
Conversation
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1067
Scan targets checked: wolfssh-bugs, wolfssh-src
No new issues found in the changed files. ✅
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
wolfsshd: fail closed when a per-connection privilege drop fails
Summary
Fixes a privilege-handling defect in
wolfsshdwhere a failed per-connectiondrop to the authenticated user's uid/gid could leave the connection handler
running at an elevated privilege level (root, or the sshd-daemon uid) instead
of terminating.
Addressed by f_5850.
Background
When servicing a channel request, the subsystem handlers
(
SHELL_Subsystem,SCP_Subsystem,SFTP_Subsystem) drop privileges to theauthenticated user via
wolfSSHD_AuthReducePermissionsUser(). On failure, theold code attempted a fallback to
wolfSSHD_AuthReducePermissions()and thendid
return WS_FATAL_ERROR:Two problems combined into a privilege-management hole:
The fallback is a no-op when privilege separation is off. With
UsePrivilegeSeparationset toWOLFSSHD_PRIV_OFF,wolfSSHD_AuthReducePermissions()performs no uid change and returnsWS_SUCCESS. So after a failed drop-to-user, the fallback "succeeds"without lowering anything.
HandleConnectiondiscarded theSHELL_Subsystemreturn value. TheWS_FATAL_ERRORwas never captured, soretstayedWS_SUCCESS. Thepost-switch error check consults
wolfSSH_get_error(ssh), which a kernelsetreuid()/setregid()failure does not set, sowolfSSH_shutdownand upto ten
wolfSSH_workeriterations would execute while the effective uid wasstill above the authenticated user.
Triggering the drop failure itself requires an environmental condition that
forces
setreuid/setregidto fail (e.g.RLIMIT_NPROCsaturation at thetarget uid, an LSM denial, or user-namespace mapping limits), so this is not
routinely reachable in default deployments — but when it does occur the handler
must fail closed.
Fix
Every per-connection privilege-drop failure path now calls
exit(1)directly instead of attempting the no-op fallback and returning. This is
strictly stronger than propagating an error into the connection handler:
the per-connection process terminates before any work runs at the wrong
privilege level. Applied consistently across
SHELL_Subsystem(the forkedchild branch and the parent branch, plus the
dup2/setgroups/chrootfailure paths),
SCP_Subsystem, andSFTP_Subsystem.HandleConnectionnow captures the return value at both subsystem callsites (
ret = SHELL_Subsystem(...)for the shell and exec sessions), so afailure is reflected in
retas well (defense in depth;exit(1)alreadymakes the path unreachable).
In the
SHELL_Subsystemparent branch theforkptychild has already beenspawned, so it is killed with
kill(childPid, SIGKILL)beforeexit(1)toguarantee deterministic teardown rather than relying on pty/pipe closure,
matching the existing unexpected-error handling later in the same function.
The daemon's own startup drop in
main()is unchanged: it already fails closedby setting
ret = WS_FATAL_ERROR, which prevents the listen/accept loop fromstarting.
Testing
wolfsshdbuilds cleanly with the project configuration.privilege-drop-failure paths are affected, and they now terminate the
per-connection process.