Skip to content

Commit 93c9d1c

Browse files
committed
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.
1 parent 05a0af6 commit 93c9d1c

File tree

8 files changed

+178
-5
lines changed

8 files changed

+178
-5
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Noteworthy changes in release ?.?? (????-??-??)
1414
* Fixed decoding of syscalls unknown to the kernel on s390/s390x.
1515
(addresses Debian bug #485979 and Fedora bug #1298294).
1616
* Fixed decoding and dumping of readv syscall in case of short read.
17+
* Fixed dumping of recvmsg syscall in case of short read.
1718

1819
Noteworthy changes in release 4.11 (2015-12-21)
1920
===============================================

defs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ extern int printflags(const struct xlat *, int, const char *);
563563
extern const char *sprintflags(const char *, const struct xlat *, int);
564564
extern const char *sprintmode(int);
565565
extern const char *sprinttime(time_t);
566-
extern void dumpiov_in_msghdr(struct tcb *, long);
566+
extern void dumpiov_in_msghdr(struct tcb *, long, unsigned long);
567567
extern void dumpiov_in_mmsghdr(struct tcb *, long);
568568
extern void dumpiov_upto(struct tcb *, int, long, unsigned long);
569569
#define dumpiov(tcp, len, addr) \

net.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -706,12 +706,12 @@ printmsghdr(struct tcb *tcp, long addr, unsigned long data_size)
706706
}
707707

708708
void
709-
dumpiov_in_msghdr(struct tcb *tcp, long addr)
709+
dumpiov_in_msghdr(struct tcb *tcp, long addr, unsigned long data_size)
710710
{
711711
struct msghdr msg;
712712

713713
if (extractmsghdr(tcp, addr, &msg))
714-
dumpiov(tcp, msg.msg_iovlen, (long)msg.msg_iov);
714+
dumpiov_upto(tcp, msg.msg_iovlen, (long)msg.msg_iov, data_size);
715715
}
716716

717717
static void

syscall.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,7 @@ dumpio(struct tcb *tcp)
691691
tcp->u_rval);
692692
return;
693693
case SEN_recvmsg:
694-
dumpiov_in_msghdr(tcp, tcp->u_arg[1]);
694+
dumpiov_in_msghdr(tcp, tcp->u_arg[1], tcp->u_rval);
695695
return;
696696
case SEN_recvmmsg:
697697
dumpiov_in_mmsghdr(tcp, tcp->u_arg[1]);
@@ -710,7 +710,8 @@ dumpio(struct tcb *tcp)
710710
dumpiov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
711711
break;
712712
case SEN_sendmsg:
713-
dumpiov_in_msghdr(tcp, tcp->u_arg[1]);
713+
dumpiov_in_msghdr(tcp, tcp->u_arg[1],
714+
(unsigned long) -1L);
714715
break;
715716
case SEN_sendmmsg:
716717
dumpiov_in_mmsghdr(tcp, tcp->u_arg[1]);

tests/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ readdir
6868
readlink
6969
readlinkat
7070
readv
71+
recvmsg
7172
restart_syscall
7273
rt_sigqueueinfo
7374
sched_xetaffinity

tests/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ check_PROGRAMS = \
114114
readlink \
115115
readlinkat \
116116
readv \
117+
recvmsg \
117118
restart_syscall \
118119
rt_sigqueueinfo \
119120
sched_xetaffinity \
@@ -251,6 +252,7 @@ TESTS = \
251252
readlink.test \
252253
readlinkat.test \
253254
readv.test \
255+
recvmsg.test \
254256
rt_sigqueueinfo.test \
255257
sched_xetaffinity.test \
256258
sched_xetattr.test \

tests/recvmsg.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
/*
2+
* Check decoding of recvmsg and sendmsg syscalls.
3+
*
4+
* Copyright (c) 2016 Dmitry V. Levin <[email protected]>
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions
9+
* are met:
10+
* 1. Redistributions of source code must retain the above copyright
11+
* notice, this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright
13+
* notice, this list of conditions and the following disclaimer in the
14+
* documentation and/or other materials provided with the distribution.
15+
* 3. The name of the author may not be used to endorse or promote products
16+
* derived from this software without specific prior written permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19+
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21+
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
*/
29+
30+
#include "tests.h"
31+
32+
#include <assert.h>
33+
#include <stdio.h>
34+
#include <unistd.h>
35+
#include <sys/socket.h>
36+
#include <sys/uio.h>
37+
38+
int
39+
main(void)
40+
{
41+
tprintf("%s", "");
42+
43+
int fds[2];
44+
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
45+
perror_msg_and_skip("socketpair");
46+
assert(0 == fds[0]);
47+
assert(1 == fds[1]);
48+
49+
static const char w0_c[] = "012";
50+
const char *w0_d = hexdump_strdup(w0_c);
51+
void *w0 = tail_memdup(w0_c, LENGTH_OF(w0_c));
52+
53+
static const char w1_c[] = "34567";
54+
const char *w1_d = hexdump_strdup(w1_c);
55+
void *w1 = tail_memdup(w1_c, LENGTH_OF(w1_c));
56+
57+
static const char w2_c[] = "89abcde";
58+
const char *w2_d = hexdump_strdup(w2_c);
59+
void *w2 = tail_memdup(w2_c, LENGTH_OF(w2_c));
60+
61+
static const char r0_c[] = "01234567";
62+
const char *r0_d = hexdump_strdup(r0_c);
63+
static const char r1_c[] = "89abcde";
64+
const char *r1_d = hexdump_strdup(r1_c);
65+
66+
const struct iovec w_iov_[] = {
67+
{
68+
.iov_base = w0,
69+
.iov_len = LENGTH_OF(w0_c)
70+
}, {
71+
.iov_base = w1,
72+
.iov_len = LENGTH_OF(w1_c)
73+
}, {
74+
.iov_base = w2,
75+
.iov_len = LENGTH_OF(w2_c)
76+
}
77+
};
78+
struct iovec *w_iov = tail_memdup(w_iov_, sizeof(w_iov_));
79+
const unsigned int w_len =
80+
LENGTH_OF(w0_c) + LENGTH_OF(w1_c) + LENGTH_OF(w2_c);
81+
82+
const struct msghdr w_mh_ = {
83+
.msg_iov = w_iov,
84+
.msg_iovlen = ARRAY_SIZE(w_iov_)
85+
};
86+
const struct msghdr *w_mh = tail_memdup(&w_mh_, sizeof(w_mh_));
87+
88+
assert(sendmsg(1, w_mh, 0) == (int) w_len);
89+
close(1);
90+
tprintf("sendmsg(1, {msg_name(0)=NULL, msg_iov(%u)="
91+
"[{\"%s\", %u}, {\"%s\", %u}, {\"%s\", %u}]"
92+
", msg_controllen=0, msg_flags=0}, 0) = %u\n"
93+
" * %u bytes in buffer 0\n"
94+
" | 00000 %-49s %-16s |\n"
95+
" * %u bytes in buffer 1\n"
96+
" | 00000 %-49s %-16s |\n"
97+
" * %u bytes in buffer 2\n"
98+
" | 00000 %-49s %-16s |\n",
99+
ARRAY_SIZE(w_iov_), w0_c, LENGTH_OF(w0_c),
100+
w1_c, LENGTH_OF(w1_c), w2_c, LENGTH_OF(w2_c), w_len,
101+
LENGTH_OF(w0_c), w0_d, w0_c, LENGTH_OF(w1_c), w1_d, w1_c,
102+
LENGTH_OF(w2_c), w2_d, w2_c);
103+
104+
const unsigned int r_len = (w_len + 1) / 2;
105+
void *r0 = tail_alloc(r_len);
106+
const struct iovec r0_iov_[] = {
107+
{
108+
.iov_base = r0,
109+
.iov_len = r_len
110+
}
111+
};
112+
struct iovec *r_iov = tail_memdup(r0_iov_, sizeof(r0_iov_));
113+
114+
const struct msghdr r_mh_ = {
115+
.msg_iov = r_iov,
116+
.msg_iovlen = ARRAY_SIZE(r0_iov_)
117+
};
118+
struct msghdr *r_mh = tail_memdup(&r_mh_, sizeof(r_mh_));
119+
120+
assert(recvmsg(0, r_mh, 0) == (int) r_len);
121+
tprintf("recvmsg(0, {msg_name(0)=NULL, msg_iov(%u)="
122+
"[{\"%s\", %u}], msg_controllen=0, msg_flags=0}, 0) = %u\n"
123+
" * %u bytes in buffer 0\n"
124+
" | 00000 %-49s %-16s |\n",
125+
ARRAY_SIZE(r0_iov_), r0_c, r_len, r_len, r_len, r0_d, r0_c);
126+
127+
void *r1 = tail_alloc(r_len);
128+
void *r2 = tail_alloc(w_len);
129+
const struct iovec r1_iov_[] = {
130+
{
131+
.iov_base = r1,
132+
.iov_len = r_len
133+
},
134+
{
135+
.iov_base = r2,
136+
.iov_len = w_len
137+
}
138+
};
139+
r_iov = tail_memdup(r1_iov_, sizeof(r1_iov_));
140+
r_mh->msg_iov = r_iov;
141+
r_mh->msg_iovlen = ARRAY_SIZE(r1_iov_);
142+
143+
assert(recvmsg(0, r_mh, 0) == (int) w_len - r_len);
144+
tprintf("recvmsg(0, {msg_name(0)=NULL, msg_iov(%u)="
145+
"[{\"%s\", %u}, {\"\", %u}], msg_controllen=0"
146+
", msg_flags=0}, 0) = %u\n"
147+
" * %u bytes in buffer 0\n"
148+
" | 00000 %-49s %-16s |\n",
149+
ARRAY_SIZE(r1_iov_), r1_c, r_len, w_len, w_len - r_len,
150+
w_len - r_len, r1_d, r1_c);
151+
close(0);
152+
153+
tprintf("+++ exited with 0 +++\n");
154+
return 0;
155+
}

tests/recvmsg.test

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/sh
2+
3+
# Check decoding of recvmsg and sendmsg syscalls.
4+
5+
. "${srcdir=.}/init.sh"
6+
7+
run_prog > /dev/null
8+
OUT="$LOG.out"
9+
run_strace -eread=0 -ewrite=1 -erecvmsg,sendmsg $args > "$OUT"
10+
match_diff "$LOG" "$OUT"
11+
rm -f "$OUT"
12+
13+
exit 0

0 commit comments

Comments
 (0)