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