]> granicus.if.org Git - strace/blob - msghdr.c
Intorduce PRINT_FIELD_SOCKADDR
[strace] / msghdr.c
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 print_scm_rights(struct tcb *tcp, const void *cmsg_data,
61                  const unsigned int data_len)
62 {
63         const int *fds = cmsg_data;
64         const unsigned int nfds = data_len / sizeof(*fds);
65         unsigned int i;
66
67         tprints("[");
68
69         for (i = 0; i < nfds; ++i) {
70                 if (i)
71                         tprints(", ");
72                 if (abbrev(tcp) && i >= max_strlen) {
73                         tprints("...");
74                         break;
75                 }
76                 printfd(tcp, fds[i]);
77         }
78
79         tprints("]");
80 }
81
82 static void
83 print_scm_creds(struct tcb *tcp, const void *cmsg_data,
84                 const unsigned int data_len)
85 {
86         const struct ucred *uc = cmsg_data;
87
88         tprintf("{pid=%u, uid=%u, gid=%u}",
89                 (unsigned) uc->pid, (unsigned) uc->uid, (unsigned) uc->gid);
90 }
91
92 static void
93 print_scm_security(struct tcb *tcp, const void *cmsg_data,
94                    const unsigned int data_len)
95 {
96         print_quoted_string(cmsg_data, data_len, 0);
97 }
98
99 static void
100 print_scm_timestamp(struct tcb *tcp, const void *cmsg_data,
101                     const unsigned int data_len)
102 {
103         print_struct_timeval_data_size(cmsg_data, data_len);
104 }
105
106 static void
107 print_scm_timestampns(struct tcb *tcp, const void *cmsg_data,
108                       const unsigned int data_len)
109 {
110         print_struct_timespec_data_size(cmsg_data, data_len);
111 }
112
113 static void
114 print_scm_timestamping(struct tcb *tcp, const void *cmsg_data,
115                        const unsigned int data_len)
116 {
117         print_struct_timespec_array_data_size(cmsg_data, 3, data_len);
118 }
119
120 static void
121 print_cmsg_ip_pktinfo(struct tcb *tcp, const void *cmsg_data,
122                       const unsigned int data_len)
123 {
124         const struct in_pktinfo *info = cmsg_data;
125
126         PRINT_FIELD_IFINDEX("{", *info, ipi_ifindex);
127         PRINT_FIELD_INET4_ADDR(", ", *info, ipi_spec_dst);
128         PRINT_FIELD_INET4_ADDR(", ", *info, ipi_addr);
129         tprints("}");
130 }
131
132 static void
133 print_cmsg_uint(struct tcb *tcp, const void *cmsg_data,
134                 const unsigned int data_len)
135 {
136         const unsigned int *p = cmsg_data;
137
138         tprintf("[%u]", *p);
139 }
140
141 static void
142 print_cmsg_uint8_t(struct tcb *tcp, const void *cmsg_data,
143                    const unsigned int data_len)
144 {
145         const uint8_t *p = cmsg_data;
146
147         tprintf("[%#x]", *p);
148 }
149
150 static void
151 print_cmsg_ip_opts(struct tcb *tcp, const void *cmsg_data,
152                    const unsigned int data_len)
153 {
154         const unsigned char *opts = cmsg_data;
155         unsigned int i;
156
157         tprints("[");
158         for (i = 0; i < data_len; ++i) {
159                 if (i)
160                         tprints(", ");
161                 if (abbrev(tcp) && i >= max_strlen) {
162                         tprints("...");
163                         break;
164                 }
165                 tprintf("0x%02x", opts[i]);
166         }
167         tprints("]");
168 }
169
170 struct sock_ee {
171         uint32_t ee_errno;
172         uint8_t  ee_origin;
173         uint8_t  ee_type;
174         uint8_t  ee_code;
175         uint8_t  ee_pad;
176         uint32_t ee_info;
177         uint32_t ee_data;
178         struct sockaddr_in offender;
179 };
180
181 static void
182 print_cmsg_ip_recverr(struct tcb *tcp, const void *cmsg_data,
183                       const unsigned int data_len)
184 {
185         const struct sock_ee *const err = cmsg_data;
186
187         tprintf("{ee_errno=%u, ee_origin=%u, ee_type=%u, ee_code=%u"
188                 ", ee_info=%u, ee_data=%u",
189                 err->ee_errno, err->ee_origin, err->ee_type,
190                 err->ee_code, err->ee_info, err->ee_data);
191         PRINT_FIELD_SOCKADDR(", ", *err, offender);
192         tprints("}");
193 }
194
195 static void
196 print_cmsg_ip_origdstaddr(struct tcb *tcp, const void *cmsg_data,
197                           const unsigned int data_len)
198 {
199         const unsigned int addr_len =
200                 data_len > sizeof(struct sockaddr_storage)
201                 ? sizeof(struct sockaddr_storage) : data_len;
202
203         print_sockaddr(cmsg_data, addr_len);
204 }
205
206 typedef void (* const cmsg_printer)(struct tcb *, const void *, unsigned int);
207
208 static const struct {
209         const cmsg_printer printer;
210         const unsigned int min_len;
211 } cmsg_socket_printers[] = {
212         [SCM_RIGHTS] = { print_scm_rights, sizeof(int) },
213         [SCM_CREDENTIALS] = { print_scm_creds, sizeof(struct ucred) },
214         [SCM_SECURITY] = { print_scm_security, 1 },
215         [SCM_TIMESTAMP] = { print_scm_timestamp, 1 },
216         [SCM_TIMESTAMPNS] = { print_scm_timestampns, 1 },
217         [SCM_TIMESTAMPING] = { print_scm_timestamping, 1 }
218 }, cmsg_ip_printers[] = {
219         [IP_PKTINFO] = { print_cmsg_ip_pktinfo, sizeof(struct in_pktinfo) },
220         [IP_TTL] = { print_cmsg_uint, sizeof(unsigned int) },
221         [IP_TOS] = { print_cmsg_uint8_t, 1 },
222         [IP_RECVOPTS] = { print_cmsg_ip_opts, 1 },
223         [IP_RETOPTS] = { print_cmsg_ip_opts, 1 },
224         [IP_RECVERR] = { print_cmsg_ip_recverr, sizeof(struct sock_ee) },
225         [IP_ORIGDSTADDR] = { print_cmsg_ip_origdstaddr, sizeof(struct sockaddr_in) },
226         [IP_CHECKSUM] = { print_cmsg_uint, sizeof(unsigned int) },
227         [SCM_SECURITY] = { print_scm_security, 1 }
228 };
229
230 static void
231 print_cmsg_type_data(struct tcb *tcp, const int cmsg_level, const int cmsg_type,
232                      const void *cmsg_data, const unsigned int data_len)
233 {
234         const unsigned int utype = cmsg_type;
235         switch (cmsg_level) {
236         case SOL_SOCKET:
237                 printxval(scmvals, cmsg_type, "SCM_???");
238                 if (utype < ARRAY_SIZE(cmsg_socket_printers)
239                     && cmsg_socket_printers[utype].printer
240                     && data_len >= cmsg_socket_printers[utype].min_len) {
241                         tprints(", cmsg_data=");
242                         cmsg_socket_printers[utype].printer(tcp, cmsg_data, data_len);
243                 }
244                 break;
245         case SOL_IP:
246                 printxval(ip_cmsg_types, cmsg_type, "IP_???");
247                 if (utype < ARRAY_SIZE(cmsg_ip_printers)
248                     && cmsg_ip_printers[utype].printer
249                     && data_len >= cmsg_ip_printers[utype].min_len) {
250                         tprints(", cmsg_data=");
251                         cmsg_ip_printers[utype].printer(tcp, cmsg_data, data_len);
252                 }
253                 break;
254         default:
255                 tprintf("%#x", cmsg_type);
256         }
257 }
258
259 static unsigned int
260 get_optmem_max(void)
261 {
262         static int optmem_max;
263
264         if (!optmem_max) {
265                 if (read_int_from_file("/proc/sys/net/core/optmem_max",
266                                        &optmem_max) || optmem_max <= 0) {
267                         optmem_max = sizeof(long long) * (2 * IOV_MAX + 512);
268                 } else {
269                         optmem_max = (optmem_max + sizeof(long long) - 1)
270                                      & ~(sizeof(long long) - 1);
271                 }
272         }
273
274         return optmem_max;
275 }
276
277 static void
278 decode_msg_control(struct tcb *const tcp, const kernel_ulong_t addr,
279                    const kernel_ulong_t in_control_len)
280 {
281         if (!in_control_len)
282                 return;
283         tprints(", msg_control=");
284
285         const unsigned int cmsg_size =
286 #ifndef current_wordsize
287                 (current_wordsize < sizeof(long)) ? sizeof(struct cmsghdr32) :
288 #endif
289                         sizeof(struct cmsghdr);
290
291         unsigned int control_len = in_control_len > get_optmem_max()
292                                    ? get_optmem_max() : in_control_len;
293         unsigned int buf_len = control_len;
294         char *buf = buf_len < cmsg_size ? NULL : malloc(buf_len);
295         if (!buf || umoven(tcp, addr, buf_len, buf) < 0) {
296                 printaddr(addr);
297                 free(buf);
298                 return;
299         }
300
301         union_cmsghdr u = { .ptr = buf };
302
303         tprints("[");
304         while (buf_len >= cmsg_size) {
305                 const kernel_ulong_t cmsg_len =
306 #ifndef current_wordsize
307                         (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_len :
308 #endif
309                                 u.cmsg->cmsg_len;
310                 const int cmsg_level =
311 #ifndef current_wordsize
312                         (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_level :
313 #endif
314                                 u.cmsg->cmsg_level;
315                 const int cmsg_type =
316 #ifndef current_wordsize
317                         (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_type :
318 #endif
319                                 u.cmsg->cmsg_type;
320
321                 if (u.ptr != buf)
322                         tprints(", ");
323                 tprintf("{cmsg_len=%" PRI_klu ", cmsg_level=", cmsg_len);
324                 printxval(socketlayers, cmsg_level, "SOL_???");
325                 tprints(", cmsg_type=");
326
327                 kernel_ulong_t len = cmsg_len > buf_len ? buf_len : cmsg_len;
328
329                 print_cmsg_type_data(tcp, cmsg_level, cmsg_type,
330                                      (const void *) (u.ptr + cmsg_size),
331                                      len > cmsg_size ? len - cmsg_size : 0);
332                 tprints("}");
333
334                 if (len < cmsg_size) {
335                         buf_len -= cmsg_size;
336                         break;
337                 }
338                 len = (cmsg_len + current_wordsize - 1) &
339                         ~((kernel_ulong_t) current_wordsize - 1);
340                 if (len >= buf_len) {
341                         buf_len = 0;
342                         break;
343                 }
344                 u.ptr += len;
345                 buf_len -= len;
346         }
347         if (buf_len) {
348                 tprints(", ");
349                 printaddr(addr + (control_len - buf_len));
350         } else if (control_len < in_control_len) {
351                 tprints(", ...");
352         }
353         tprints("]");
354         free(buf);
355 }
356
357 void
358 print_struct_msghdr(struct tcb *tcp, const struct msghdr *msg,
359                     const int *const p_user_msg_namelen,
360                     const kernel_ulong_t data_size)
361 {
362         const int msg_namelen =
363                 p_user_msg_namelen && (int) msg->msg_namelen > *p_user_msg_namelen
364                 ? *p_user_msg_namelen : (int) msg->msg_namelen;
365
366         tprints("{msg_name=");
367         const int family =
368                 decode_sockaddr(tcp, ptr_to_kulong(msg->msg_name), msg_namelen);
369         const enum iov_decode decode =
370                 (family == AF_NETLINK) ? IOV_DECODE_NETLINK : IOV_DECODE_STR;
371
372         tprints(", msg_namelen=");
373         if (p_user_msg_namelen && *p_user_msg_namelen != (int) msg->msg_namelen)
374                 tprintf("%d->", *p_user_msg_namelen);
375         tprintf("%d", msg->msg_namelen);
376
377         tprints(", msg_iov=");
378
379         tprint_iov_upto(tcp, msg->msg_iovlen,
380                         ptr_to_kulong(msg->msg_iov), decode, data_size);
381         tprintf(", msg_iovlen=%" PRI_klu, (kernel_ulong_t) msg->msg_iovlen);
382
383         decode_msg_control(tcp, ptr_to_kulong(msg->msg_control),
384                            msg->msg_controllen);
385         tprintf(", msg_controllen=%" PRI_klu, (kernel_ulong_t) msg->msg_controllen);
386
387         tprints(", msg_flags=");
388         printflags(msg_flags, msg->msg_flags, "MSG_???");
389         tprints("}");
390 }
391
392 static bool
393 fetch_msghdr_namelen(struct tcb *const tcp, const kernel_ulong_t addr,
394                      int *const p_msg_namelen)
395 {
396         struct msghdr msg;
397
398         if (addr && verbose(tcp) && fetch_struct_msghdr(tcp, addr, &msg)) {
399                 *p_msg_namelen = msg.msg_namelen;
400                 return true;
401         } else {
402                 return false;
403         }
404 }
405
406 static void
407 decode_msghdr(struct tcb *const tcp, const int *const p_user_msg_namelen,
408               const kernel_ulong_t addr, const kernel_ulong_t data_size)
409 {
410         struct msghdr msg;
411
412         if (addr && verbose(tcp) && fetch_struct_msghdr(tcp, addr, &msg))
413                 print_struct_msghdr(tcp, &msg, p_user_msg_namelen, data_size);
414         else
415                 printaddr(addr);
416 }
417
418 void
419 dumpiov_in_msghdr(struct tcb *const tcp, const kernel_ulong_t addr,
420                   const kernel_ulong_t data_size)
421 {
422         struct msghdr msg;
423
424         if (fetch_struct_msghdr(tcp, addr, &msg)) {
425                 dumpiov_upto(tcp, msg.msg_iovlen,
426                              ptr_to_kulong(msg.msg_iov), data_size);
427         }
428 }
429
430 SYS_FUNC(sendmsg)
431 {
432         printfd(tcp, tcp->u_arg[0]);
433         tprints(", ");
434         decode_msghdr(tcp, 0, tcp->u_arg[1], -1);
435         /* flags */
436         tprints(", ");
437         printflags(msg_flags, tcp->u_arg[2], "MSG_???");
438
439         return RVAL_DECODED;
440 }
441
442 SYS_FUNC(recvmsg)
443 {
444         int msg_namelen;
445
446         if (entering(tcp)) {
447                 printfd(tcp, tcp->u_arg[0]);
448                 tprints(", ");
449                 if (fetch_msghdr_namelen(tcp, tcp->u_arg[1], &msg_namelen)) {
450                         set_tcb_priv_ulong(tcp, msg_namelen);
451                         return 0;
452                 }
453                 printaddr(tcp->u_arg[1]);
454         } else {
455                 msg_namelen = get_tcb_priv_ulong(tcp);
456
457                 if (syserror(tcp))
458                         tprintf("{msg_namelen=%d}", msg_namelen);
459                 else
460                         decode_msghdr(tcp, &msg_namelen, tcp->u_arg[1],
461                                       tcp->u_rval);
462         }
463
464         /* flags */
465         tprints(", ");
466         printflags(msg_flags, tcp->u_arg[2], "MSG_???");
467
468         return RVAL_DECODED;
469 }