Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions src/wolfsftp.c
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ static int SFTP_AddFileHandle(WOLFSSH* ssh,
#endif
const char* fileName, word32 id[2]);
static int SFTP_RemoveFileHandle(WOLFSSH* ssh, word32 id[2]);
static int SFTP_FileHandleCapped(WOLFSSH* ssh);
#endif /* !NO_WOLFSSH_SERVER */

/* Returns WS_SUCCESS if a server-side inbound SFTP message body of the given
Expand Down Expand Up @@ -2348,6 +2349,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
char oer[] = "Open File Error";
char naf[] = "Not A File";
char per[] = "Permission denied";
char tmf[] = "Too Many Open File Handles";
int handleStored = 0;

if (ssh == NULL) {
Expand Down Expand Up @@ -2386,6 +2388,16 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
goto cleanup;
}

/* Check the cap before opening. The open flags may carry O_CREAT/O_TRUNC,
* so refusing after the fact would leave the file created or truncated on
* a request the peer is told failed. */
if (SFTP_FileHandleCapped(ssh)) {
WLOG(WS_LOG_SFTP, "Too many open file handles for session");
rc = SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, tmf);
ret = (rc == WS_SUCCESS) ? WS_BAD_FILE_E : rc;
goto cleanup;
}

/* get reason for opening file */
if (GetUint32(&reason, data, maxSz, &idx) != WS_SUCCESS) {
ret = WS_BUFFER_E;
Expand Down Expand Up @@ -2572,6 +2584,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
char ier[] = "Internal Failure";
char oer[] = "Open File Error";
char per[] = "Permission denied";
char tmf[] = "Too Many Open File Handles";
int handleStored = 0;

fileHandle = INVALID_HANDLE_VALUE;
Expand Down Expand Up @@ -2606,6 +2619,16 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
goto cleanup;
}

/* Check the cap before opening. The open flags may carry O_CREAT/O_TRUNC,
* so refusing after the fact would leave the file created or truncated on
* a request the peer is told failed. */
if (SFTP_FileHandleCapped(ssh)) {
WLOG(WS_LOG_SFTP, "Too many open file handles for session");
rc = SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, tmf);
ret = (rc == WS_SUCCESS) ? WS_BAD_FILE_E : rc;
goto cleanup;
}

/* get reason for opening file */
if (GetUint32(&reason, data, maxSz, &idx) != WS_SUCCESS) {
ret = WS_BUFFER_E;
Expand Down Expand Up @@ -2750,6 +2773,22 @@ struct WS_DIR_LIST {
};


/* returns 1 when the session already holds the maximum directory handles */
static int SFTP_DirHandleCapped(WOLFSSH* ssh)
{
WS_DIR_LIST* cur;
word32 count = 0;

for (cur = ssh->dirList; cur != NULL; cur = cur->next) {
if (++count >= WOLFSSH_MAX_SFTP_HANDLES) {
return 1;
}
}

return 0;
}


/* Handles packet to open a directory
*
* returns WS_SUCCESS on success
Expand All @@ -2769,6 +2808,7 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
byte* out = NULL;
byte idFlat[WOLFSSH_HANDLE_ID_SZ];
char per[] = "Permission denied";
char tooMany[] = "Too Many Open Directory Handles";

if (ssh == NULL) {
return WS_BAD_ARGUMENT;
Expand Down Expand Up @@ -2796,6 +2836,13 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}

/* check the cap before opening, so there is nothing to unwind */
if (SFTP_DirHandleCapped(ssh)) {
WLOG(WS_LOG_SFTP, "Too many open directory handles for session");
rc = SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, tooMany);
return (rc == WS_SUCCESS) ? WS_BAD_FILE_E : rc;
}

if (WOPENDIR(ssh->fs, ssh->ctx->heap, &ctx, dir) != 0) {
WLOG(WS_LOG_SFTP, "Error with opening directory: %s", dir);
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_NOFILE, reqId,
Expand Down Expand Up @@ -2882,6 +2929,7 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
char name[MAX_PATH];
char clean[WOLFSSH_MAX_FILENAME];
char per[] = "Permission denied";
char tooMany[] = "Too Many Open Directory Handles";

if (ssh == NULL) {
return WS_BAD_ARGUMENT;
Expand Down Expand Up @@ -2920,6 +2968,13 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}

/* check the cap before allocating, so there is nothing to unwind */
if (SFTP_DirHandleCapped(ssh)) {
WLOG(WS_LOG_SFTP, "Too many open directory handles for session");
rc = SFTP_SendStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, tooMany);
return (rc == WS_SUCCESS) ? WS_BAD_FILE_E : rc;
}

/* plus one to make sure is null terminated */
dirNameSz = (word32)WSTRLEN(clean) + 1;
dirName = (char*)WMALLOC(dirNameSz, ssh->ctx->heap, DYNTYPE_BUFFER);
Expand Down Expand Up @@ -4003,6 +4058,22 @@ int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle, word32 handleSz)

#endif /* NO_WOLFSSH_DIR */

/* returns 1 when the session already holds the maximum file handles */
static int SFTP_FileHandleCapped(WOLFSSH* ssh)
{
WS_FILE_LIST* cur;
word32 count = 0;

for (cur = ssh->fileList; cur != NULL; cur = cur->next) {
if (++count >= WOLFSSH_MAX_SFTP_HANDLES) {
return 1;
}
}

return 0;
}


/* Add a file handle to the tracking list keeping track of open files
* returns WS_SUCCESS on success */
static int SFTP_AddFileHandle(WOLFSSH* ssh,
Expand All @@ -4021,6 +4092,14 @@ static int SFTP_AddFileHandle(WOLFSSH* ssh,
return WS_BAD_ARGUMENT;
}

/* Backstop only. RecvOpen checks the cap before opening the file, so a
* refused request leaves no O_CREAT/O_TRUNC side effect behind; reaching
* the cap here means a caller skipped that check. */
if (SFTP_FileHandleCapped(ssh)) {
WLOG(WS_LOG_SFTP, "Too many open file handles for session");
return WS_MEMORY_E;
}

cur = (WS_FILE_LIST*)WMALLOC(sizeof(WS_FILE_LIST), ssh->ctx->heap,
DYNTYPE_SFTP);
if (cur == NULL) {
Expand Down Expand Up @@ -6313,6 +6392,23 @@ int wolfSSH_SFTP_TestFileHandleCount(WOLFSSH* ssh)
return count;
}

#ifndef NO_WOLFSSH_DIR
/* Return the number of open directory handles tracked for the session. */
int wolfSSH_SFTP_TestDirHandleCount(WOLFSSH* ssh)
{
WS_DIR_LIST* cur;
int count = 0;

if (ssh == NULL) {
return 0;
}
for (cur = ssh->dirList; cur != NULL; cur = cur->next) {
count++;
}
return count;
}
#endif /* NO_WOLFSSH_DIR */

/* Close the underlying descriptor of the head tracked file handle out of band,
* leaving the node in the list with a now-stale fd. The next RecvClose on that
* handle will see its close() fail, exercising the path that must still drop
Expand Down
Loading
Loading