Skip to content

Commit 2a1cbef

Browse files
Fix SFTP rekey transparency in buffer_read and buffer_send
1 parent fd33457 commit 2a1cbef

1 file changed

Lines changed: 35 additions & 4 deletions

File tree

src/wolfsftp.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ static int wolfSSH_SFTP_buffer_send(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer)
517517
int ret = WS_SUCCESS;
518518
int err;
519519

520-
if (buffer == NULL) {
520+
if (buffer == NULL || ssh == NULL) {
521521
return WS_BAD_ARGUMENT;
522522
}
523523

@@ -538,11 +538,25 @@ static int wolfSSH_SFTP_buffer_send(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer)
538538
}
539539
}
540540

541-
/* Call wolfSSH worker if rekeying or adjusting window size */
541+
/* Best-effort: drive the worker while a rekey or full window blocks sending.
542+
* Also checks ssh->isKeying for a rekey triggered by a receive
543+
* (HighwaterCheck) where ssh->error holds a different code. If the window is
544+
* still full after this (e.g. worker returned WS_CHAN_RXD), stream_send
545+
* returns WS_WINDOW_FULL and the caller retries via NoticeError(). */
542546
err = wolfSSH_get_error(ssh);
543-
if (err == WS_WINDOW_FULL || err == WS_REKEYING) {
544-
(void)wolfSSH_worker(ssh, NULL);
547+
while (ssh->isKeying || err == WS_WINDOW_FULL || err == WS_REKEYING) {
548+
ret = wolfSSH_worker(ssh, NULL);
549+
/* Only a rekey/window/channel-data status means "keep driving". Any
550+
* other negative status (fatal error, or WS_WANT_READ/WS_WANT_WRITE on
551+
* a non-blocking socket) is returned so a stalled or dead rekey cannot
552+
* spin forever. */
553+
if (ret < 0 && ret != WS_REKEYING && ret != WS_WINDOW_FULL
554+
&& ret != WS_CHAN_RXD) {
555+
return ret;
556+
}
557+
err = wolfSSH_get_error(ssh);
545558
}
559+
ret = WS_SUCCESS;
546560

547561
if (buffer->idx < buffer->sz) {
548562
ret = wolfSSH_stream_send(ssh, buffer->data + buffer->idx,
@@ -577,6 +591,7 @@ static int wolfSSH_SFTP_buffer_read(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer,
577591
int readSz)
578592
{
579593
int ret;
594+
int polled;
580595
byte peekBuf[1];
581596

582597
if (buffer == NULL || ssh == NULL) {
@@ -598,9 +613,11 @@ static int wolfSSH_SFTP_buffer_read(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer,
598613
}
599614

600615
do {
616+
polled = 0;
601617
if (!wolfSSH_stream_peek(ssh, peekBuf, 1)) {
602618
/* poll more data off the wire */
603619
ret = wolfSSH_worker(ssh, NULL);
620+
polled = 1;
604621
}
605622
else {
606623
ret = WS_CHAN_RXD; /* existing data found with peek */
@@ -611,6 +628,20 @@ static int wolfSSH_SFTP_buffer_read(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer,
611628
buffer->sz - buffer->idx);
612629
}
613630
if (ret < 0) {
631+
if (wolfSSH_get_error(ssh) == WS_REKEYING) {
632+
/* Drive the rekey forward only if the top of the loop did not
633+
* already poll this iteration. Keep looping while it is still
634+
* in progress; a genuine failure changes ssh->error and is
635+
* returned. */
636+
if (!polled) {
637+
ret = wolfSSH_worker(ssh, NULL);
638+
if (ret < 0 && ret != WS_CHAN_RXD
639+
&& wolfSSH_get_error(ssh) != WS_REKEYING) {
640+
return WS_FATAL_ERROR;
641+
}
642+
}
643+
continue;
644+
}
614645
return WS_FATAL_ERROR;
615646
}
616647
buffer->idx += (word32)ret;

0 commit comments

Comments
 (0)