Skip to content

Commit 8a2617d

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 e0402aa commit 8a2617d

3 files changed

Lines changed: 557 additions & 0 deletions

File tree

src/wolfsftp.c

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

62196219
#endif /* _WIN32_WCE */
6220+
6221+
#if defined(WOLFSSH_TEST_INTERNAL) && !defined(USE_WINDOWS_API) && \
6222+
!defined(NO_FILESYSTEM)
6223+
/* Test-only plumbing for the forged-handle regression test in tests/regress.c.
6224+
*
6225+
* The SFTP request handlers buffer their status/handle reply into ssh->recvState
6226+
* via wolfSSH_SFTP_RecvSetSend(). When a test drives the handlers directly that
6227+
* state is not otherwise allocated, so these accessors let the test own its
6228+
* lifetime (and inspect the buffered reply) without exposing the private
6229+
* WS_SFTP_RECV_STATE type. */
6230+
6231+
/* Allocate ssh->recvState so handler replies are captured instead of leaked. */
6232+
int wolfSSH_SFTP_TestRecvStateInit(WOLFSSH* ssh)
6233+
{
6234+
if (ssh == NULL) {
6235+
return WS_BAD_ARGUMENT;
6236+
}
6237+
if (ssh->recvState == NULL) {
6238+
ssh->recvState = (WS_SFTP_RECV_STATE*)WMALLOC(
6239+
sizeof(WS_SFTP_RECV_STATE), ssh->ctx->heap, DYNTYPE_SFTP_STATE);
6240+
if (ssh->recvState == NULL) {
6241+
return WS_MEMORY_E;
6242+
}
6243+
WMEMSET(ssh->recvState, 0, sizeof(WS_SFTP_RECV_STATE));
6244+
}
6245+
return WS_SUCCESS;
6246+
}
6247+
6248+
/* Return the most recent buffered reply (data + size) produced by a handler. */
6249+
const byte* wolfSSH_SFTP_TestRecvReply(WOLFSSH* ssh, word32* sz)
6250+
{
6251+
if (ssh == NULL || ssh->recvState == NULL) {
6252+
if (sz != NULL) {
6253+
*sz = 0;
6254+
}
6255+
return NULL;
6256+
}
6257+
if (sz != NULL) {
6258+
*sz = ssh->recvState->buffer.sz;
6259+
}
6260+
return ssh->recvState->buffer.data;
6261+
}
6262+
6263+
/* Free ssh->recvState and any buffered reply. */
6264+
void wolfSSH_SFTP_TestRecvStateFree(WOLFSSH* ssh)
6265+
{
6266+
if (ssh != NULL) {
6267+
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
6268+
}
6269+
}
6270+
6271+
/* Return the number of open file handles tracked for the session. Lets the
6272+
* handle-cap and close-failure regression tests observe the tracking list
6273+
* without exposing the private WS_FILE_LIST type. */
6274+
int wolfSSH_SFTP_TestFileHandleCount(WOLFSSH* ssh)
6275+
{
6276+
WS_FILE_LIST* cur;
6277+
int count = 0;
6278+
6279+
if (ssh == NULL) {
6280+
return 0;
6281+
}
6282+
for (cur = ssh->fileList; cur != NULL; cur = cur->next) {
6283+
count++;
6284+
}
6285+
return count;
6286+
}
6287+
6288+
/* Close the underlying descriptor of the head tracked file handle out of band,
6289+
* leaving the node in the list with a now-stale fd. The next RecvClose on that
6290+
* handle will see its close() fail, exercising the path that must still drop
6291+
* the handle from the tracking list. Returns WS_SUCCESS if a node was found. */
6292+
int wolfSSH_SFTP_TestInvalidateHeadFd(WOLFSSH* ssh)
6293+
{
6294+
if (ssh == NULL || ssh->fileList == NULL) {
6295+
return WS_BAD_ARGUMENT;
6296+
}
6297+
#ifdef MICROCHIP_MPLAB_HARMONY
6298+
WFCLOSE(ssh->fs, &ssh->fileList->fd);
6299+
#else
6300+
WCLOSE(ssh->fs, ssh->fileList->fd);
6301+
#endif
6302+
return WS_SUCCESS;
6303+
}
6304+
#endif /* WOLFSSH_TEST_INTERNAL && !USE_WINDOWS_API && !NO_FILESYSTEM */
6305+
62206306
#endif /* !NO_WOLFSSH_SERVER */
62216307

62226308

0 commit comments

Comments
 (0)