]> granicus.if.org Git - strace/blob - sock.c
rtnl_neightbl: always decode struct ndt_config and struct ndt_stats
[strace] / sock.c
1 /*
2  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
3  * Copyright (c) 1996-2018 The strace developers.
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
7  */
8
9 #include "defs.h"
10 #include "print_fields.h"
11
12 #include <sys/socket.h>
13 #if defined ALPHA || defined SH || defined SH64
14 # include <linux/ioctl.h>
15 #endif
16 #include <linux/sockios.h>
17 #include <arpa/inet.h>
18 #include <net/if.h>
19
20 #include DEF_MPERS_TYPE(struct_ifconf)
21 #include DEF_MPERS_TYPE(struct_ifreq)
22
23 typedef struct ifconf struct_ifconf;
24 typedef struct ifreq struct_ifreq;
25
26 #include MPERS_DEFS
27
28 #include "xlat/iffflags.h"
29
30 #define XLAT_MACROS_ONLY
31 #include "xlat/arp_hardware_types.h"
32 #undef XLAT_MACROS_ONLY
33
34 static void
35 print_ifname(const char *ifname)
36 {
37         print_quoted_string(ifname, IFNAMSIZ + 1, QUOTE_0_TERMINATED);
38 }
39
40 static void
41 print_ifreq(struct tcb *const tcp, const unsigned int code,
42             const kernel_ulong_t arg, const struct_ifreq *const ifr)
43 {
44         switch (code) {
45         case SIOCSIFADDR:
46         case SIOCGIFADDR:
47                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_addr);
48                 break;
49         case SIOCSIFDSTADDR:
50         case SIOCGIFDSTADDR:
51                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_dstaddr);
52                 break;
53         case SIOCSIFBRDADDR:
54         case SIOCGIFBRDADDR:
55                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_broadaddr);
56                 break;
57         case SIOCSIFNETMASK:
58         case SIOCGIFNETMASK:
59                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_netmask);
60                 break;
61         case SIOCSIFHWADDR:
62         case SIOCGIFHWADDR: {
63                 PRINT_FIELD_XVAL("ifr_hwaddr={", ifr->ifr_hwaddr, sa_family,
64                                  arp_hardware_types, "ARPHRD_???");
65                 PRINT_FIELD_HWADDR_SZ(", ", ifr->ifr_hwaddr, sa_data,
66                                       sizeof(ifr->ifr_hwaddr.sa_data),
67                                       ifr->ifr_hwaddr.sa_family);
68                 tprints("}");
69                 break;
70         }
71         case SIOCSIFFLAGS:
72         case SIOCGIFFLAGS:
73                 tprints("ifr_flags=");
74                 printflags(iffflags, (unsigned short) ifr->ifr_flags, "IFF_???");
75                 break;
76         case SIOCSIFMETRIC:
77         case SIOCGIFMETRIC:
78                 tprintf("ifr_metric=%d", ifr->ifr_metric);
79                 break;
80         case SIOCSIFMTU:
81         case SIOCGIFMTU:
82                 tprintf("ifr_mtu=%d", ifr->ifr_mtu);
83                 break;
84         case SIOCSIFSLAVE:
85         case SIOCGIFSLAVE:
86                 tprints("ifr_slave=");
87                 print_ifname(ifr->ifr_slave);
88                 break;
89         case SIOCSIFTXQLEN:
90         case SIOCGIFTXQLEN:
91                 tprintf("ifr_qlen=%d", ifr->ifr_qlen);
92                 break;
93         case SIOCSIFMAP:
94         case SIOCGIFMAP:
95                 tprintf("ifr_map={mem_start=%#" PRI_klx ", "
96                         "mem_end=%#" PRI_klx ", base_addr=%#x, "
97                         "irq=%u, dma=%u, port=%u}",
98                         (kernel_ulong_t) ifr->ifr_map.mem_start,
99                         (kernel_ulong_t) ifr->ifr_map.mem_end,
100                         (unsigned) ifr->ifr_map.base_addr,
101                         (unsigned) ifr->ifr_map.irq,
102                         (unsigned) ifr->ifr_map.dma,
103                         (unsigned) ifr->ifr_map.port);
104                 break;
105         }
106 }
107
108 static unsigned int
109 print_ifc_len(int len)
110 {
111         const unsigned int n = (unsigned int) len / sizeof(struct_ifreq);
112
113         if (len < 0 || n * sizeof(struct_ifreq) != (unsigned int) len)
114                 tprintf("%d", len);
115         else
116                 tprintf("%u * sizeof(struct ifreq)", n);
117
118         return n;
119 }
120
121 static bool
122 print_ifconf_ifreq(struct tcb *tcp, void *elem_buf, size_t elem_size,
123                    void *dummy)
124 {
125         struct_ifreq *ifr = elem_buf;
126
127         tprints("{ifr_name=");
128         print_ifname(ifr->ifr_name);
129         PRINT_FIELD_SOCKADDR(", ", *ifr, ifr_addr);
130         tprints("}");
131
132         return true;
133 }
134
135 /*
136  * There are two different modes of operation:
137  *
138  * - Get buffer size.  In this case, the callee sets ifc_buf to NULL,
139  *   and the kernel returns the buffer size in ifc_len.
140  * - Get actual data.  In this case, the callee specifies the buffer address
141  *   in ifc_buf and its size in ifc_len.  The kernel fills the buffer with
142  *   the data, and its amount is returned in ifc_len.
143  *
144  * Note that, technically, the whole struct ifconf is overwritten,
145  * so ifc_buf could be different on exit, but current ioctl handler
146  * implementation does not touch it.
147  */
148 static int
149 decode_ifconf(struct tcb *const tcp, const kernel_ulong_t addr)
150 {
151         struct_ifconf *entering_ifc = NULL;
152         struct_ifconf *ifc =
153                 entering(tcp) ? malloc(sizeof(*ifc)) : alloca(sizeof(*ifc));
154
155         if (exiting(tcp)) {
156                 entering_ifc = get_tcb_priv_data(tcp);
157
158                 if (!entering_ifc) {
159                         error_func_msg("where is my ifconf?");
160                         return 0;
161                 }
162         }
163
164         if (!ifc || umove(tcp, addr, ifc) < 0) {
165                 if (entering(tcp)) {
166                         free(ifc);
167
168                         tprints(", ");
169                         printaddr(addr);
170                 } else {
171                         /*
172                          * We failed to fetch the structure on exiting syscall,
173                          * print whatever was fetched on entering syscall.
174                          */
175                         if (!entering_ifc->ifc_buf)
176                                 print_ifc_len(entering_ifc->ifc_len);
177
178                         tprints(", ifc_buf=");
179                         printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
180
181                         tprints("}");
182                 }
183
184                 return RVAL_IOCTL_DECODED;
185         }
186
187         if (entering(tcp)) {
188                 tprints(", {ifc_len=");
189                 if (ifc->ifc_buf)
190                         print_ifc_len(ifc->ifc_len);
191
192                 set_tcb_priv_data(tcp, ifc, free);
193
194                 return 0;
195         }
196
197         /* exiting */
198
199         if (entering_ifc->ifc_buf && (entering_ifc->ifc_len != ifc->ifc_len))
200                 tprints(" => ");
201         if (!entering_ifc->ifc_buf || (entering_ifc->ifc_len != ifc->ifc_len))
202                 print_ifc_len(ifc->ifc_len);
203
204         tprints(", ifc_buf=");
205
206         if (!entering_ifc->ifc_buf || syserror(tcp)) {
207                 printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
208                 if (entering_ifc->ifc_buf != ifc->ifc_buf) {
209                         tprints(" => ");
210                         printaddr(ptr_to_kulong(ifc->ifc_buf));
211                 }
212         } else {
213                 struct_ifreq ifr;
214
215                 print_array(tcp, ptr_to_kulong(ifc->ifc_buf),
216                             ifc->ifc_len / sizeof(struct_ifreq),
217                             &ifr, sizeof(ifr),
218                             tfetch_mem, print_ifconf_ifreq, NULL);
219         }
220
221         tprints("}");
222
223         return RVAL_IOCTL_DECODED;
224 }
225
226 MPERS_PRINTER_DECL(int, sock_ioctl,
227                    struct tcb *tcp, const unsigned int code,
228                    const kernel_ulong_t arg)
229 {
230         struct_ifreq ifr;
231
232         switch (code) {
233         case SIOCGIFCONF:
234                 return decode_ifconf(tcp, arg);
235
236 #ifdef SIOCBRADDBR
237         case SIOCBRADDBR:
238         case SIOCBRDELBR:
239                 tprints(", ");
240                 printstr(tcp, arg);
241                 break;
242 #endif
243
244 #ifdef FIOSETOWN
245         case FIOSETOWN:
246 #endif
247 #ifdef SIOCSPGRP
248         case SIOCSPGRP:
249 #endif
250                 tprints(", ");
251                 printnum_int(tcp, arg, "%d");
252                 break;
253
254 #ifdef FIOGETOWN
255         case FIOGETOWN:
256 #endif
257 #ifdef SIOCGPGRP
258         case SIOCGPGRP:
259 #endif
260 #ifdef SIOCATMARK
261         case SIOCATMARK:
262 #endif
263                 if (entering(tcp))
264                         return 0;
265                 tprints(", ");
266                 printnum_int(tcp, arg, "%d");
267                 break;
268
269 #ifdef SIOCBRADDIF
270         case SIOCBRADDIF:
271 #endif
272 #ifdef SIOCBRDELIF
273         case SIOCBRDELIF:
274 #endif
275                 /* no arguments */
276                 break;
277
278         case SIOCSIFNAME:
279         case SIOCSIFADDR:
280         case SIOCSIFDSTADDR:
281         case SIOCSIFBRDADDR:
282         case SIOCSIFNETMASK:
283         case SIOCSIFFLAGS:
284         case SIOCSIFMETRIC:
285         case SIOCSIFMTU:
286         case SIOCSIFSLAVE:
287         case SIOCSIFHWADDR:
288         case SIOCSIFTXQLEN:
289         case SIOCSIFMAP:
290                 tprints(", ");
291                 if (umove_or_printaddr(tcp, arg, &ifr))
292                         break;
293
294                 tprints("{ifr_name=");
295                 print_ifname(ifr.ifr_name);
296                 tprints(", ");
297                 if (code == SIOCSIFNAME) {
298                         tprints("ifr_newname=");
299                         print_ifname(ifr.ifr_newname);
300                 } else {
301                         print_ifreq(tcp, code, arg, &ifr);
302                 }
303                 tprints("}");
304                 break;
305
306         case SIOCGIFNAME:
307         case SIOCGIFINDEX:
308         case SIOCGIFADDR:
309         case SIOCGIFDSTADDR:
310         case SIOCGIFBRDADDR:
311         case SIOCGIFNETMASK:
312         case SIOCGIFFLAGS:
313         case SIOCGIFMETRIC:
314         case SIOCGIFMTU:
315         case SIOCGIFSLAVE:
316         case SIOCGIFHWADDR:
317         case SIOCGIFTXQLEN:
318         case SIOCGIFMAP:
319                 if (entering(tcp)) {
320                         tprints(", ");
321                         if (umove_or_printaddr(tcp, arg, &ifr))
322                                 break;
323
324                         if (SIOCGIFNAME == code) {
325                                 tprintf("{ifr_index=%d", ifr.ifr_ifindex);
326                         } else {
327                                 tprints("{ifr_name=");
328                                 print_ifname(ifr.ifr_name);
329                         }
330                         return 0;
331                 } else {
332                         if (syserror(tcp)) {
333                                 tprints("}");
334                                 break;
335                         }
336
337                         tprints(", ");
338                         if (umove(tcp, arg, &ifr) < 0) {
339                                 tprints("???}");
340                                 break;
341                         }
342
343                         if (SIOCGIFNAME == code) {
344                                 tprints("ifr_name=");
345                                 print_ifname(ifr.ifr_name);
346                         } else {
347                                 print_ifreq(tcp, code, arg, &ifr);
348                         }
349                         tprints("}");
350                         break;
351                 }
352
353         default:
354                 return RVAL_DECODED;
355         }
356
357         return RVAL_IOCTL_DECODED;
358 }