]> granicus.if.org Git - strace/blob - mmsghdr.c
Fix race condition in decoding timeout argument of recvmmsg syscall
[strace] / mmsghdr.c
1 /*
2  * Copyright (c) 2010 Andreas Schwab <schwab@linux-m68k.org>
3  * Copyright (c) 2012-2013 Denys Vlasenko <vda.linux@googlemail.com>
4  * Copyright (c) 2014 Masatake YAMATO <yamato@redhat.com>
5  * Copyright (c) 2010-2016 Dmitry V. Levin <ldv@altlinux.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "defs.h"
32 #include "msghdr.h"
33
34 static int
35 decode_mmsghdr(struct tcb *tcp, const int *const p_user_msg_namelen,
36                const long addr, const bool use_msg_len)
37 {
38         struct mmsghdr mmsg;
39         int fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg);
40
41         if (fetched) {
42                 tprints("{msg_hdr=");
43                 print_struct_msghdr(tcp, &mmsg.msg_hdr, p_user_msg_namelen,
44                                     use_msg_len ? mmsg.msg_len : -1UL);
45                 tprintf(", msg_len=%u}", mmsg.msg_len);
46         } else {
47                 printaddr(addr);
48         }
49
50         return fetched;
51 }
52
53 static void
54 decode_mmsgvec(struct tcb *tcp, unsigned long addr, unsigned int len,
55                bool use_msg_len)
56 {
57         if (syserror(tcp)) {
58                 printaddr(addr);
59         } else {
60                 unsigned int i, fetched;
61
62                 tprints("[");
63                 for (i = 0; i < len; ++i, addr += fetched) {
64                         if (i)
65                                 tprints(", ");
66                         fetched = decode_mmsghdr(tcp, 0, addr, use_msg_len);
67                         if (!fetched)
68                                 break;
69                 }
70                 tprints("]");
71         }
72 }
73
74 void
75 dumpiov_in_mmsghdr(struct tcb *tcp, long addr)
76 {
77         unsigned int len = tcp->u_rval;
78         unsigned int i, fetched;
79         struct mmsghdr mmsg;
80
81         for (i = 0; i < len; ++i, addr += fetched) {
82                 fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg);
83                 if (!fetched)
84                         break;
85                 tprintf(" = %lu buffers in vector %u\n",
86                         (unsigned long) mmsg.msg_hdr.msg_iovlen, i);
87                 dumpiov_upto(tcp, mmsg.msg_hdr.msg_iovlen,
88                         (long) mmsg.msg_hdr.msg_iov, mmsg.msg_len);
89         }
90 }
91
92 SYS_FUNC(sendmmsg)
93 {
94         if (entering(tcp)) {
95                 /* sockfd */
96                 printfd(tcp, tcp->u_arg[0]);
97                 tprints(", ");
98                 if (!verbose(tcp)) {
99                         printaddr(tcp->u_arg[1]);
100                         /* vlen */
101                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
102                         /* flags */
103                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
104                         return RVAL_DECODED;
105                 }
106         } else {
107                 decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval, false);
108                 /* vlen */
109                 tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
110                 /* flags */
111                 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
112         }
113         return 0;
114 }
115
116 SYS_FUNC(recvmmsg)
117 {
118         if (entering(tcp)) {
119                 printfd(tcp, tcp->u_arg[0]);
120                 tprints(", ");
121                 if (verbose(tcp)) {
122                         char *sts = xstrdup(sprint_timespec(tcp, tcp->u_arg[4]));
123                         set_tcb_priv_data(tcp, sts, free);
124                 } else {
125                         printaddr(tcp->u_arg[1]);
126                         /* vlen */
127                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
128                         /* flags */
129                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
130                         tprints(", ");
131                         print_timespec(tcp, tcp->u_arg[4]);
132                 }
133                 return 0;
134         } else {
135                 if (verbose(tcp)) {
136                         decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval, true);
137                         /* vlen */
138                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
139                         /* flags */
140                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
141                         tprints(", ");
142                         /* timeout on entrance */
143                         tprints(get_tcb_priv_data(tcp));
144                 }
145                 if (syserror(tcp))
146                         return 0;
147                 if (tcp->u_rval == 0) {
148                         tcp->auxstr = "Timeout";
149                         return RVAL_STR;
150                 }
151                 if (!verbose(tcp))
152                         return 0;
153                 /* timeout on exit */
154                 static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
155                 snprintf(str, sizeof(str), "left %s",
156                          sprint_timespec(tcp, tcp->u_arg[4]));
157                 tcp->auxstr = str;
158                 return RVAL_STR;
159         }
160 }