]> granicus.if.org Git - strace/blob - sock.c
sock: guess ifr_hwaddr size in SIOCSIFHWADDR/SIOCGIFHWADDR
[strace] / sock.c
1 /*
2  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
3  * Copyright (c) 1996-2017 The strace developers.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "defs.h"
30 #include "print_fields.h"
31
32 #include <sys/socket.h>
33 #if defined ALPHA || defined SH || defined SH64
34 # include <linux/ioctl.h>
35 #endif
36 #include <linux/sockios.h>
37 #include <arpa/inet.h>
38 #include <net/if.h>
39
40 #include DEF_MPERS_TYPE(struct_ifconf)
41 #include DEF_MPERS_TYPE(struct_ifreq)
42
43 typedef struct ifconf struct_ifconf;
44 typedef struct ifreq struct_ifreq;
45
46 #include MPERS_DEFS
47
48 #include "xlat/iffflags.h"
49
50 #define XLAT_MACROS_ONLY
51 # include "xlat/arp_hardware_types.h"
52 #undef XLAT_MACROS_ONLY
53
54 static void
55 print_ifname(const char *ifname)
56 {
57         print_quoted_string(ifname, IFNAMSIZ + 1, QUOTE_0_TERMINATED);
58 }
59
60 static void
61 print_ifreq(struct tcb *const tcp, const unsigned int code,
62             const kernel_ulong_t arg, const struct_ifreq *const ifr)
63 {
64         switch (code) {
65         case SIOCSIFADDR:
66         case SIOCGIFADDR:
67                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_addr);
68                 break;
69         case SIOCSIFDSTADDR:
70         case SIOCGIFDSTADDR:
71                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_dstaddr);
72                 break;
73         case SIOCSIFBRDADDR:
74         case SIOCGIFBRDADDR:
75                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_broadaddr);
76                 break;
77         case SIOCSIFNETMASK:
78         case SIOCGIFNETMASK:
79                 PRINT_FIELD_SOCKADDR("", *ifr, ifr_netmask);
80                 break;
81         case SIOCSIFHWADDR:
82         case SIOCGIFHWADDR: {
83                 static uint8_t hwaddr_sizes[] = {
84                         [0 ... ARPHRD_IEEE802_TR] = 255,
85
86                         [ARPHRD_NETROM]     =  7 /* AX25_ADDR_LEN */,
87                         [ARPHRD_ETHER]      =  6 /* ETH_ALEN */,
88                         /* ARPHRD_EETHER - no actual devices in Linux */
89                         [ARPHRD_AX25]       =  7 /* AX25_ADDR_LEN */,
90                         /* ARPHRD_PRONET - no actual devices in Linux */
91                         /* ARPHRD_CHAOS - no actual devices in Linux */
92                         [ARPHRD_IEEE802]    =  6 /* FC_ALEN */,
93                         [ARPHRD_ARCNET]     =  1 /* ARCNET_ALEN */,
94                         /* ARPHRD_APPLETLK - no actual devices in Linux */
95                         [ARPHRD_DLCI]       = sizeof(short),
96                         /* ARPHRD_ATM - no explicit setting */
97                         /* ARPHRD_METRICOM - no actual devices in Linux */
98                         [ARPHRD_IEEE1394]   = 16 /* FWNET_ALEN */,
99                         [ARPHRD_EUI64]      =  8 /* EUI64_ADDR_LEN */,
100                         [ARPHRD_INFINIBAND] = 20 /* INFINIBAND_ALEN */,
101                         [ARPHRD_SLIP]       =  0,
102                         /* ARPHRD_CSLIP - no actual devices in Linux */
103                         /* ARPHRD_SLIP6 - no actual devices in Linux */
104                         /* ARPHRD_CSLIP6 - no actual devices in Linux */
105                         /* ARPHRD_RSRVD - no actual devices in Linux */
106                         /* ARPHRD_ADAPT - no actual devices in Linux */
107                         [ARPHRD_ROSE]       =  5 /* ROSE_ADDR_LEN */,
108                         [ARPHRD_X25]        =  0,
109                         /* ARPHRD_HWX25 - no actual devices in Linux */
110                         [ARPHRD_CAN]        =  0,
111                         [ARPHRD_PPP]        =  0,
112                         /* ARPHRD_CISCO - no actual devices in Linux */
113                         /* ARPHRD_LAPB - no actual devices in Linux */
114                         /* ARPHRD_DDCMP - no actual devices in Linux */
115                         [ARPHRD_RAWHDLC]    =  0,
116                         [ARPHRD_RAWIP]      =  0,
117                         [ARPHRD_TUNNEL]     =  4 /* IPIP */,
118                         [ARPHRD_TUNNEL6]    = 16 /* sizeof(struct in6_addr) */,
119                         /* ARPHRD_FRAD - no actual devices in Linux */
120                         /* ARPHRD_SKIP - no actual devices in Linux */
121                         [ARPHRD_LOOPBACK]   =  6 /* ETH_ALEN */,
122                         [ARPHRD_LOCALTLK]   =  1 /* LTALK_ALEN */,
123                         [ARPHRD_FDDI]       =  6 /* FDDI_K_ALEN */,
124                         /* ARPHRD_BIF - no actual devices in Linux */
125                         [ARPHRD_SIT]        =  4,
126                         [ARPHRD_IPDDP]      =  0,
127                         [ARPHRD_IPGRE]      =  4,
128                         [ARPHRD_PIMREG]     =  0,
129                         [ARPHRD_HIPPI]      =  6 /* HIPPI_ALEN */,
130                         /* ARPHRD_ASH - no actual devices in Linux */
131                         /* ARPHRD_ECONET - no actual devices in Linux */
132                         [ARPHRD_IRDA]       =  4 /* LAP_ALEN */,
133                         /* ARPHRD_FCPP - no actual devices in Linux */
134                         /* ARPHRD_FCAL - no actual devices in Linux */
135                         /* ARPHRD_FCPL - no actual devices in Linux */
136                         /* ARPHRD_FCFABRIC - no actual devices in Linux */
137                         /* ARPHRD_IEEE802_TR - no actual devices in Linux */
138                         [ARPHRD_IEEE80211]  =  6 /* ETH_ALEN */,
139                         [ARPHRD_IEEE80211_PRISM] = 6 /* ETH_ALEN */,
140                         [ARPHRD_IEEE80211_RADIOTAP] = 6 /* ETH_ALEN */,
141                         [ARPHRD_IEEE802154]
142                                 = 8 /* IEEE802154_EXTENDED_ADDR_LEN */,
143                         [ARPHRD_IEEE802154_MONITOR]
144                                 = 8 /* IEEE802154_EXTENDED_ADDR_LEN */,
145                         [ARPHRD_PHONET]     =  1,
146                         [ARPHRD_PHONET_PIPE] = 1,
147                         [ARPHRD_CAIF]       =  0,
148                         [ARPHRD_IP6GRE]     = 16 /* sizeof(struct in6_addr) */,
149                         [ARPHRD_NETLINK]    =  0,
150                         [ARPHRD_6LOWPAN]    =  8 /* EUI64_ADDR_LEN */
151                                 /* ^ or ETH_ALEN, depending on lltype */,
152                         [ARPHRD_VSOCKMON]   =  0,
153                 };
154
155                 uint16_t proto = ifr->ifr_hwaddr.sa_family;
156                 uint8_t sz = (proto < ARRAY_SIZE(hwaddr_sizes))
157                                 ? hwaddr_sizes[proto] : 255;
158
159                 PRINT_FIELD_XVAL("ifr_hwaddr={", ifr->ifr_hwaddr, sa_family,
160                                  arp_hardware_types, "ARPHRD_???");
161                 PRINT_FIELD_MAC_SZ(", ", ifr->ifr_hwaddr, sa_data,
162                                    MIN(sizeof(ifr->ifr_hwaddr.sa_data), sz));
163                 tprints("}");
164                 break;
165         }
166         case SIOCSIFFLAGS:
167         case SIOCGIFFLAGS:
168                 tprints("ifr_flags=");
169                 printflags(iffflags, (unsigned short) ifr->ifr_flags, "IFF_???");
170                 break;
171         case SIOCSIFMETRIC:
172         case SIOCGIFMETRIC:
173                 tprintf("ifr_metric=%d", ifr->ifr_metric);
174                 break;
175         case SIOCSIFMTU:
176         case SIOCGIFMTU:
177                 tprintf("ifr_mtu=%d", ifr->ifr_mtu);
178                 break;
179         case SIOCSIFSLAVE:
180         case SIOCGIFSLAVE:
181                 tprints("ifr_slave=");
182                 print_ifname(ifr->ifr_slave);
183                 break;
184         case SIOCSIFTXQLEN:
185         case SIOCGIFTXQLEN:
186                 tprintf("ifr_qlen=%d", ifr->ifr_qlen);
187                 break;
188         case SIOCSIFMAP:
189         case SIOCGIFMAP:
190                 tprintf("ifr_map={mem_start=%#" PRI_klx ", "
191                         "mem_end=%#" PRI_klx ", base_addr=%#x, "
192                         "irq=%u, dma=%u, port=%u}",
193                         (kernel_ulong_t) ifr->ifr_map.mem_start,
194                         (kernel_ulong_t) ifr->ifr_map.mem_end,
195                         (unsigned) ifr->ifr_map.base_addr,
196                         (unsigned) ifr->ifr_map.irq,
197                         (unsigned) ifr->ifr_map.dma,
198                         (unsigned) ifr->ifr_map.port);
199                 break;
200         }
201 }
202
203 static unsigned int
204 print_ifc_len(int len)
205 {
206         const unsigned int n = (unsigned int) len / sizeof(struct_ifreq);
207
208         if (len < 0 || n * sizeof(struct_ifreq) != (unsigned int) len)
209                 tprintf("%d", len);
210         else
211                 tprintf("%u * sizeof(struct ifreq)", n);
212
213         return n;
214 }
215
216 static bool
217 print_ifconf_ifreq(struct tcb *tcp, void *elem_buf, size_t elem_size,
218                    void *dummy)
219 {
220         struct_ifreq *ifr = elem_buf;
221
222         tprints("{ifr_name=");
223         print_ifname(ifr->ifr_name);
224         PRINT_FIELD_SOCKADDR(", ", *ifr, ifr_addr);
225         tprints("}");
226
227         return true;
228 }
229
230 /*
231  * There are two different modes of operation:
232  *
233  * - Get buffer size.  In this case, the callee sets ifc_buf to NULL,
234  *   and the kernel returns the buffer size in ifc_len.
235  * - Get actual data.  In this case, the callee specifies the buffer address
236  *   in ifc_buf and its size in ifc_len.  The kernel fills the buffer with
237  *   the data, and its amount is returned in ifc_len.
238  *
239  * Note that, technically, the whole struct ifconf is overwritten,
240  * so ifc_buf could be different on exit, but current ioctl handler
241  * implementation does not touch it.
242  */
243 static int
244 decode_ifconf(struct tcb *const tcp, const kernel_ulong_t addr)
245 {
246         struct_ifconf *entering_ifc = NULL;
247         struct_ifconf *ifc =
248                 entering(tcp) ? malloc(sizeof(*ifc)) : alloca(sizeof(*ifc));
249
250         if (exiting(tcp)) {
251                 entering_ifc = get_tcb_priv_data(tcp);
252
253                 if (!entering_ifc) {
254                         error_func_msg("where is my ifconf?");
255                         return 0;
256                 }
257         }
258
259         if (!ifc || umove(tcp, addr, ifc) < 0) {
260                 if (entering(tcp)) {
261                         free(ifc);
262
263                         tprints(", ");
264                         printaddr(addr);
265                 } else {
266                         /*
267                          * We failed to fetch the structure on exiting syscall,
268                          * print whatever was fetched on entering syscall.
269                          */
270                         if (!entering_ifc->ifc_buf)
271                                 print_ifc_len(entering_ifc->ifc_len);
272
273                         tprints(", ifc_buf=");
274                         printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
275
276                         tprints("}");
277                 }
278
279                 return RVAL_IOCTL_DECODED;
280         }
281
282         if (entering(tcp)) {
283                 tprints(", {ifc_len=");
284                 if (ifc->ifc_buf)
285                         print_ifc_len(ifc->ifc_len);
286
287                 set_tcb_priv_data(tcp, ifc, free);
288
289                 return 0;
290         }
291
292         /* exiting */
293
294         if (entering_ifc->ifc_buf && (entering_ifc->ifc_len != ifc->ifc_len))
295                 tprints(" => ");
296         if (!entering_ifc->ifc_buf || (entering_ifc->ifc_len != ifc->ifc_len))
297                 print_ifc_len(ifc->ifc_len);
298
299         tprints(", ifc_buf=");
300
301         if (!entering_ifc->ifc_buf || syserror(tcp)) {
302                 printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
303                 if (entering_ifc->ifc_buf != ifc->ifc_buf) {
304                         tprints(" => ");
305                         printaddr(ptr_to_kulong(ifc->ifc_buf));
306                 }
307         } else {
308                 struct_ifreq ifr;
309
310                 print_array(tcp, ptr_to_kulong(ifc->ifc_buf),
311                             ifc->ifc_len / sizeof(struct_ifreq),
312                             &ifr, sizeof(ifr),
313                             umoven_or_printaddr, print_ifconf_ifreq, NULL);
314         }
315
316         tprints("}");
317
318         return RVAL_IOCTL_DECODED;
319 }
320
321 MPERS_PRINTER_DECL(int, sock_ioctl,
322                    struct tcb *tcp, const unsigned int code,
323                    const kernel_ulong_t arg)
324 {
325         struct_ifreq ifr;
326
327         switch (code) {
328         case SIOCGIFCONF:
329                 return decode_ifconf(tcp, arg);
330
331 #ifdef SIOCBRADDBR
332         case SIOCBRADDBR:
333         case SIOCBRDELBR:
334                 tprints(", ");
335                 printstr(tcp, arg);
336                 break;
337 #endif
338
339 #ifdef FIOSETOWN
340         case FIOSETOWN:
341 #endif
342 #ifdef SIOCSPGRP
343         case SIOCSPGRP:
344 #endif
345                 tprints(", ");
346                 printnum_int(tcp, arg, "%d");
347                 break;
348
349 #ifdef FIOGETOWN
350         case FIOGETOWN:
351 #endif
352 #ifdef SIOCGPGRP
353         case SIOCGPGRP:
354 #endif
355 #ifdef SIOCATMARK
356         case SIOCATMARK:
357 #endif
358                 if (entering(tcp))
359                         return 0;
360                 tprints(", ");
361                 printnum_int(tcp, arg, "%d");
362                 break;
363
364 #ifdef SIOCBRADDIF
365         case SIOCBRADDIF:
366 #endif
367 #ifdef SIOCBRDELIF
368         case SIOCBRDELIF:
369 #endif
370                 /* no arguments */
371                 break;
372
373         case SIOCSIFNAME:
374         case SIOCSIFADDR:
375         case SIOCSIFDSTADDR:
376         case SIOCSIFBRDADDR:
377         case SIOCSIFNETMASK:
378         case SIOCSIFFLAGS:
379         case SIOCSIFMETRIC:
380         case SIOCSIFMTU:
381         case SIOCSIFSLAVE:
382         case SIOCSIFHWADDR:
383         case SIOCSIFTXQLEN:
384         case SIOCSIFMAP:
385                 tprints(", ");
386                 if (umove_or_printaddr(tcp, arg, &ifr))
387                         break;
388
389                 tprints("{ifr_name=");
390                 print_ifname(ifr.ifr_name);
391                 tprints(", ");
392                 if (code == SIOCSIFNAME) {
393                         tprints("ifr_newname=");
394                         print_ifname(ifr.ifr_newname);
395                 } else {
396                         print_ifreq(tcp, code, arg, &ifr);
397                 }
398                 tprints("}");
399                 break;
400
401         case SIOCGIFNAME:
402         case SIOCGIFINDEX:
403         case SIOCGIFADDR:
404         case SIOCGIFDSTADDR:
405         case SIOCGIFBRDADDR:
406         case SIOCGIFNETMASK:
407         case SIOCGIFFLAGS:
408         case SIOCGIFMETRIC:
409         case SIOCGIFMTU:
410         case SIOCGIFSLAVE:
411         case SIOCGIFHWADDR:
412         case SIOCGIFTXQLEN:
413         case SIOCGIFMAP:
414                 if (entering(tcp)) {
415                         tprints(", ");
416                         if (umove_or_printaddr(tcp, arg, &ifr))
417                                 break;
418
419                         if (SIOCGIFNAME == code) {
420                                 tprintf("{ifr_index=%d", ifr.ifr_ifindex);
421                         } else {
422                                 tprints("{ifr_name=");
423                                 print_ifname(ifr.ifr_name);
424                         }
425                         return 0;
426                 } else {
427                         if (syserror(tcp)) {
428                                 tprints("}");
429                                 break;
430                         }
431
432                         tprints(", ");
433                         if (umove(tcp, arg, &ifr) < 0) {
434                                 tprints("???}");
435                                 break;
436                         }
437
438                         if (SIOCGIFNAME == code) {
439                                 tprints("ifr_name=");
440                                 print_ifname(ifr.ifr_name);
441                         } else {
442                                 print_ifreq(tcp, code, arg, &ifr);
443                         }
444                         tprints("}");
445                         break;
446                 }
447
448         default:
449                 return RVAL_DECODED;
450         }
451
452         return RVAL_IOCTL_DECODED;
453 }