Skip to content

fix: guard sshd chroot steps after a failure#1088

Open
MarkAtwood wants to merge 1 commit into
wolfSSL:masterfrom
MarkAtwood:fix/sshd-chroot-guard-chdir-failure
Open

fix: guard sshd chroot steps after a failure#1088
MarkAtwood wants to merge 1 commit into
wolfSSL:masterfrom
MarkAtwood:fix/sshd-chroot-guard-chdir-failure

Conversation

@MarkAtwood

Copy link
Copy Markdown

Problem

SetupChroot() in apps/wolfsshd/wolfsshd.c performs the chroot sequence in three independent if blocks with a single return at the end:

if (chdir(chrootPath) != 0) { ...; ret = WS_FATAL_ERROR; }
if (chroot(chrootPath) != 0) { ...; ret = WS_FATAL_ERROR; }
if (chdir("/")       != 0) { ...; ret = WS_FATAL_ERROR; }

Every step runs unconditionally, so chroot() executes even when the preceding chdir(chrootPath) failed. The secure idiom requires being inside the target directory before/at chroot; running chroot() after a failed chdir can leave the process chrooted with a working directory outside the new root. The caller does abort on the negative return, but chroot() has already run by then, so this is a defense-in-depth gap.

Fix

Short-circuit the later steps on ret > 0 (the no-failure state) so chroot() runs only after the chdir() into the target succeeds, and chdir("/") only after chroot() succeeds. WS_FATAL_ERROR is -1001, so ret > 0 holds only while no step has failed.

Verified: wolfsshd builds cleanly (--enable-sshd) against wolfSSL --enable-ssh with the change. No behavioral change on the success path (all three steps still run and ret stays 1); on failure the chain now stops at the first failed step.

Note: no automated test is added — SetupChroot is a static function whose failure path requires root plus a specifically failing chdir, which isn't exercisable in the wolfSSH test harness.

Reported by static analysis (Fenrir finding 58).

SetupChroot() in wolfsshd ran chdir(chrootPath), chroot(chrootPath) and
chdir("/") in three independent if-blocks with a single return at the end.
Each ran unconditionally, so chroot() executed even when the preceding
chdir() into the target failed. That can leave the process chrooted with a
working directory still outside the new root.

Short-circuit the later steps on the ret>0 (no-failure) state so chroot()
runs only after the chdir() into the target succeeds, and chdir("/") only
after chroot() succeeds. WS_FATAL_ERROR is negative, so ret>0 is true only
while no step has failed.
Copilot AI review requested due to automatic review settings July 9, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the wolfsshd chroot setup sequence by ensuring later chroot steps only execute when earlier prerequisite steps succeeded, avoiding unsafe partial-chroot states.

Changes:

  • Adds explicit short-circuit guards so chroot() only runs after a successful chdir(chrootPath).
  • Ensures chdir("/") only runs after a successful chroot().
  • Adds an explanatory in-code comment documenting why the sequencing guard matters.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/wolfsshd/wolfsshd.c
* chdir("/") once inside the new root. Running a later step after an
* earlier failure could leave the process chrooted with a working
* directory outside the new root. */
if (ret > 0 && chroot(chrootPath) != 0) {
Comment thread apps/wolfsshd/wolfsshd.c
ret = WS_FATAL_ERROR;
}
if (chdir("/") != 0) {
if (ret > 0 && chdir("/") != 0) {
@MarkAtwood MarkAtwood requested a review from ejohnstown July 10, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants