From: Dmitry V. Levin Date: Wed, 20 Jan 2016 03:26:37 +0000 (+0000) Subject: Fix dumping of recvmsg syscall in case of short read X-Git-Tag: v4.12~621 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=93c9d1cdbdc9d1f406f5a773eac987ef1db6ce95;p=strace Fix dumping of recvmsg syscall in case of short read * defs.h (dumpiov_in_msghdr): Add unsigned long argument. * net.c (dumpiov_in_msghdr): Add data_size argument. Call dumpiov_upto instead of dumpiov, pass data_size to dumpiov_upto. * syscall.c (dumpio): Pass data size limit to dumpiov_in_msghdr. * NEWS: Mention this fix. * tests/recvmsg.c: New file. * tests/recvmsg.test: New test. * tests/Makefile.am (check_PROGRAMS): Add recvmsg. (TESTS): Add recvmsg.test. * tests/.gitignore: Add recvmsg. --- diff --git a/NEWS b/NEWS index 8b09bdae..d1d5064b 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Noteworthy changes in release ?.?? (????-??-??) * Fixed decoding of syscalls unknown to the kernel on s390/s390x. (addresses Debian bug #485979 and Fedora bug #1298294). * Fixed decoding and dumping of readv syscall in case of short read. + * Fixed dumping of recvmsg syscall in case of short read. Noteworthy changes in release 4.11 (2015-12-21) =============================================== diff --git a/defs.h b/defs.h index 47ca0c05..6b4f2ab6 100644 --- a/defs.h +++ b/defs.h @@ -563,7 +563,7 @@ extern int printflags(const struct xlat *, int, const char *); extern const char *sprintflags(const char *, const struct xlat *, int); extern const char *sprintmode(int); extern const char *sprinttime(time_t); -extern void dumpiov_in_msghdr(struct tcb *, long); +extern void dumpiov_in_msghdr(struct tcb *, long, unsigned long); extern void dumpiov_in_mmsghdr(struct tcb *, long); extern void dumpiov_upto(struct tcb *, int, long, unsigned long); #define dumpiov(tcp, len, addr) \ diff --git a/net.c b/net.c index 4d2f837f..bd3cb15b 100644 --- a/net.c +++ b/net.c @@ -706,12 +706,12 @@ printmsghdr(struct tcb *tcp, long addr, unsigned long data_size) } void -dumpiov_in_msghdr(struct tcb *tcp, long addr) +dumpiov_in_msghdr(struct tcb *tcp, long addr, unsigned long data_size) { struct msghdr msg; if (extractmsghdr(tcp, addr, &msg)) - dumpiov(tcp, msg.msg_iovlen, (long)msg.msg_iov); + dumpiov_upto(tcp, msg.msg_iovlen, (long)msg.msg_iov, data_size); } static void diff --git a/syscall.c b/syscall.c index 5f7b0edc..9729fe57 100644 --- a/syscall.c +++ b/syscall.c @@ -691,7 +691,7 @@ dumpio(struct tcb *tcp) tcp->u_rval); return; case SEN_recvmsg: - dumpiov_in_msghdr(tcp, tcp->u_arg[1]); + dumpiov_in_msghdr(tcp, tcp->u_arg[1], tcp->u_rval); return; case SEN_recvmmsg: dumpiov_in_mmsghdr(tcp, tcp->u_arg[1]); @@ -710,7 +710,8 @@ dumpio(struct tcb *tcp) dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]); break; case SEN_sendmsg: - dumpiov_in_msghdr(tcp, tcp->u_arg[1]); + dumpiov_in_msghdr(tcp, tcp->u_arg[1], + (unsigned long) -1L); break; case SEN_sendmmsg: dumpiov_in_mmsghdr(tcp, tcp->u_arg[1]); diff --git a/tests/.gitignore b/tests/.gitignore index 6b62117e..34e8c2a1 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -68,6 +68,7 @@ readdir readlink readlinkat readv +recvmsg restart_syscall rt_sigqueueinfo sched_xetaffinity diff --git a/tests/Makefile.am b/tests/Makefile.am index d683a6bc..8a918712 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -114,6 +114,7 @@ check_PROGRAMS = \ readlink \ readlinkat \ readv \ + recvmsg \ restart_syscall \ rt_sigqueueinfo \ sched_xetaffinity \ @@ -251,6 +252,7 @@ TESTS = \ readlink.test \ readlinkat.test \ readv.test \ + recvmsg.test \ rt_sigqueueinfo.test \ sched_xetaffinity.test \ sched_xetattr.test \ diff --git a/tests/recvmsg.c b/tests/recvmsg.c new file mode 100644 index 00000000..f0f8fa33 --- /dev/null +++ b/tests/recvmsg.c @@ -0,0 +1,155 @@ +/* + * Check decoding of recvmsg and sendmsg syscalls. + * + * Copyright (c) 2016 Dmitry V. Levin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "tests.h" + +#include +#include +#include +#include +#include + +int +main(void) +{ + tprintf("%s", ""); + + int fds[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + perror_msg_and_skip("socketpair"); + assert(0 == fds[0]); + assert(1 == fds[1]); + + static const char w0_c[] = "012"; + const char *w0_d = hexdump_strdup(w0_c); + void *w0 = tail_memdup(w0_c, LENGTH_OF(w0_c)); + + static const char w1_c[] = "34567"; + const char *w1_d = hexdump_strdup(w1_c); + void *w1 = tail_memdup(w1_c, LENGTH_OF(w1_c)); + + static const char w2_c[] = "89abcde"; + const char *w2_d = hexdump_strdup(w2_c); + void *w2 = tail_memdup(w2_c, LENGTH_OF(w2_c)); + + static const char r0_c[] = "01234567"; + const char *r0_d = hexdump_strdup(r0_c); + static const char r1_c[] = "89abcde"; + const char *r1_d = hexdump_strdup(r1_c); + + const struct iovec w_iov_[] = { + { + .iov_base = w0, + .iov_len = LENGTH_OF(w0_c) + }, { + .iov_base = w1, + .iov_len = LENGTH_OF(w1_c) + }, { + .iov_base = w2, + .iov_len = LENGTH_OF(w2_c) + } + }; + struct iovec *w_iov = tail_memdup(w_iov_, sizeof(w_iov_)); + const unsigned int w_len = + LENGTH_OF(w0_c) + LENGTH_OF(w1_c) + LENGTH_OF(w2_c); + + const struct msghdr w_mh_ = { + .msg_iov = w_iov, + .msg_iovlen = ARRAY_SIZE(w_iov_) + }; + const struct msghdr *w_mh = tail_memdup(&w_mh_, sizeof(w_mh_)); + + assert(sendmsg(1, w_mh, 0) == (int) w_len); + close(1); + tprintf("sendmsg(1, {msg_name(0)=NULL, msg_iov(%u)=" + "[{\"%s\", %u}, {\"%s\", %u}, {\"%s\", %u}]" + ", msg_controllen=0, msg_flags=0}, 0) = %u\n" + " * %u bytes in buffer 0\n" + " | 00000 %-49s %-16s |\n" + " * %u bytes in buffer 1\n" + " | 00000 %-49s %-16s |\n" + " * %u bytes in buffer 2\n" + " | 00000 %-49s %-16s |\n", + ARRAY_SIZE(w_iov_), w0_c, LENGTH_OF(w0_c), + w1_c, LENGTH_OF(w1_c), w2_c, LENGTH_OF(w2_c), w_len, + LENGTH_OF(w0_c), w0_d, w0_c, LENGTH_OF(w1_c), w1_d, w1_c, + LENGTH_OF(w2_c), w2_d, w2_c); + + const unsigned int r_len = (w_len + 1) / 2; + void *r0 = tail_alloc(r_len); + const struct iovec r0_iov_[] = { + { + .iov_base = r0, + .iov_len = r_len + } + }; + struct iovec *r_iov = tail_memdup(r0_iov_, sizeof(r0_iov_)); + + const struct msghdr r_mh_ = { + .msg_iov = r_iov, + .msg_iovlen = ARRAY_SIZE(r0_iov_) + }; + struct msghdr *r_mh = tail_memdup(&r_mh_, sizeof(r_mh_)); + + assert(recvmsg(0, r_mh, 0) == (int) r_len); + tprintf("recvmsg(0, {msg_name(0)=NULL, msg_iov(%u)=" + "[{\"%s\", %u}], msg_controllen=0, msg_flags=0}, 0) = %u\n" + " * %u bytes in buffer 0\n" + " | 00000 %-49s %-16s |\n", + ARRAY_SIZE(r0_iov_), r0_c, r_len, r_len, r_len, r0_d, r0_c); + + void *r1 = tail_alloc(r_len); + void *r2 = tail_alloc(w_len); + const struct iovec r1_iov_[] = { + { + .iov_base = r1, + .iov_len = r_len + }, + { + .iov_base = r2, + .iov_len = w_len + } + }; + r_iov = tail_memdup(r1_iov_, sizeof(r1_iov_)); + r_mh->msg_iov = r_iov; + r_mh->msg_iovlen = ARRAY_SIZE(r1_iov_); + + assert(recvmsg(0, r_mh, 0) == (int) w_len - r_len); + tprintf("recvmsg(0, {msg_name(0)=NULL, msg_iov(%u)=" + "[{\"%s\", %u}, {\"\", %u}], msg_controllen=0" + ", msg_flags=0}, 0) = %u\n" + " * %u bytes in buffer 0\n" + " | 00000 %-49s %-16s |\n", + ARRAY_SIZE(r1_iov_), r1_c, r_len, w_len, w_len - r_len, + w_len - r_len, r1_d, r1_c); + close(0); + + tprintf("+++ exited with 0 +++\n"); + return 0; +} diff --git a/tests/recvmsg.test b/tests/recvmsg.test new file mode 100755 index 00000000..cf1104a6 --- /dev/null +++ b/tests/recvmsg.test @@ -0,0 +1,13 @@ +#!/bin/sh + +# Check decoding of recvmsg and sendmsg syscalls. + +. "${srcdir=.}/init.sh" + +run_prog > /dev/null +OUT="$LOG.out" +run_strace -eread=0 -ewrite=1 -erecvmsg,sendmsg $args > "$OUT" +match_diff "$LOG" "$OUT" +rm -f "$OUT" + +exit 0