From f565ae4cc7841e1525987e763defa0204c7398b4 Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Fri, 2 Aug 2019 11:01:29 +0800 Subject: [PATCH] net: Fix access beyond tracee buffer for MSG_TRUNC receives The recv(), recvfrom() and recvmsg() calls allow a MSG_TRUNC flag, which indicates that the kernel should return the available size of an incoming message, rather than the received size. When strace-ing a truncated recv(), strace will try to access a return-value size area of the tracee's buffer, which may be larger than the actual buffer: $ obj/strace -e trace=recvfrom ~/tmp/recv-test recvfrom(3, "\1\2\3\4\0\0\0\0", 4, MSG_TRUNC, NULL, NULL) = 8 If I add a non-readable guard page after the tracee's recv buffer, we see strace failing to read the vm area: $ obj/strace -e trace=recvfrom ~/tmp/recv-test+guard recvfrom(3, obj/strace: umoven: short read (4 < 8) @0x7f0b0d7ddffc 0x7f0b0d7ddffc, 4, MSG_TRUNC, NULL, NULL) = 8 This change restricts the maximum read size to the size of the tracee's actual buffer. The recvmsg() handler will do the right thing by using the .iov_len data, so no change is required there. * net.c (sys_recv, sys_recvfrom): Clamp maximum sockbuf size. --- net.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net.c b/net.c index 1cece9af..b4b3ac40 100644 --- a/net.c +++ b/net.c @@ -291,7 +291,8 @@ SYS_FUNC(recv) printaddr(tcp->u_arg[1]); } else { decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], - tcp->u_rval); + MIN((kernel_ulong_t) tcp->u_rval, + tcp->u_arg[2])); } tprintf(", %" PRI_klu ", ", tcp->u_arg[2]); @@ -316,7 +317,8 @@ SYS_FUNC(recvfrom) printaddr(tcp->u_arg[1]); } else { decode_sockbuf(tcp, tcp->u_arg[0], tcp->u_arg[1], - tcp->u_rval); + MIN((kernel_ulong_t) tcp->u_rval, + tcp->u_arg[2])); } /* size */ tprintf(", %" PRI_klu ", ", tcp->u_arg[2]); -- 2.40.0