Skip to content

Commit 4dd113a

Browse files
committed
liburing.h: fix integer overflow in recvmsg_validate and payload_length wraparound
Signed-off-by: Youichi Uemura <youichi0929@outlook.jp>
1 parent 20b3fe6 commit 4dd113a

2 files changed

Lines changed: 80 additions & 3 deletions

File tree

src/include/liburing.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,9 +1195,17 @@ IOURINGINLINE struct io_uring_recvmsg_out *
11951195
io_uring_recvmsg_validate(void *buf, int buf_len, struct msghdr *msgh)
11961196
LIBURING_NOEXCEPT
11971197
{
1198-
unsigned long header = msgh->msg_controllen + msgh->msg_namelen +
1199-
sizeof(struct io_uring_recvmsg_out);
1200-
if (buf_len < 0 || (unsigned long)buf_len < header)
1198+
unsigned long ulen = (unsigned long)(unsigned int)buf_len;
1199+
unsigned long hdr = sizeof(struct io_uring_recvmsg_out);
1200+
unsigned long namelen = msgh->msg_namelen;
1201+
unsigned long controllen = msgh->msg_controllen;
1202+
1203+
if (buf_len < 0 || ulen < hdr)
1204+
return NULL;
1205+
/* check each addition separately to avoid integer overflow */
1206+
if (namelen > ulen - hdr)
1207+
return NULL;
1208+
if (controllen > ulen - hdr - namelen)
12011209
return NULL;
12021210
return (struct io_uring_recvmsg_out *)buf;
12031211
}
@@ -1257,8 +1265,12 @@ io_uring_recvmsg_payload_length(struct io_uring_recvmsg_out *o,
12571265
{
12581266
unsigned long payload_start, payload_end;
12591267

1268+
if (buf_len < 0)
1269+
return 0;
12601270
payload_start = (unsigned long) io_uring_recvmsg_payload(o, msgh);
12611271
payload_end = (unsigned long) o + buf_len;
1272+
if (payload_start >= payload_end)
1273+
return 0;
12621274
return (unsigned int) (payload_end - payload_start);
12631275
}
12641276

test/recv-multishot.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,65 @@ static int test(struct args *args)
474474
return ret;
475475
}
476476

477+
static int test_recvmsg_validate(void)
478+
{
479+
struct io_uring_recvmsg_out *o;
480+
unsigned char buf[64];
481+
struct msghdr msgh;
482+
unsigned int len;
483+
484+
memset(buf, 0, sizeof(buf));
485+
memset(&msgh, 0, sizeof(msgh));
486+
o = (struct io_uring_recvmsg_out *)buf;
487+
488+
msgh.msg_namelen = 4;
489+
msgh.msg_controllen = 8;
490+
if (!io_uring_recvmsg_validate(buf, 64, &msgh))
491+
return -1;
492+
493+
/* exact fit */
494+
if (!io_uring_recvmsg_validate(buf, 28, &msgh))
495+
return -1;
496+
497+
/* one byte short */
498+
if (io_uring_recvmsg_validate(buf, 27, &msgh))
499+
return -1;
500+
501+
/* negative buf_len */
502+
if (io_uring_recvmsg_validate(buf, -1, &msgh))
503+
return -1;
504+
505+
/* buf smaller than header alone */
506+
msgh.msg_namelen = 0;
507+
msgh.msg_controllen = 0;
508+
if (io_uring_recvmsg_validate(buf, 15, &msgh))
509+
return -1;
510+
511+
/* controllen overflow must be rejected */
512+
msgh.msg_controllen = (socklen_t)(~(socklen_t)0 - sizeof(struct io_uring_recvmsg_out));
513+
msgh.msg_namelen = 4;
514+
if (io_uring_recvmsg_validate(buf, 64, &msgh))
515+
return -1;
516+
517+
msgh.msg_namelen = 4;
518+
msgh.msg_controllen = 8;
519+
len = io_uring_recvmsg_payload_length(o, 64, &msgh);
520+
if (len != 36)
521+
return -1;
522+
523+
/* negative buf_len */
524+
if (io_uring_recvmsg_payload_length(o, -1, &msgh) != 0)
525+
return -1;
526+
527+
/* name+ctrl > buf_len must return 0, not wrap around */
528+
msgh.msg_namelen = 40;
529+
msgh.msg_controllen = 30;
530+
if (io_uring_recvmsg_payload_length(o, 64, &msgh) != 0)
531+
return -1;
532+
533+
return 0;
534+
}
535+
477536
static int test_enobuf(void)
478537
{
479538
struct io_uring ring;
@@ -564,6 +623,12 @@ int main(int argc, char *argv[])
564623

565624
has_defer = t_probe_defer_taskrun();
566625

626+
ret = test_recvmsg_validate();
627+
if (ret) {
628+
fprintf(stderr, "test_recvmsg_validate() failed: %d\n", ret);
629+
return T_EXIT_FAIL;
630+
}
631+
567632
for (loop = 0; loop < 16; loop++) {
568633
struct args a = {
569634
.stream = loop & 0x01,

0 commit comments

Comments
 (0)