Skip to content

wolfscp: fix ExtractFileName for separator-less paths#1020

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/scpRecursive
Open

wolfscp: fix ExtractFileName for separator-less paths#1020
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/scpRecursive

Conversation

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor

Fix recursive SCP source abort on separator-less paths

Problem

A recursive SCP source request for a bare relative name with no path separator — e.g. scp -r -f scp_rk_src — aborted immediately after sending the top-level directory message, transferring no files. The receiving side saw WS_SUCCESS but ended up with an empty destination. Absolute paths and any path containing a / worked fine.

Root cause

ExtractFileName() rejected any path with no / or \ separator:

if (separator < 0)
    return WS_BAD_ARGUMENT;

In the recursive first-request path, ScpPushDir() opened the directory successfully, but the following ExtractFileName(peerRequest, ...) returned WS_BAD_ARGUMENT (-1002) for the bare name. The failure then fell into a branch mislabeled "scp: error getting file stats, abort" — so the log pointed at GetFileStats, which was never actually reached. The same helper feeds the single-file request path, so a single-file GET of a bare filename had the same latent bug.

A path with no separator is a valid bare file/directory name (the whole string is the leaf name); the existing length math already handles the separator == -1 case, so only the early-return guard was wrong.

Changes

  • src/wolfscp.cExtractFileName(): reject only a genuinely empty path (if (pathLen == 0)) instead of any separator-less path. No behavior change for paths containing a separator (absolute paths unchanged). Fixes both the recursive-source and single-file request paths.
  • src/wolfscp.c — recursive first-request branch: split the single misleading "error getting file stats" log into per-step messages (open base directory / extract name / get file stats), so a future failure names the actual culprit. Keeps the existing fallthrough cleanup style.
  • tests/unit.ctest_ScpExtractFileName: new unit test covering bare name, ./ prefix, nested, absolute, ./.., trailing separator, empty, NULL args, too-small buffer, and the exact size-check boundary. ExtractFileName stays static; the test reaches it through a new wolfSSH_TestScpExtractFileName wrapper guarded by WOLFSSH_TEST_INTERNAL.
  • wolfssh/internal.h: prototype for the test wrapper inside the existing WOLFSSH_TEST_INTERNAL block, sub-guarded by WOLFSSH_SCP && !WOLFSSH_SCP_USER_CALLBACKS.

Notes

ExtractFileName was never a path-traversal guard — ../x-style paths always have separator >= 0 and passed through unchanged; only a trivial bare ./.. was incidentally rejected before. Accepting ./.. now matches real scp semantics (scp -r host:. dst); ./.. directory entries are still skipped during the recursive walk, and sink-side path confinement is separate.

Testing

  • tests/unit.testScpExtractFileName: SUCCESS. Negative control: with the old guard restored the test FAILS (exit 1), so it genuinely catches the bug.
  • ASan + UBSan unit build (-fsanitize=address,undefined, no LeakSanitizer on macOS) → clean.
  • scripts/scp.testALL Tests Passed (single-file client path unaffected).
  • End-to-end: recursive transfer of a relative source tree (big.txt, sub/s.txt, top.txt) completes byte-identical (diff -r clean) against examples/echoserver.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Jun 11, 2026
Copilot AI review requested due to automatic review settings June 11, 2026 07:38

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

Fixes wolfSCP source-mode failures when the peer requests a bare relative name (no / or \ separators), which previously caused ExtractFileName() to return WS_BAD_ARGUMENT and abort recursive (and latent single-file) transfers.

Changes:

  • Update ExtractFileName() to reject only truly empty paths, allowing separator-less leaf names.
  • Improve recursive first-request error logging by reporting failures per-step (open dir / extract name / stat).
  • Add internal unit coverage for ExtractFileName() via a new WOLFSSH_TEST_INTERNAL wrapper and a comprehensive unit test.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/wolfscp.c Fixes separator-less path handling in ExtractFileName(), adds an internal test wrapper, and refines recursive-request error logs.
tests/unit.c Adds test_ScpExtractFileName covering bare names and a broad set of edge/error cases.
wolfssh/internal.h Declares the new internal test wrapper under appropriate SCP and test guards.

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

@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 #1020

Scan targets checked: wolfssh-bugs, wolfssh-src

No new issues found in the changed files. ✅

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