Skip to content

SCP: receive through a per-session dirfd - #1306

Open
ejohnstown wants to merge 1 commit into
wolfSSL:masterfrom
ejohnstown:scp-rx-paths
Open

ejohnstown wants to merge 1 commit into
wolfSSL:masterfrom
ejohnstown:scp-rx-paths

Conversation

@ejohnstown

@ejohnstown ejohnstown commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

The default SCP receive callback keeps its destination per session instead of changing the process working directory, and on POSIX walks it through a directory descriptor with O_NOFOLLOW opens.

  • The destination path is kept per session, so sessions of a threaded server no longer share a working directory (F-13998).
  • The base and each file and directory below it are opened relative to the held descriptor with O_NOFOLLOW, closing the lstat-then-open window on a planted symlink, and leaving a directory confirms the parent is the one entered from (F-14758).
  • Ports without openat() keep the path-based open behind a screen that requires a directory and not a link, for the base and for each directory entered; scp-test.yml now builds and tests that fallback too.
  • futimes() backs the descriptor-bound timestamp update on hosts that have openat() but not futimens().

Copilot AI balanced review requested due to automatic review settings October 9, 2026 17:34

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.

🟡 Changes recommended

Base-path and timestamp races can still escape confinement, while fallback validation and CI rebuilding are incomplete.

4 open findings
What changed in this PR

Moves SCP receive state from the process working directory into per-session paths and POSIX directory descriptors.

Changes:

  • Adds dirfd-relative file and directory creation with symlink protections.
  • Tracks and releases receive paths, descriptors, and parent identities per session.
  • Adds regression tests and fallback-build CI coverage.
File Description
src/​wolfscp.c Implements per-session receive traversal.
src/​internal.c Initializes and frees receive state.
wolfssh/​internal.h Adds session receive fields.
wolfssh/​port.h Adds dirfd portability macros.
configure.ac Detects required *at() APIs.
tests/​unit.c Tests traversal, isolation, and moves.
tests/​api.c Updates recursive-test assumptions.
scripts/​scp.test Tests symlink write refusal.
.github/​workflows/​scp-test.yml Adds fallback configuration coverage.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/wolfscp.c Outdated
Comment thread src/wolfscp.c
Comment thread .github/workflows/scp-test.yml
Comment thread src/wolfscp.c

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #1306

Scan targets checked: wolfssh-src, wolfssh-bugs
Coverage: 3 of 6 in-scope changed file(s) opened by the reviewer; not opened: src/internal.c, tests/api.c, wolfssh/internal.h

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Lite

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #1306

Scan targets checked: wolfssh-src, wolfssh-bugs
Coverage: 3 of 4 in-scope changed file(s) opened by the reviewer; not opened: src/port.c

Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Reported findings require changes before merge.

Review tier: Lite

Comment thread src/wolfscp.c
The default SCP receive callback keeps its destination per session, the
base path plus each directory entered, in place of the process working
directory that every session of a threaded server shares. With openat()
it holds that directory open, reaches it and everything created below
it with O_NOFOLLOW, and confirms a reopened parent is the one entered.

- port.h gains WOPENAT, WMKDIRAT, WOLFSSH_O_SEARCH with a search check
  as chdir() made, and WOLFSSH_HAVE_DIRFD, which sizes WOLFSSH so it
  keys only on configure's openat() probe; WOLFSSH_NO_DIRFD opts out
- ports without them open by the full path after a wIsDirNoFollow()
  screen of the base and of each directory entered; a refused base
  frees the receive path
- the receive path is capped at DEFAULT_SCP_FILE_NAME_SZ like the
  send side's; futimes() stands in for futimens() on hosts with
  openat() but not futimens(), such as macOS before 10.13
- unit: ScpRecvCallback_SessionPath walks down and back with the
  working directory untouched, then has the tree moved out from under
  it; a linked base and a file-named directory are refused
- scp.test: a planted symlink at the destination name keeps its target;
  scp-test.yml also builds and tests the fallback

Issue: F-14758, F-13998

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #1306

Scan targets checked: wolfssh-src, wolfssh-bugs
Coverage: 1 of 1 in-scope changed file(s) opened by the reviewer

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Lite

@wolfSSL-Fenrir-bot
wolfSSL-Fenrir-bot dismissed their stale review October 9, 2026 19:26

Fenrir's latest completed scan found no issues; clearing the prior automated change request.

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.

4 participants