Skip to content

Commit 6645fee

Browse files
committed
Test SFTP forged handles and namespace isolation
- Reject forged/raw-fd handles in Write/Read/FSetSTAT/FSTAT/Close - Isolate file vs directory handle-ID namespaces - Cover positive and forged FSTAT
1 parent a6570e0 commit 6645fee

3 files changed

Lines changed: 543 additions & 0 deletions

File tree

src/wolfsftp.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6124,6 +6124,92 @@ int wolfSSH_SFTP_RecvFSetSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
61246124
}
61256125

61266126
#endif /* _WIN32_WCE */
6127+
6128+
#if defined(WOLFSSH_TEST_INTERNAL) && !defined(USE_WINDOWS_API) && \
6129+
!defined(NO_FILESYSTEM)
6130+
/* Test-only plumbing for the forged-handle regression test in tests/regress.c.
6131+
*
6132+
* The SFTP request handlers buffer their status/handle reply into ssh->recvState
6133+
* via wolfSSH_SFTP_RecvSetSend(). When a test drives the handlers directly that
6134+
* state is not otherwise allocated, so these accessors let the test own its
6135+
* lifetime (and inspect the buffered reply) without exposing the private
6136+
* WS_SFTP_RECV_STATE type. */
6137+
6138+
/* Allocate ssh->recvState so handler replies are captured instead of leaked. */
6139+
int wolfSSH_SFTP_TestRecvStateInit(WOLFSSH* ssh)
6140+
{
6141+
if (ssh == NULL) {
6142+
return WS_BAD_ARGUMENT;
6143+
}
6144+
if (ssh->recvState == NULL) {
6145+
ssh->recvState = (WS_SFTP_RECV_STATE*)WMALLOC(
6146+
sizeof(WS_SFTP_RECV_STATE), ssh->ctx->heap, DYNTYPE_SFTP_STATE);
6147+
if (ssh->recvState == NULL) {
6148+
return WS_MEMORY_E;
6149+
}
6150+
WMEMSET(ssh->recvState, 0, sizeof(WS_SFTP_RECV_STATE));
6151+
}
6152+
return WS_SUCCESS;
6153+
}
6154+
6155+
/* Return the most recent buffered reply (data + size) produced by a handler. */
6156+
const byte* wolfSSH_SFTP_TestRecvReply(WOLFSSH* ssh, word32* sz)
6157+
{
6158+
if (ssh == NULL || ssh->recvState == NULL) {
6159+
if (sz != NULL) {
6160+
*sz = 0;
6161+
}
6162+
return NULL;
6163+
}
6164+
if (sz != NULL) {
6165+
*sz = ssh->recvState->buffer.sz;
6166+
}
6167+
return ssh->recvState->buffer.data;
6168+
}
6169+
6170+
/* Free ssh->recvState and any buffered reply. */
6171+
void wolfSSH_SFTP_TestRecvStateFree(WOLFSSH* ssh)
6172+
{
6173+
if (ssh != NULL) {
6174+
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
6175+
}
6176+
}
6177+
6178+
/* Return the number of open file handles tracked for the session. Lets the
6179+
* handle-cap and close-failure regression tests observe the tracking list
6180+
* without exposing the private WS_FILE_LIST type. */
6181+
int wolfSSH_SFTP_TestFileHandleCount(WOLFSSH* ssh)
6182+
{
6183+
WS_FILE_LIST* cur;
6184+
int count = 0;
6185+
6186+
if (ssh == NULL) {
6187+
return 0;
6188+
}
6189+
for (cur = ssh->fileList; cur != NULL; cur = cur->next) {
6190+
count++;
6191+
}
6192+
return count;
6193+
}
6194+
6195+
/* Close the underlying descriptor of the head tracked file handle out of band,
6196+
* leaving the node in the list with a now-stale fd. The next RecvClose on that
6197+
* handle will see its close() fail, exercising the path that must still drop
6198+
* the handle from the tracking list. Returns WS_SUCCESS if a node was found. */
6199+
int wolfSSH_SFTP_TestInvalidateHeadFd(WOLFSSH* ssh)
6200+
{
6201+
if (ssh == NULL || ssh->fileList == NULL) {
6202+
return WS_BAD_ARGUMENT;
6203+
}
6204+
#ifdef MICROCHIP_MPLAB_HARMONY
6205+
WFCLOSE(ssh->fs, &ssh->fileList->fd);
6206+
#else
6207+
WCLOSE(ssh->fs, ssh->fileList->fd);
6208+
#endif
6209+
return WS_SUCCESS;
6210+
}
6211+
#endif /* WOLFSSH_TEST_INTERNAL && !USE_WINDOWS_API && !NO_FILESYSTEM */
6212+
61276213
#endif /* !NO_WOLFSSH_SERVER */
61286214

61296215

0 commit comments

Comments
 (0)