Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 : : * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 : : * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 : : * Copyright (c) 1996-2000 Wichert Akkerman <wichert@cistron.nl>
6 : : * Copyright (c) 2005-2016 Dmitry V. Levin <ldv@altlinux.org>
7 : : * All rights reserved.
8 : : *
9 : : * Redistribution and use in source and binary forms, with or without
10 : : * modification, are permitted provided that the following conditions
11 : : * are met:
12 : : * 1. Redistributions of source code must retain the above copyright
13 : : * notice, this list of conditions and the following disclaimer.
14 : : * 2. Redistributions in binary form must reproduce the above copyright
15 : : * notice, this list of conditions and the following disclaimer in the
16 : : * documentation and/or other materials provided with the distribution.
17 : : * 3. The name of the author may not be used to endorse or promote products
18 : : * derived from this software without specific prior written permission.
19 : : *
20 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : : */
31 : :
32 : : #include "defs.h"
33 : : #include "print_fields.h"
34 : : #include "msghdr.h"
35 : : #include <limits.h>
36 : : #include <arpa/inet.h>
37 : : #include <netinet/in.h>
38 : :
39 : : #include "xlat/msg_flags.h"
40 : : #include "xlat/scmvals.h"
41 : : #include "xlat/ip_cmsg_types.h"
42 : :
43 : : #ifndef current_wordsize
44 : : struct cmsghdr32 {
45 : : uint32_t cmsg_len;
46 : : int cmsg_level;
47 : : int cmsg_type;
48 : : };
49 : : #endif
50 : :
51 : : typedef union {
52 : : char *ptr;
53 : : struct cmsghdr *cmsg;
54 : : #ifndef current_wordsize
55 : : struct cmsghdr32 *cmsg32;
56 : : #endif
57 : : } union_cmsghdr;
58 : :
59 : : static void
60 : 78024 : print_scm_rights(struct tcb *tcp, const void *cmsg_data,
61 : : const unsigned int data_len)
62 : : {
63 : 78024 : const int *fds = cmsg_data;
64 : 78024 : const unsigned int nfds = data_len / sizeof(*fds);
65 : : unsigned int i;
66 : :
67 : 78024 : tprints("[");
68 : :
69 [ + + ]: 284499 : for (i = 0; i < nfds; ++i) {
70 [ + + ]: 206479 : if (i)
71 : 128455 : tprints(", ");
72 [ + + ][ + + ]: 206479 : if (abbrev(tcp) && i >= max_strlen) {
73 : 4 : tprints("...");
74 : 4 : break;
75 : : }
76 : 206475 : printfd(tcp, fds[i]);
77 : : }
78 : :
79 : 78024 : tprints("]");
80 : 78024 : }
81 : :
82 : : static void
83 : 2 : print_scm_creds(struct tcb *tcp, const void *cmsg_data,
84 : : const unsigned int data_len)
85 : : {
86 : 2 : const struct ucred *uc = cmsg_data;
87 : :
88 : 2 : PRINT_FIELD_U("{", *uc, pid);
89 [ - + ]: 2 : PRINT_FIELD_UID(", ", *uc, uid);
90 [ - + ]: 2 : PRINT_FIELD_UID(", ", *uc, gid);
91 : 2 : tprints("}");
92 : 2 : }
93 : :
94 : : static void
95 : 1524 : print_scm_security(struct tcb *tcp, const void *cmsg_data,
96 : : const unsigned int data_len)
97 : : {
98 : 1524 : print_quoted_string(cmsg_data, data_len, 0);
99 : 1524 : }
100 : :
101 : : static void
102 : 8 : print_scm_timestamp(struct tcb *tcp, const void *cmsg_data,
103 : : const unsigned int data_len)
104 : : {
105 : 8 : print_struct_timeval_data_size(cmsg_data, data_len);
106 : 8 : }
107 : :
108 : : static void
109 : 8 : print_scm_timestampns(struct tcb *tcp, const void *cmsg_data,
110 : : const unsigned int data_len)
111 : : {
112 : 8 : print_struct_timespec_data_size(cmsg_data, data_len);
113 : 8 : }
114 : :
115 : : static void
116 : 8 : print_scm_timestamping(struct tcb *tcp, const void *cmsg_data,
117 : : const unsigned int data_len)
118 : : {
119 : 8 : print_struct_timespec_array_data_size(cmsg_data, 3, data_len);
120 : 8 : }
121 : :
122 : : static void
123 : 6 : print_cmsg_ip_pktinfo(struct tcb *tcp, const void *cmsg_data,
124 : : const unsigned int data_len)
125 : : {
126 : 6 : const struct in_pktinfo *info = cmsg_data;
127 : :
128 : 6 : PRINT_FIELD_IFINDEX("{", *info, ipi_ifindex);
129 : 6 : PRINT_FIELD_INET4_ADDR(", ", *info, ipi_spec_dst);
130 : 6 : PRINT_FIELD_INET4_ADDR(", ", *info, ipi_addr);
131 : 6 : tprints("}");
132 : 6 : }
133 : :
134 : : static void
135 : 6 : print_cmsg_uint(struct tcb *tcp, const void *cmsg_data,
136 : : const unsigned int data_len)
137 : : {
138 : 6 : const unsigned int *p = cmsg_data;
139 : :
140 : 6 : tprintf("[%u]", *p);
141 : 6 : }
142 : :
143 : : static void
144 : 6 : print_cmsg_uint8_t(struct tcb *tcp, const void *cmsg_data,
145 : : const unsigned int data_len)
146 : : {
147 : 6 : const uint8_t *p = cmsg_data;
148 : :
149 : 6 : tprintf("[%#x]", *p);
150 : 6 : }
151 : :
152 : : static void
153 : 46 : print_cmsg_ip_opts(struct tcb *tcp, const void *cmsg_data,
154 : : const unsigned int data_len)
155 : : {
156 : 46 : const unsigned char *opts = cmsg_data;
157 : : unsigned int i;
158 : :
159 : 46 : tprints("[");
160 [ + + ]: 580 : for (i = 0; i < data_len; ++i) {
161 [ + + ]: 536 : if (i)
162 : 490 : tprints(", ");
163 [ + + ][ + + ]: 536 : if (abbrev(tcp) && i >= max_strlen) {
164 : 2 : tprints("...");
165 : 2 : break;
166 : : }
167 : 534 : tprintf("0x%02x", opts[i]);
168 : : }
169 : 46 : tprints("]");
170 : 46 : }
171 : :
172 : : struct sock_ee {
173 : : uint32_t ee_errno;
174 : : uint8_t ee_origin;
175 : : uint8_t ee_type;
176 : : uint8_t ee_code;
177 : : uint8_t ee_pad;
178 : : uint32_t ee_info;
179 : : uint32_t ee_data;
180 : : struct sockaddr_in offender;
181 : : };
182 : :
183 : : static void
184 : 0 : print_cmsg_ip_recverr(struct tcb *tcp, const void *cmsg_data,
185 : : const unsigned int data_len)
186 : : {
187 : 0 : const struct sock_ee *const err = cmsg_data;
188 : :
189 : 0 : PRINT_FIELD_U("{", *err, ee_errno);
190 : 0 : PRINT_FIELD_U(", ", *err, ee_origin);
191 : 0 : PRINT_FIELD_U(", ", *err, ee_type);
192 : 0 : PRINT_FIELD_U(", ", *err, ee_code);
193 : 0 : PRINT_FIELD_U(", ", *err, ee_info);
194 : 0 : PRINT_FIELD_U(", ", *err, ee_data);
195 : 0 : PRINT_FIELD_SOCKADDR(", ", *err, offender);
196 : 0 : tprints("}");
197 : 0 : }
198 : :
199 : : static void
200 : 4 : print_cmsg_ip_origdstaddr(struct tcb *tcp, const void *cmsg_data,
201 : : const unsigned int data_len)
202 : : {
203 : 4 : const unsigned int addr_len =
204 : : data_len > sizeof(struct sockaddr_storage)
205 : : ? sizeof(struct sockaddr_storage) : data_len;
206 : :
207 : 4 : print_sockaddr(cmsg_data, addr_len);
208 : 4 : }
209 : :
210 : : typedef void (* const cmsg_printer)(struct tcb *, const void *, unsigned int);
211 : :
212 : : static const struct {
213 : : const cmsg_printer printer;
214 : : const unsigned int min_len;
215 : : } cmsg_socket_printers[] = {
216 : : [SCM_RIGHTS] = { print_scm_rights, sizeof(int) },
217 : : [SCM_CREDENTIALS] = { print_scm_creds, sizeof(struct ucred) },
218 : : [SCM_SECURITY] = { print_scm_security, 1 },
219 : : [SCM_TIMESTAMP] = { print_scm_timestamp, 1 },
220 : : [SCM_TIMESTAMPNS] = { print_scm_timestampns, 1 },
221 : : [SCM_TIMESTAMPING] = { print_scm_timestamping, 1 }
222 : : }, cmsg_ip_printers[] = {
223 : : [IP_PKTINFO] = { print_cmsg_ip_pktinfo, sizeof(struct in_pktinfo) },
224 : : [IP_TTL] = { print_cmsg_uint, sizeof(unsigned int) },
225 : : [IP_TOS] = { print_cmsg_uint8_t, 1 },
226 : : [IP_RECVOPTS] = { print_cmsg_ip_opts, 1 },
227 : : [IP_RETOPTS] = { print_cmsg_ip_opts, 1 },
228 : : [IP_RECVERR] = { print_cmsg_ip_recverr, sizeof(struct sock_ee) },
229 : : [IP_ORIGDSTADDR] = { print_cmsg_ip_origdstaddr, sizeof(struct sockaddr_in) },
230 : : [IP_CHECKSUM] = { print_cmsg_uint, sizeof(unsigned int) },
231 : : [SCM_SECURITY] = { print_scm_security, 1 }
232 : : };
233 : :
234 : : static void
235 : 121208 : print_cmsg_type_data(struct tcb *tcp, const int cmsg_level, const int cmsg_type,
236 : : const void *cmsg_data, const unsigned int data_len)
237 : : {
238 : 121208 : const unsigned int utype = cmsg_type;
239 [ + + + ]: 121208 : switch (cmsg_level) {
240 : : case SOL_SOCKET:
241 : 121126 : printxval(scmvals, cmsg_type, "SCM_???");
242 [ + + ]: 121126 : if (utype < ARRAY_SIZE(cmsg_socket_printers)
243 [ + - ]: 121122 : && cmsg_socket_printers[utype].printer
244 [ + + ]: 121122 : && data_len >= cmsg_socket_printers[utype].min_len) {
245 : 79574 : tprints(", cmsg_data=");
246 : 79574 : cmsg_socket_printers[utype].printer(tcp, cmsg_data, data_len);
247 : : }
248 : : break;
249 : : case SOL_IP:
250 : 78 : printxval(ip_cmsg_types, cmsg_type, "IP_???");
251 [ + + ]: 78 : if (utype < ARRAY_SIZE(cmsg_ip_printers)
252 [ + - ]: 74 : && cmsg_ip_printers[utype].printer
253 [ + + ]: 74 : && data_len >= cmsg_ip_printers[utype].min_len) {
254 : 68 : tprints(", cmsg_data=");
255 : 68 : cmsg_ip_printers[utype].printer(tcp, cmsg_data, data_len);
256 : : }
257 : : break;
258 : : default:
259 : 4 : tprintf("%#x", cmsg_type);
260 : : }
261 : 121208 : }
262 : :
263 : : static unsigned int
264 : 65014 : get_optmem_max(void)
265 : : {
266 : : static int optmem_max;
267 : :
268 [ + + ]: 65014 : if (!optmem_max) {
269 [ + - ]: 8 : if (read_int_from_file("/proc/sys/net/core/optmem_max",
270 [ - + ]: 8 : &optmem_max) || optmem_max <= 0) {
271 : 0 : optmem_max = sizeof(long long) * (2 * IOV_MAX + 512);
272 : : } else {
273 : 8 : optmem_max = (optmem_max + sizeof(long long) - 1)
274 : : & ~(sizeof(long long) - 1);
275 : : }
276 : : }
277 : :
278 : 65014 : return optmem_max;
279 : : }
280 : :
281 : : static void
282 : 69944 : decode_msg_control(struct tcb *const tcp, const kernel_ulong_t addr,
283 : : const kernel_ulong_t in_control_len)
284 : : {
285 [ + + ]: 69944 : if (!in_control_len)
286 : : return;
287 : 65010 : tprints(", msg_control=");
288 : :
289 [ + + ]: 65010 : const unsigned int cmsg_size =
290 : : #ifndef current_wordsize
291 : 65010 : (current_wordsize < sizeof(long)) ? sizeof(struct cmsghdr32) :
292 : : #endif
293 : : sizeof(struct cmsghdr);
294 : :
295 [ + + ]: 65010 : unsigned int control_len = in_control_len > get_optmem_max()
296 : : ? get_optmem_max() : in_control_len;
297 : 65010 : unsigned int buf_len = control_len;
298 [ + + ]: 65010 : char *buf = buf_len < cmsg_size ? NULL : malloc(buf_len);
299 [ + + ][ + + ]: 65010 : if (!buf || umoven(tcp, addr, buf_len, buf) < 0) {
300 : 1172 : printaddr(addr);
301 : 1172 : free(buf);
302 : 1172 : return;
303 : : }
304 : :
305 : 63838 : union_cmsghdr u = { .ptr = buf };
306 : :
307 : 63838 : tprints("[");
308 [ + + ]: 136532 : while (buf_len >= cmsg_size) {
309 : 121208 : const kernel_ulong_t cmsg_len =
310 : : #ifndef current_wordsize
311 [ + + ]: 121208 : (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_len :
312 : : #endif
313 : : u.cmsg->cmsg_len;
314 : 121208 : const int cmsg_level =
315 : : #ifndef current_wordsize
316 [ + + ]: 121208 : (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_level :
317 : : #endif
318 : : u.cmsg->cmsg_level;
319 : 121208 : const int cmsg_type =
320 : : #ifndef current_wordsize
321 [ + + ]: 121208 : (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_type :
322 : : #endif
323 : : u.cmsg->cmsg_type;
324 : :
325 [ + + ]: 121208 : if (u.ptr != buf)
326 : 57370 : tprints(", ");
327 : 121208 : tprintf("{cmsg_len=%" PRI_klu ", cmsg_level=", cmsg_len);
328 : 121208 : printxval(socketlayers, cmsg_level, "SOL_???");
329 : 121208 : tprints(", cmsg_type=");
330 : :
331 : 121208 : kernel_ulong_t len = cmsg_len > buf_len ? buf_len : cmsg_len;
332 : :
333 [ + + ]: 121208 : print_cmsg_type_data(tcp, cmsg_level, cmsg_type,
334 : : (const void *) (u.ptr + cmsg_size),
335 : 121208 : len > cmsg_size ? len - cmsg_size : 0);
336 : 121208 : tprints("}");
337 : :
338 [ + + ]: 121208 : if (len < cmsg_size) {
339 : 16416 : buf_len -= cmsg_size;
340 : 16416 : break;
341 : : }
342 : 209584 : len = (cmsg_len + current_wordsize - 1) &
343 : 104792 : ~((kernel_ulong_t) current_wordsize - 1);
344 [ + + ]: 104792 : if (len >= buf_len) {
345 : : buf_len = 0;
346 : : break;
347 : : }
348 : 72694 : u.ptr += len;
349 : 72694 : buf_len -= len;
350 : : }
351 [ + + ]: 63838 : if (buf_len) {
352 : 30676 : tprints(", ");
353 : 30676 : printaddr(addr + (control_len - buf_len));
354 [ + + ]: 33162 : } else if (control_len < in_control_len) {
355 : 4 : tprints(", ...");
356 : : }
357 : 63838 : tprints("]");
358 : 63838 : free(buf);
359 : : }
360 : :
361 : : void
362 : 69944 : print_struct_msghdr(struct tcb *tcp, const struct msghdr *msg,
363 : : const int *const p_user_msg_namelen,
364 : : const kernel_ulong_t data_size)
365 : : {
366 : 69944 : const int msg_namelen =
367 [ + + ]: 644 : p_user_msg_namelen && (int) msg->msg_namelen > *p_user_msg_namelen
368 [ + + ]: 70444 : ? *p_user_msg_namelen : (int) msg->msg_namelen;
369 : :
370 : 69944 : tprints("{msg_name=");
371 : 69944 : const int family =
372 : 69944 : decode_sockaddr(tcp, ptr_to_kulong(msg->msg_name), msg_namelen);
373 [ + - ]: 69944 : const enum iov_decode decode =
374 : : (family == AF_NETLINK) ? IOV_DECODE_NETLINK : IOV_DECODE_STR;
375 : :
376 : 69944 : tprints(", msg_namelen=");
377 [ + + ][ + + ]: 69944 : if (p_user_msg_namelen && *p_user_msg_namelen != (int) msg->msg_namelen)
378 : 620 : tprintf("%d->", *p_user_msg_namelen);
379 : 69944 : tprintf("%d", msg->msg_namelen);
380 : :
381 : 69944 : tprints(", msg_iov=");
382 : 69944 : tprint_iov_upto(tcp, msg->msg_iovlen,
383 : 69944 : ptr_to_kulong(msg->msg_iov), decode, data_size);
384 : 69944 : PRINT_FIELD_U(", ", *msg, msg_iovlen);
385 : :
386 : 69944 : decode_msg_control(tcp, ptr_to_kulong(msg->msg_control),
387 : : msg->msg_controllen);
388 : 69944 : PRINT_FIELD_U(", ", *msg, msg_controllen);
389 : :
390 : 69944 : PRINT_FIELD_FLAGS(", ", *msg, msg_flags, msg_flags, "MSG_???");
391 : 69944 : tprints("}");
392 : 69944 : }
393 : :
394 : : static bool
395 : 24 : fetch_msghdr_namelen(struct tcb *const tcp, const kernel_ulong_t addr,
396 : : int *const p_msg_namelen)
397 : : {
398 : : struct msghdr msg;
399 : :
400 [ + + ][ + - ]: 24 : if (addr && verbose(tcp) && fetch_struct_msghdr(tcp, addr, &msg)) {
[ + + ]
401 : 20 : *p_msg_namelen = msg.msg_namelen;
402 : 20 : return true;
403 : : } else {
404 : : return false;
405 : : }
406 : : }
407 : :
408 : : static void
409 : 65094 : decode_msghdr(struct tcb *const tcp, const int *const p_user_msg_namelen,
410 : : const kernel_ulong_t addr, const kernel_ulong_t data_size)
411 : : {
412 : : struct msghdr msg;
413 : :
414 [ + + ][ + - ]: 65094 : if (addr && verbose(tcp) && fetch_struct_msghdr(tcp, addr, &msg))
[ + + ]
415 : 65086 : print_struct_msghdr(tcp, &msg, p_user_msg_namelen, data_size);
416 : : else
417 : 8 : printaddr(addr);
418 : 65094 : }
419 : :
420 : : void
421 : 6 : dumpiov_in_msghdr(struct tcb *const tcp, const kernel_ulong_t addr,
422 : : const kernel_ulong_t data_size)
423 : : {
424 : : struct msghdr msg;
425 : :
426 [ + - ]: 6 : if (fetch_struct_msghdr(tcp, addr, &msg)) {
427 : 6 : dumpiov_upto(tcp, msg.msg_iovlen,
428 : 6 : ptr_to_kulong(msg.msg_iov), data_size);
429 : : }
430 : 6 : }
431 : :
432 : 65076 : SYS_FUNC(sendmsg)
433 : : {
434 : 65076 : printfd(tcp, tcp->u_arg[0]);
435 : 65076 : tprints(", ");
436 : 65076 : decode_msghdr(tcp, 0, tcp->u_arg[1], -1);
437 : : /* flags */
438 : 65076 : tprints(", ");
439 : 65076 : printflags(msg_flags, tcp->u_arg[2], "MSG_???");
440 : :
441 : 65076 : return RVAL_DECODED;
442 : : }
443 : :
444 : 44 : SYS_FUNC(recvmsg)
445 : : {
446 : : int msg_namelen;
447 : :
448 [ + + ]: 44 : if (entering(tcp)) {
449 : 24 : printfd(tcp, tcp->u_arg[0]);
450 : 24 : tprints(", ");
451 [ + + ]: 24 : if (fetch_msghdr_namelen(tcp, tcp->u_arg[1], &msg_namelen)) {
452 : 20 : set_tcb_priv_ulong(tcp, msg_namelen);
453 : 20 : return 0;
454 : : }
455 : 4 : printaddr(tcp->u_arg[1]);
456 : : } else {
457 : 20 : msg_namelen = get_tcb_priv_ulong(tcp);
458 : :
459 [ + + ]: 20 : if (syserror(tcp))
460 : 2 : tprintf("{msg_namelen=%d}", msg_namelen);
461 : : else
462 : 18 : decode_msghdr(tcp, &msg_namelen, tcp->u_arg[1],
463 : 18 : tcp->u_rval);
464 : : }
465 : :
466 : : /* flags */
467 : 24 : tprints(", ");
468 : 24 : printflags(msg_flags, tcp->u_arg[2], "MSG_???");
469 : :
470 : 24 : return RVAL_DECODED;
471 : : }
|