-
Notifications
You must be signed in to change notification settings - Fork 114
Fix multiple reported issues #1084
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
f0ed3ec
48b55c2
9756122
4c7ef4e
fb6496e
baf2356
faba36e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -839,7 +839,18 @@ char* wstrnstr(const char* s1, const char* s2, unsigned int n) | |
| * end of s1 including a null terminator. */ | ||
| char* wstrncat(char* s1, const char* s2, size_t n) | ||
| { | ||
| size_t freeSpace = n - strlen(s1) - 1; | ||
| size_t s1_len = 0; | ||
| size_t freeSpace; | ||
|
|
||
| while (s1_len < n && s1[s1_len] != '\0') { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 [High] wstrncat change breaks RealPath callers that pass remaining capacity · Logic The PR changes wstrncat() to return NULL when s1 is not NUL-terminated within the first n bytes. That matches the helper's documented contract and is safer for callers that pass the full destination size and check the return value, but existing changed-file callers do neither. wolfSSH_RealPath() calls WSTRNCAT(out, ..., outSz - curSz) (src/ssh.c:3843 and src/ssh.c:3846) with remaining capacity instead of the full buffer size while out already holds curSz bytes, and ignores the return. After this PR, for a remote SFTP/SCP path with a long first segment, once curSz >= outSz - curSz the existing terminator is beyond the shortened n, so later appends return NULL even when the final path still fits; wolfSSH_RealPath() still increments curSz and returns WS_SUCCESS with a truncated path (separator/segment omitted). The same new failure mode affects other changed-file SCP path construction such as WSTRNCAT((char*)basePath, "/", sizeof("/")) at src/wolfscp.c:2466. This reaches public wolfSSH_RealPath callers used by SFTP/SCP path handling. Severity note: the Fix: Keep the bounded scan, but update affected callers to pass the full destination buffer size and check WSTRNCAT() return values. In wolfSSH_RealPath(), include the optional slash in the bounds check and use explicit length-based appends or call WSTRNCAT(out, ..., outSz) after the existing bounds checks, returning WS_INVALID_PATH_E on NULL: if (curSz + ((curSz != 1) ? 1 : 0) + segSz >= outSz) { Fix the Nucleus SCP basePath append to use the actual basePath capacity. Add a regression test where a valid resolved path grows beyond half of the output buffer but still fits. |
||
| s1_len++; | ||
| } | ||
|
|
||
| if (s1_len >= n) { | ||
| return NULL; | ||
| } | ||
|
|
||
| freeSpace = n - s1_len - 1; | ||
|
|
||
| if (freeSpace >= strlen(s2)) { | ||
| #ifndef USE_WINDOWS_API | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,9 @@ | |
| #include <wolfssh/internal.h> | ||
| #include <wolfssh/log.h> | ||
|
|
||
| #include <errno.h> | ||
| #include <stdint.h> | ||
|
|
||
|
|
||
| #ifdef NO_INLINE | ||
| #include <wolfssh/misc.h> | ||
|
|
@@ -1093,19 +1096,35 @@ static int GetScpFileSize(WOLFSSH* ssh, byte* buf, word32 bufSz, | |
| ret = WS_SCP_BAD_MSG_E; | ||
|
|
||
| if (ret == WS_SUCCESS) { | ||
| /* replace space with newline for atoi */ | ||
| buf[spaceIdx] = '\n'; | ||
| ssh->scpFileSz = atoi((char *)(buf + idx)); | ||
| /* replace space with newline to terminate the size field, then parse | ||
| * with strtoull() which parses in 64-bit width, so a negative field | ||
| * such as "-1" wraps above UINT32_MAX and is rejected by the bound | ||
| * below instead of becoming a huge word32 size */ | ||
| char* endptr = NULL; | ||
| word64 fileSz; | ||
|
|
||
| /* restore space, increment idx to space */ | ||
| buf[spaceIdx] = '\n'; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 [Medium] New SCP numeric parsing lacks regression coverage · test The PR replaces atoi with strtoull and adds overflow and malformed-field handling for SCP file sizes and timestamps, but the current tests only expose wolfSSH_TestScpGetFileMode; there are no targeted tests for these changed parser paths. This is boundary-heavy protocol parsing, so regressions around negative values, overflow, and partial parses would be easy to miss. Fix: Add WOLFSSH_TEST_INTERNAL wrappers or ReceiveScpMessage-based tests for file sizes -1, UINT32_MAX, UINT32_MAX + 1, empty/non-numeric fields, timestamp overflow, and malformed timestamp fields. |
||
| errno = 0; | ||
| fileSz = (word64)strtoull((char*)(buf + idx), &endptr, 10); | ||
| buf[spaceIdx] = ' '; | ||
| idx = spaceIdx; | ||
|
|
||
| /* eat trailing space */ | ||
| if (bufSz >= (word32)(idx + 1)) | ||
| idx++; | ||
| /* reject any parse error (e.g. ERANGE overflow), a non-numeric field | ||
| * (parse must consume every character up to the separator), and | ||
| * sizes too large for the word32 scpFileSz */ | ||
| if (errno != 0 || endptr != (char*)(buf + spaceIdx) || | ||
| fileSz > UINT32_MAX) { | ||
| ret = WS_SCP_BAD_MSG_E; | ||
| } | ||
| else { | ||
| ssh->scpFileSz = (word32)fileSz; | ||
|
|
||
| *inOutIdx = idx; | ||
| /* increment idx to space, then eat trailing space */ | ||
| idx = spaceIdx; | ||
| if (bufSz >= (word32)(idx + 1)) | ||
| idx++; | ||
|
|
||
| *inOutIdx = idx; | ||
| } | ||
| } | ||
|
|
||
| return ret; | ||
|
|
@@ -1225,15 +1244,23 @@ static int GetScpTimestamp(WOLFSSH* ssh, byte* buf, word32 bufSz, | |
|
|
||
| /* read modification time */ | ||
| if (ret == WS_SUCCESS) { | ||
| /* replace space with newline for atoi */ | ||
| buf[spaceIdx] = '\n'; | ||
| ssh->scpMTime = atoi((char*)(buf + idx)); | ||
| char* endptr = NULL; | ||
|
|
||
| /* restore space, increment idx past it */ | ||
| /* replace space with newline to terminate the field */ | ||
| buf[spaceIdx] = '\n'; | ||
| errno = 0; | ||
| ssh->scpMTime = (word64)strtoull((char*)(buf + idx), &endptr, 10); | ||
| buf[spaceIdx] = ' '; | ||
| if (spaceIdx + 1 < bufSz) { | ||
|
|
||
| /* reject any parse error (e.g. ERANGE overflow) and a non-numeric | ||
| * field, then step past the separating space */ | ||
| if (errno != 0 || endptr != (char*)(buf + spaceIdx)) { | ||
| ret = WS_SCP_TIMESTAMP_E; | ||
| } | ||
| else if (spaceIdx + 1 < bufSz) { | ||
| idx = spaceIdx + 1; | ||
| } else { | ||
| } | ||
| else { | ||
| ret = WS_SCP_TIMESTAMP_E; | ||
| } | ||
| } | ||
|
|
@@ -1264,15 +1291,21 @@ static int GetScpTimestamp(WOLFSSH* ssh, byte* buf, word32 bufSz, | |
| } | ||
|
|
||
| if (ret == WS_SUCCESS) { | ||
| /* replace space with newline for atoi */ | ||
| char* endptr = NULL; | ||
| /* replace space with newline for strtoull */ | ||
| buf[spaceIdx] = '\n'; | ||
| ssh->scpATime = atoi((char*)(buf + idx)); | ||
|
|
||
| errno = 0; | ||
| ssh->scpATime = (word64)strtoull((char*)(buf + idx), &endptr, 10); | ||
| /* restore space, increment idx past it */ | ||
| buf[spaceIdx] = ' '; | ||
| if (spaceIdx + 1 < bufSz) { | ||
|
|
||
| if (errno != 0 || endptr != (char*)(buf + spaceIdx)) { | ||
| ret = WS_SCP_TIMESTAMP_E; | ||
| } | ||
| else if (spaceIdx + 1 < bufSz) { | ||
| idx = spaceIdx + 1; | ||
| } else { | ||
| } | ||
| else { | ||
| ret = WS_SCP_TIMESTAMP_E; | ||
| } | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.