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.
This commit is contained in:
Дмитрий Левин 2015-07-04 14:01:08 +03:00
parent a0beac1538
commit b93c110079

436
sock.c
View File

@ -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);
} else {
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("}");
} else {
tprints(", {ifr_name=");
print_ifname(ifr.ifr_name);
if (entering(tcp)) {
tprints(", ");
switch (code) {
case SIOCGIFINDEX:
tprintf("ifr_index=%d", ifr.ifr_ifindex);
if (umove_or_printaddr(tcp, arg, &ifr))
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 (SIOCGIFNAME == code) {
tprintf("{ifr_index=%d", ifr.ifr_ifindex);
} else {
tprints("{ifr_name=");
print_ifname(ifr.ifr_name);
}
return 1;
} else {
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)