From b93c110079a0ba3adb561437546db7f6ee27be73 Mon Sep 17 00:00:00 2001 From: "Dmitry V. Levin" Date: Sat, 4 Jul 2015 14:01:08 +0300 Subject: [PATCH] sock.c: enhance socket ioctl parser Decode as much data on entering syscall as possible. * sock.c: Update for RVAL_DECODED. (print_addr): Remove. (print_ifreq_addr, print_ifreq, print_ifc_len, decode_ifconf): New functions. (sock_ioctl) Use them. Use umove_or_printaddr. --- sock.c | 432 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 245 insertions(+), 187 deletions(-) diff --git a/sock.c b/sock.c index 48bf74b5..97d8afa6 100644 --- a/sock.c +++ b/sock.c @@ -41,14 +41,19 @@ #include "xlat/iffflags.h" static void -print_addr(struct tcb *tcp, long addr, struct ifreq *ifr) +print_ifreq_addr(struct tcb *tcp, const struct ifreq *ifr, const long addr) { + tprintf("{"); + printxval(addrfams, ifr->ifr_addr.sa_family, "AF_???"); + tprints(", "); if (ifr->ifr_addr.sa_family == AF_INET) { - struct sockaddr_in *sinp; - sinp = (struct sockaddr_in *) &ifr->ifr_addr; + const struct sockaddr_in *sinp = + (struct sockaddr_in *) &ifr->ifr_addr; tprintf("inet_addr(\"%s\")", inet_ntoa(sinp->sin_addr)); } else - printstr(tcp, addr, sizeof(ifr->ifr_addr.sa_data)); + printstr(tcp, addr + offsetof(struct ifreq, ifr_addr.sa_data), + sizeof(ifr->ifr_addr.sa_data)); + tprints("}"); } static void @@ -57,59 +62,189 @@ print_ifname(const char *ifname) print_quoted_string(ifname, IFNAMSIZ + 1, QUOTE_0_TERMINATED); } -int -sock_ioctl(struct tcb *tcp, const unsigned int code, long arg) +static void +print_ifreq(struct tcb *tcp, const unsigned int code, const long arg, + const struct ifreq *ifr) +{ + switch (code) { + case SIOCSIFADDR: + case SIOCGIFADDR: + tprints("ifr_addr="); + print_ifreq_addr(tcp, ifr, arg); + break; + case SIOCSIFDSTADDR: + case SIOCGIFDSTADDR: + tprints("ifr_dstaddr="); + print_ifreq_addr(tcp, ifr, arg); + break; + case SIOCSIFBRDADDR: + case SIOCGIFBRDADDR: + tprints("ifr_broadaddr="); + print_ifreq_addr(tcp, ifr, arg); + break; + case SIOCSIFNETMASK: + case SIOCGIFNETMASK: + tprints("ifr_netmask="); + print_ifreq_addr(tcp, ifr, arg); + break; + case SIOCSIFHWADDR: + case SIOCGIFHWADDR: { + /* XXX Are there other hardware addresses + than 6-byte MACs? */ + const unsigned char *bytes = + (unsigned char *) &ifr->ifr_hwaddr.sa_data; + tprintf("ifr_hwaddr=%02x:%02x:%02x:%02x:%02x:%02x", + bytes[0], bytes[1], bytes[2], + bytes[3], bytes[4], bytes[5]); + break; + } + case SIOCSIFFLAGS: + case SIOCGIFFLAGS: + tprints("ifr_flags="); + printflags(iffflags, ifr->ifr_flags, "IFF_???"); + break; + case SIOCSIFMETRIC: + case SIOCGIFMETRIC: + tprintf("ifr_metric=%d", ifr->ifr_metric); + break; + case SIOCSIFMTU: + case SIOCGIFMTU: + tprintf("ifr_mtu=%d", ifr->ifr_mtu); + break; + case SIOCSIFSLAVE: + case SIOCGIFSLAVE: + tprints("ifr_slave="); + print_ifname(ifr->ifr_slave); + break; + case SIOCSIFTXQLEN: + case SIOCGIFTXQLEN: + tprintf("ifr_qlen=%d", ifr->ifr_qlen); + break; + case SIOCSIFMAP: + case SIOCGIFMAP: + tprintf("ifr_map={mem_start=%#lx, " + "mem_end=%#lx, base_addr=%#x, " + "irq=%u, dma=%u, port=%u}", + ifr->ifr_map.mem_start, + ifr->ifr_map.mem_end, + (unsigned) ifr->ifr_map.base_addr, + (unsigned) ifr->ifr_map.irq, + (unsigned) ifr->ifr_map.dma, + (unsigned) ifr->ifr_map.port); + break; + } +} + +static unsigned int +print_ifc_len(int len) +{ + const unsigned int n = (unsigned int) len / sizeof(struct ifreq); + + if (len < 0 || n * sizeof(struct ifreq) != (unsigned int) len) + tprintf("%d", len); + else + tprintf("%u * sizeof(struct ifreq)", n); + + return n; +} + +static int +decode_ifconf(struct tcb *tcp, const long addr) { - struct ifreq ifr; struct ifconf ifc; - const char *str = NULL; - unsigned char *bytes; if (entering(tcp)) { - switch (code) { - case SIOCGIFCONF: - if (umove(tcp, tcp->u_arg[2], &ifc) >= 0 - && ifc.ifc_buf == NULL) - tprintf(", {%d -> ", ifc.ifc_len); - else - tprints(", {"); - break; - case SIOCSIFNAME: - if (umove(tcp, tcp->u_arg[2], &ifr) < 0) - tprintf(", %#lx", tcp->u_arg[2]); - else { - tprints(", {ifr_name="); - print_ifname(ifr.ifr_name); - tprints(", ifr_newname="); - print_ifname(ifr.ifr_newname); - tprints("}"); - } - break; + tprints(", "); + if (umove_or_printaddr(tcp, addr, &ifc)) + return RVAL_DECODED | 1; + if (ifc.ifc_buf) { + tprints("{"); + print_ifc_len(ifc.ifc_len); } - return 0; + return 1; + } + + if (syserror(tcp) || umove(tcp, addr, &ifc) < 0) { + if (ifc.ifc_buf) + tprints("}"); + else + printaddr(addr); + return RVAL_DECODED | 1; } + if (!ifc.ifc_buf) { + tprints("{"); + print_ifc_len(ifc.ifc_len); + tprints(", NULL}"); + return RVAL_DECODED | 1; + } + + tprints(" => "); + const unsigned int nifra = print_ifc_len(ifc.ifc_len); + if (!nifra) { + tprints("}"); + return RVAL_DECODED | 1; + } + + struct ifreq ifra[nifra > max_strlen ? max_strlen : nifra]; + tprints(", "); + if (umove_or_printaddr(tcp, (unsigned long) ifc.ifc_buf, &ifra)) { + tprints("}"); + return RVAL_DECODED | 1; + } + + tprints("["); + unsigned int i; + for (i = 0; i < ARRAY_SIZE(ifra); ++i) { + if (i > 0) + tprints(", "); + tprints("{ifr_name="); + print_ifname(ifra[i].ifr_name); + tprints(", "); + if (verbose(tcp)) { + tprints("ifr_addr="); + print_ifreq_addr(tcp, &ifra[i], + addr + i * sizeof(ifra[0])); + } else + tprints("..."); + tprints("}"); + } + if (i < nifra) + tprints(", ..."); + tprints("]}"); + + return RVAL_DECODED | 1; +} + +int +sock_ioctl(struct tcb *tcp, const unsigned int code, const long arg) +{ + struct ifreq ifr; + switch (code) { -#ifdef SIOCSHIWAT - case SIOCSHIWAT: -#endif -#ifdef SIOCGHIWAT - case SIOCGHIWAT: -#endif -#ifdef SIOCSLOWAT - case SIOCSLOWAT: -#endif -#ifdef SIOCGLOWAT - case SIOCGLOWAT: + case SIOCGIFCONF: + return decode_ifconf(tcp, arg); + +#ifdef SIOCBRADDBR + case SIOCBRADDBR: + case SIOCBRDELBR: + tprints(", "); + printstr(tcp, arg, -1); + break; #endif + #ifdef FIOSETOWN case FIOSETOWN: #endif -#ifdef FIOGETOWN - case FIOGETOWN: -#endif #ifdef SIOCSPGRP case SIOCSPGRP: +#endif + tprints(", "); + printnum_int(tcp, arg, "%d"); + break; + +#ifdef FIOGETOWN + case FIOGETOWN: #endif #ifdef SIOCGPGRP case SIOCGPGRP: @@ -117,178 +252,101 @@ sock_ioctl(struct tcb *tcp, const unsigned int code, long arg) #ifdef SIOCATMARK case SIOCATMARK: #endif - printnum_int(tcp, arg, ", %d"); + if (entering(tcp)) + return 0; + tprints(", "); + printnum_int(tcp, arg, "%d"); + break; + +#ifdef SIOCBRADDIF + case SIOCBRADDIF: +#endif +#ifdef SIOCBRDELIF + case SIOCBRDELIF: +#endif + /* no arguments */ + break; + case SIOCSIFNAME: - return 1; + case SIOCSIFADDR: + case SIOCSIFDSTADDR: + case SIOCSIFBRDADDR: + case SIOCSIFNETMASK: + case SIOCSIFFLAGS: + case SIOCSIFMETRIC: + case SIOCSIFMTU: + case SIOCSIFSLAVE: + case SIOCSIFHWADDR: + case SIOCSIFTXQLEN: + case SIOCSIFMAP: + tprints(", "); + if (umove_or_printaddr(tcp, arg, &ifr)) + break; + + tprints("{ifr_name="); + print_ifname(ifr.ifr_name); + tprints(", "); + if (code == SIOCSIFNAME) { + tprints("ifr_newname="); + print_ifname(ifr.ifr_newname); + } else { + print_ifreq(tcp, code, arg, &ifr); + } + tprints("}"); + break; + case SIOCGIFNAME: case SIOCGIFINDEX: case SIOCGIFADDR: - case SIOCSIFADDR: case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: case SIOCGIFNETMASK: - case SIOCSIFNETMASK: case SIOCGIFFLAGS: - case SIOCSIFFLAGS: case SIOCGIFMETRIC: - case SIOCSIFMETRIC: case SIOCGIFMTU: - case SIOCSIFMTU: case SIOCGIFSLAVE: - case SIOCSIFSLAVE: case SIOCGIFHWADDR: - case SIOCSIFHWADDR: case SIOCGIFTXQLEN: - case SIOCSIFTXQLEN: case SIOCGIFMAP: - case SIOCSIFMAP: - if (umove(tcp, tcp->u_arg[2], &ifr) < 0) - tprintf(", %#lx", tcp->u_arg[2]); - else if (syserror(tcp)) { - if (code == SIOCGIFNAME) { - tprintf(", {ifr_index=%d, ifr_name=???}", - ifr.ifr_ifindex); + if (entering(tcp)) { + tprints(", "); + if (umove_or_printaddr(tcp, arg, &ifr)) + break; + + if (SIOCGIFNAME == code) { + tprintf("{ifr_index=%d", ifr.ifr_ifindex); } else { - tprints(", {ifr_name="); + tprints("{ifr_name="); print_ifname(ifr.ifr_name); - tprints(", ???}"); } - } else if (code == SIOCGIFNAME) { - tprintf(", {ifr_index=%d, ifr_name=", ifr.ifr_ifindex); - print_ifname(ifr.ifr_name); - tprints("}"); + return 1; } else { - tprints(", {ifr_name="); - print_ifname(ifr.ifr_name); - tprints(", "); - switch (code) { - case SIOCGIFINDEX: - tprintf("ifr_index=%d", ifr.ifr_ifindex); - break; - case SIOCGIFADDR: - case SIOCSIFADDR: - str = "ifr_addr"; - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - if (!str) - str = "ifr_dstaddr"; - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - if (!str) - str = "ifr_broadaddr"; - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - if (!str) - str = "ifr_netmask"; - tprintf("%s={", str); - printxval(addrfams, - ifr.ifr_addr.sa_family, - "AF_???"); - tprints(", "); - print_addr(tcp, ((long) tcp->u_arg[2] - + offsetof(struct ifreq, - ifr_addr.sa_data)), - &ifr); + if (syserror(tcp)) { tprints("}"); break; - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - /* XXX Are there other hardware addresses - than 6-byte MACs? */ - bytes = (unsigned char *) &ifr.ifr_hwaddr.sa_data; - tprintf("ifr_hwaddr=%02x:%02x:%02x:%02x:%02x:%02x", - bytes[0], bytes[1], bytes[2], - bytes[3], bytes[4], bytes[5]); - break; - case SIOCGIFFLAGS: - case SIOCSIFFLAGS: - tprints("ifr_flags="); - printflags(iffflags, ifr.ifr_flags, "IFF_???"); - break; - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - tprintf("ifr_metric=%d", ifr.ifr_metric); - break; - case SIOCGIFMTU: - case SIOCSIFMTU: - tprintf("ifr_mtu=%d", ifr.ifr_mtu); - break; - case SIOCGIFSLAVE: - case SIOCSIFSLAVE: - tprints("ifr_slave="); - print_ifname(ifr.ifr_slave); - break; - case SIOCGIFTXQLEN: - case SIOCSIFTXQLEN: - tprintf("ifr_qlen=%d", ifr.ifr_qlen); - break; - case SIOCGIFMAP: - case SIOCSIFMAP: - tprintf("ifr_map={mem_start=%#lx, " - "mem_end=%#lx, base_addr=%#x, " - "irq=%u, dma=%u, port=%u}", - ifr.ifr_map.mem_start, - ifr.ifr_map.mem_end, - (unsigned) ifr.ifr_map.base_addr, - (unsigned) ifr.ifr_map.irq, - (unsigned) ifr.ifr_map.dma, - (unsigned) ifr.ifr_map.port); - break; } - tprints("}"); - } - return 1; - case SIOCGIFCONF: - if (umove(tcp, tcp->u_arg[2], &ifc) < 0) { - tprints("???}"); - return 1; - } - tprintf("%d, ", ifc.ifc_len); - if (syserror(tcp)) { - tprintf("%lx", (unsigned long) ifc.ifc_buf); - } else if (ifc.ifc_buf == NULL) { - tprints("NULL"); - } else { - unsigned int i; - unsigned int nifra = ifc.ifc_len / sizeof(struct ifreq); - struct ifreq ifra[nifra]; - if (umoven(tcp, (unsigned long) ifc.ifc_buf, - sizeof(ifra), ifra) < 0) { - tprintf("%lx}", (unsigned long) ifc.ifc_buf); - return 1; + tprints(", "); + if (umove(tcp, arg, &ifr) < 0) { + tprints("???}"); + break; } - tprints("{"); - for (i = 0; i < nifra; ++i ) { - if (i > 0) - tprints(", "); - tprints("{"); - print_ifname(ifra[i].ifr_newname); - tprints(", {"); - if (verbose(tcp)) { - printxval(addrfams, - ifra[i].ifr_addr.sa_family, - "AF_???"); - tprints(", "); - print_addr(tcp, ((long) tcp->u_arg[2] - + offsetof(struct ifreq, - ifr_addr.sa_data) - + ((char *) &ifra[i] - - (char *) &ifra[0])), - &ifra[i]); - } else - tprints("..."); - tprints("}}"); + + if (SIOCGIFNAME == code) { + tprints("ifr_name="); + print_ifname(ifr.ifr_name); + } else { + print_ifreq(tcp, code, arg, &ifr); } tprints("}"); + break; } - tprints("}"); - return 1; + default: - return 0; + return RVAL_DECODED; } + + return RVAL_DECODED | 1; } SYS_FUNC(socketcall) -- 2.40.0