mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-08-09 09:51:49 +08:00
tlslib: harden recv_remaining() against truncated CSTP reads
recv_remaining() is used only on the non-TLS CSTP path (a UNIX socket proxying plaintext CSTP in front of ocserv). On a recv() failure or peer close mid-read, it discarded the error and returned whatever partial byte count it had accumulated so far. Since every caller only checks "ret <= 0" and otherwise trusts the count as a complete read, a truncated body could come back as a positive, non-zero total that looked like success: _cstp_recv_packet() would then report the full 8+pktlen size to its caller with only part of the buffer actually populated from the network, feeding stale/uninitialized bytes into parse_cstp_data() as if they were received client data. Make the contract unambiguous: recv_remaining() now returns either exactly the requested byte count or a negative error - never a partial positive count a caller could mistake for success. Signed-off-by: Nikos Mavrogiannopoulos <n.mavrogiannopoulos@gmail.com>
This commit is contained in:
@@ -87,6 +87,72 @@ void receiver(int fd)
|
||||
}
|
||||
}
|
||||
|
||||
/* Writes a CSTP header announcing a BODY_SIZE-byte body, but only
|
||||
* BODY_SIZE/2 bytes of body, then closes the socket - simulating a
|
||||
* proxy connection dropped mid-packet. A correct _cstp_recv_packet()
|
||||
* must report this as an error, not as a successful, fully-populated
|
||||
* packet built from a truncated buffer. */
|
||||
#define NEG_BODY_SIZE 64
|
||||
|
||||
void neg_writer(int fd)
|
||||
{
|
||||
unsigned char buf[8 + NEG_BODY_SIZE] = { 0 };
|
||||
|
||||
buf[4] = (NEG_BODY_SIZE >> 8) & 0xff;
|
||||
buf[5] = NEG_BODY_SIZE & 0xff;
|
||||
|
||||
assert(write(fd, buf, 8 + NEG_BODY_SIZE / 2) == 8 + NEG_BODY_SIZE / 2);
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void neg_receiver(int fd)
|
||||
{
|
||||
worker_st ws = { 0 };
|
||||
unsigned char buf[8 + NEG_BODY_SIZE];
|
||||
int ret;
|
||||
|
||||
ws.conn_fd = fd;
|
||||
|
||||
ret = _cstp_recv_packet(&ws, buf, sizeof(buf));
|
||||
if (verbose)
|
||||
fprintf(stderr, "negative test received %d\n", ret);
|
||||
|
||||
if (ret > 0) {
|
||||
fprintf(stderr,
|
||||
"FAIL: expected error on truncated packet, got %d\n",
|
||||
ret);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void run_negative_test(void)
|
||||
{
|
||||
int sockets[2];
|
||||
pid_t child;
|
||||
int status = 0;
|
||||
|
||||
assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) >= 0);
|
||||
|
||||
child = fork();
|
||||
assert(child >= 0);
|
||||
|
||||
if (child) {
|
||||
close(sockets[1]);
|
||||
neg_receiver(sockets[0]);
|
||||
wait(&status);
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
fprintf(stderr, "negative test child failed %d!\n",
|
||||
(int)WEXITSTATUS(status));
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
close(sockets[0]);
|
||||
neg_writer(sockets[1]);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int sockets[2];
|
||||
@@ -116,5 +182,7 @@ int main(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
run_negative_test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user