Add a state, with buffer, for the receiving of SFTP init message, so that partial read don't cause issues. Activated for the server only at the moment.

pull/550/head
Fabio Alemagna 2023-05-04 17:18:57 +02:00 committed by Fabio
parent 87caf4ad04
commit 975b145a0c
2 changed files with 98 additions and 39 deletions

View File

@ -63,6 +63,7 @@ enum WS_SFTP_STATE_ID {
STATE_ID_RECV = 0x10000, STATE_ID_RECV = 0x10000,
STATE_ID_CHMOD = 0x20000, STATE_ID_CHMOD = 0x20000,
STATE_ID_SETATR = 0x40000, STATE_ID_SETATR = 0x40000,
STATE_ID_RECV_INIT = 0x80000,
}; };
enum WS_SFTP_CHMOD_STATE_ID { enum WS_SFTP_CHMOD_STATE_ID {
@ -239,6 +240,11 @@ typedef struct WS_SFTP_LS_STATE {
} WS_SFTP_LS_STATE; } WS_SFTP_LS_STATE;
typedef struct WS_SFTP_RECV_INIT_STATE {
WS_SFTP_BUFFER buffer;
word32 extSz;
} WS_SFTP_RECV_INIT_STATE;
enum WS_SFTP_GET_STATE_ID { enum WS_SFTP_GET_STATE_ID {
STATE_GET_INIT, STATE_GET_INIT,
STATE_GET_LSTAT, STATE_GET_LSTAT,
@ -762,6 +768,14 @@ static void wolfSSH_SFTP_ClearState(WOLFSSH* ssh, enum WS_SFTP_STATE_ID state)
ssh->setatrState = NULL; ssh->setatrState = NULL;
} }
} }
if (state & STATE_ID_RECV_INIT) {
if (ssh->recvInitState) {
wolfSSH_SFTP_buffer_free(ssh, &ssh->recvInitState->buffer);
WFREE(ssh->recvInitState, ssh->ctx->heap, DYNTYPE_SFTP_STATE);
ssh->recvInitState = NULL;
}
}
} }
} }
@ -987,31 +1001,55 @@ static int SFTP_GetAttributes_Handle(WOLFSSH* ssh, byte* handle, int handleSz,
* returns WS_SUCCESS on success * returns WS_SUCCESS on success
*/ */
static int SFTP_ServerRecvInit(WOLFSSH* ssh) { static int SFTP_ServerRecvInit(WOLFSSH* ssh) {
int len; enum {
RECV_INIT_SIZE = LENGTH_SZ + MSG_ID_SZ + UINT32_SZ
};
int ret;
byte id; byte id;
word32 sz = 0; word32 sz = 0;
word32 version = 0; word32 version = 0;
byte buf[LENGTH_SZ + MSG_ID_SZ + UINT32_SZ]; WS_SFTP_RECV_INIT_STATE *state;
if ((len = wolfSSH_stream_read(ssh, buf, sizeof(buf))) != sizeof(buf)) { state = ssh->recvInitState;
return len; if (state == NULL) {
state = (WS_SFTP_RECV_INIT_STATE*)WMALLOC(sizeof(WS_SFTP_RECV_INIT_STATE),
ssh->ctx->heap, DYNTYPE_SFTP_STATE);
if (state == NULL) {
ssh->error = WS_MEMORY_E;
return WS_FATAL_ERROR;
}
WMEMSET(state, 0, sizeof(WS_SFTP_RECV_INIT_STATE));
ssh->recvInitState = state;
} }
if (SFTP_GetSz(buf, &sz, switch (ssh->sftpState) {
case SFTP_BEGIN:
ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, RECV_INIT_SIZE);
if (ret < 0) {
return WS_FATAL_ERROR;
}
if (ret < WOLFSSH_SFTP_HEADER) {
WLOG(WS_LOG_SFTP, "Unable to read SFTP INIT message");
return WS_FATAL_ERROR;
}
if (SFTP_GetSz(state->buffer.data, &sz,
MSG_ID_SZ + UINT32_SZ, WOLFSSH_MAX_SFTP_RECV) != WS_SUCCESS) { MSG_ID_SZ + UINT32_SZ, WOLFSSH_MAX_SFTP_RECV) != WS_SUCCESS) {
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL); wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
return WS_BUFFER_E; return WS_BUFFER_E;
} }
/* compare versions supported */ /* compare versions supported */
id = buf[LENGTH_SZ]; id = state->buffer.data[LENGTH_SZ];
if (id != WOLFSSH_FTP_INIT) { if (id != WOLFSSH_FTP_INIT) {
WLOG(WS_LOG_SFTP, "Unexpected SFTP type received"); WLOG(WS_LOG_SFTP, "Unexpected SFTP type received");
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL); wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
return WS_BUFFER_E; return WS_BUFFER_E;
} }
ato32(buf + LENGTH_SZ + MSG_ID_SZ, &version); ato32(state->buffer.data + LENGTH_SZ + MSG_ID_SZ, &version);
/* versions greater than WOLFSSH_SFTP_VERSION should fall back to ours /* versions greater than WOLFSSH_SFTP_VERSION should fall back to ours
* versions less than WOLFSSH_SFTP_VERSION we should bail out on or * versions less than WOLFSSH_SFTP_VERSION we should bail out on or
* implement a fall back */ * implement a fall back */
@ -1021,15 +1059,27 @@ static int SFTP_ServerRecvInit(WOLFSSH* ssh) {
return WS_VERSION_E; return WS_VERSION_E;
} }
wolfSSH_SFTP_buffer_free(ssh, &state->buffer);
state->extSz = sz - MSG_ID_SZ - UINT32_SZ;
ssh->sftpState = SFTP_EXT;
NO_BREAK;
case SFTP_EXT:
/* silently ignore extensions if not supported */ /* silently ignore extensions if not supported */
sz = sz - MSG_ID_SZ - UINT32_SZ; if (state->extSz > 0) {
if (sz > 0) { ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, (int)state->extSz);
byte* data = (byte*)WMALLOC(sz, NULL, DYNTYPE_BUFFER); if (ret < 0) {
if (data == NULL) return WS_MEMORY_E; return WS_FATAL_ERROR;
len = wolfSSH_stream_read(ssh, data, sz); }
WFREE(data, NULL, DYNTYPE_BUFFER);
if (len != (int)sz) if (ret < (int)state->extSz) {
return len; WLOG(WS_LOG_SFTP, "Unable to read SFTP INIT extensions");
return WS_FATAL_ERROR;
}
wolfSSH_SFTP_buffer_free(ssh, &state->buffer);
}
} }
ssh->reqId++; ssh->reqId++;
@ -1063,7 +1113,7 @@ static int SFTP_ServerSendInit(WOLFSSH* ssh) {
*/ */
int wolfSSH_SFTP_accept(WOLFSSH* ssh) int wolfSSH_SFTP_accept(WOLFSSH* ssh)
{ {
int ret = WS_SFTP_COMPLETE; int ret = WS_FATAL_ERROR;
if (ssh == NULL) { if (ssh == NULL) {
return WS_BAD_ARGUMENT; return WS_BAD_ARGUMENT;
@ -1090,18 +1140,25 @@ int wolfSSH_SFTP_accept(WOLFSSH* ssh)
switch (ssh->sftpState) { switch (ssh->sftpState) {
case SFTP_BEGIN: case SFTP_BEGIN:
if (SFTP_ServerRecvInit(ssh) != WS_SUCCESS) { case SFTP_EXT:
return WS_FATAL_ERROR; ret = SFTP_ServerRecvInit(ssh);
if (ret != WS_SUCCESS) {
if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE)
wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL);
return ret;
} }
ssh->sftpState = SFTP_RECV; ssh->sftpState = SFTP_RECV;
NO_BREAK; NO_BREAK;
case SFTP_RECV: case SFTP_RECV:
if (SFTP_ServerSendInit(ssh) != WS_SUCCESS) { ret = SFTP_ServerSendInit(ssh);
return WS_FATAL_ERROR; if (ret != WS_SUCCESS) {
return ret;
} }
ssh->sftpState = SFTP_DONE; ssh->sftpState = SFTP_DONE;
WLOG(WS_LOG_SFTP, "SFTP connection established"); WLOG(WS_LOG_SFTP, "SFTP connection established");
wolfSSH_SFTP_ClearState(ssh, STATE_ID_RECV_INIT);
ret = WS_SFTP_COMPLETE;
break; break;
default: default:

View File

@ -578,6 +578,7 @@ typedef struct SFTP_OFST {
char to[WOLFSSH_MAX_FILENAME]; char to[WOLFSSH_MAX_FILENAME];
} SFTP_OFST; } SFTP_OFST;
struct WS_SFTP_RECV_INIT_STATE;
struct WS_SFTP_GET_STATE; struct WS_SFTP_GET_STATE;
struct WS_SFTP_PUT_STATE; struct WS_SFTP_PUT_STATE;
struct WS_SFTP_LSTAT_STATE; struct WS_SFTP_LSTAT_STATE;
@ -754,6 +755,7 @@ struct WOLFSSH {
#ifdef WOLFSSH_STOREHANDLE #ifdef WOLFSSH_STOREHANDLE
WS_HANDLE_LIST* handleList; WS_HANDLE_LIST* handleList;
#endif #endif
struct WS_SFTP_RECV_INIT_STATE* recvInitState;
struct WS_SFTP_RECV_STATE* recvState; struct WS_SFTP_RECV_STATE* recvState;
struct WS_SFTP_RMDIR_STATE* rmdirState; struct WS_SFTP_RMDIR_STATE* rmdirState;
struct WS_SFTP_MKDIR_STATE* mkdirState; struct WS_SFTP_MKDIR_STATE* mkdirState;