From: Mike Frysinger Date: Wed, 19 Aug 2015 17:29:27 +0000 (-0400) Subject: decode extend getsockopt/setsockopt options X-Git-Tag: v4.11~255 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=54646b8e057443f0b76afe9a231eae63afbf5d5a;p=strace decode extend getsockopt/setsockopt options Currently the code assumes the set of valid options between getsockopt and setsockopt are exactly the same and thus maintains one list. The kernel unfortunately does not do this -- it allows for different opts between the get and set functions. See the {g,s}et_opt{min,max} fields in the various netfilter subcores. To support this, extend the printxval function to take multiple sets of xlats as varargs. Then we add the new get/set lists, and pass them down in the net code when decoding things. A simple example is iptables; before: getsockopt(4, SOL_IP, 0x40 /* IP_??? */, ...) = 0 getsockopt(4, SOL_IP, 0x41 /* IP_??? */, ...) = 0 after: getsockopt(4, SOL_IP, IPT_SO_GET_INFO, ...) = 0 getsockopt(4, SOL_IP, IPT_SO_GET_ENTRIES, ...) = 0 If these were setsockopt calls, then 0x40 & 0x41 would be IPT_SO_SET_REPLACE & IPT_SO_SET_ADD_COUNTERS. * configure.ac: Check for netfilter headers. * defs.h (printxvals): New prototype. (printxval): Change to a define. * net.c: Include netfilter headers and new sockopts headers. (print_sockopt_fd_level_name): Add a is_getsockopt argument. Change SOL_IP and SOL_IPV6 decoding to use printxvals, and use is_getsockopt to pass more xlats down. (getsockopt): Call print_sockopt_fd_level_name with is_getsockopt as true. (setsockopt): Call print_sockopt_fd_level_name with is_getsockopt as false. * util.c (printxval): Rename to ... (printxvals): ... this. Rewrite to be varargs based. * xlat/getsockipoptions.in: New xlat list. * xlat/getsockipv6options.in, xlat/setsockipoptions.in, xlat/setsockipv6options.in: Likewise. --- diff --git a/configure.ac b/configure.ac index 0819f839..92160392 100644 --- a/configure.ac +++ b/configure.ac @@ -267,6 +267,7 @@ AC_CHECK_HEADERS(m4_normalize([ linux/falloc.h linux/filter.h linux/hiddev.h + linux/ip_vs.h linux/mmtimer.h linux/perf_event.h linux/seccomp.h @@ -293,6 +294,13 @@ AC_CHECK_HEADERS([linux/icmp.h linux/in6.h linux/netlink.h linux/if_packet.h], AC_CHECK_HEADERS([asm/sigcontext.h], [], [], [#include ]) AC_CHECK_TYPES([struct sigcontext],,, [#include ]) AC_CHECK_HEADERS([netinet/tcp.h netinet/udp.h],,, [#include ]) +AC_CHECK_HEADERS(m4_normalize([ + linux/netfilter_arp/arp_tables.h + linux/netfilter_bridge/ebtables.h + linux/netfilter_ipv4/ip_tables.h + linux/netfilter_ipv6/ip6_tables.h +]), [], [], [#include +#include ]) AC_CHECK_TYPES([struct mmsghdr],,, [#include ]) AC_CHECK_MEMBERS([struct msghdr.msg_control],,, [#include ]) diff --git a/defs.h b/defs.h index 9059026c..20587c71 100644 --- a/defs.h +++ b/defs.h @@ -519,7 +519,8 @@ extern int printllval(struct tcb *, const char *, int) ATTRIBUTE_FORMAT((printf, 2, 0)); extern void printaddr(long); -extern void printxval(const struct xlat *, const unsigned int, const char *); +extern void printxvals(const unsigned int, const char *, const struct xlat *, ...); +#define printxval(xlat, val, dflt) printxvals(val, dflt, xlat, NULL) extern int printargs(struct tcb *); extern int printargs_lu(struct tcb *); extern int printargs_ld(struct tcb *); diff --git a/net.c b/net.c index 7e735288..40b5a5c3 100644 --- a/net.c +++ b/net.c @@ -52,9 +52,24 @@ # include #endif +#if defined(HAVE_LINUX_IP_VS_H) +# include +#endif #if defined(HAVE_LINUX_NETLINK_H) # include #endif +#if defined(HAVE_LINUX_NETFILTER_ARP_ARP_TABLES_H) +# include +#endif +#if defined(HAVE_LINUX_NETFILTER_BRIDGE_EBTABLES_H) +# include +#endif +#if defined(HAVE_LINUX_NETFILTER_IPV4_IP_TABLES_H) +# include +#endif +#if defined(HAVE_LINUX_NETFILTER_IPV6_IP6_TABLES_H) +# include +#endif #if defined(HAVE_LINUX_IF_PACKET_H) # include #endif @@ -989,7 +1004,11 @@ SYS_FUNC(socketpair) #include "xlat/sockoptions.h" #include "xlat/sockipoptions.h" +#include "xlat/getsockipoptions.h" +#include "xlat/setsockipoptions.h" #include "xlat/sockipv6options.h" +#include "xlat/getsockipv6options.h" +#include "xlat/setsockipv6options.h" #include "xlat/sockipxoptions.h" #include "xlat/sockrawoptions.h" #include "xlat/sockpacketoptions.h" @@ -997,7 +1016,7 @@ SYS_FUNC(socketpair) #include "xlat/socktcpoptions.h" static void -print_sockopt_fd_level_name(struct tcb *tcp, int fd, int level, int name) +print_sockopt_fd_level_name(struct tcb *tcp, int fd, int level, int name, bool is_getsockopt) { printfd(tcp, fd); tprints(", "); @@ -1009,10 +1028,12 @@ print_sockopt_fd_level_name(struct tcb *tcp, int fd, int level, int name) printxval(sockoptions, name, "SO_???"); break; case SOL_IP: - printxval(sockipoptions, name, "IP_???"); + printxvals(name, "IP_???", sockipoptions, + is_getsockopt ? getsockipoptions : setsockipoptions, NULL); break; case SOL_IPV6: - printxval(sockipv6options, name, "IPV6_???"); + printxvals(name, "IPV6_???", sockipv6options, + is_getsockopt ? getsockipv6options : setsockipv6options, NULL); break; case SOL_IPX: printxval(sockipxoptions, name, "IPX_???"); @@ -1172,7 +1193,7 @@ SYS_FUNC(getsockopt) { if (entering(tcp)) { print_sockopt_fd_level_name(tcp, tcp->u_arg[0], - tcp->u_arg[1], tcp->u_arg[2]); + tcp->u_arg[1], tcp->u_arg[2], true); } else { int len; @@ -1435,7 +1456,7 @@ done: SYS_FUNC(setsockopt) { print_sockopt_fd_level_name(tcp, tcp->u_arg[0], - tcp->u_arg[1], tcp->u_arg[2]); + tcp->u_arg[1], tcp->u_arg[2], false); print_setsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]); diff --git a/util.c b/util.c index 81387891..94d9265f 100644 --- a/util.c +++ b/util.c @@ -34,6 +34,7 @@ #include "defs.h" #include #include +#include #ifdef HAVE_SYS_XATTR_H # include #endif @@ -207,14 +208,24 @@ next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits) * Print entry in struct xlat table, if there. */ void -printxval(const struct xlat *xlat, const unsigned int val, const char *dflt) +printxvals(const unsigned int val, const char *dflt, const struct xlat *xlat, ...) { - const char *str = xlookup(xlat, val); + va_list args; - if (str) - tprints(str); - else - tprintf("%#x /* %s */", val, dflt); + va_start(args, xlat); + for (; xlat; xlat = va_arg(args, const struct xlat *)) { + const char *str = xlookup(xlat, val); + + if (str) { + tprints(str); + va_end(args); + return; + } + } + /* No hits -- print raw # instead. */ + tprintf("%#x /* %s */", val, dflt); + + va_end(args); } /* diff --git a/xlat/getsockipoptions.in b/xlat/getsockipoptions.in new file mode 100644 index 00000000..847cec2a --- /dev/null +++ b/xlat/getsockipoptions.in @@ -0,0 +1,29 @@ +/* + * Options specific to getsockopt(SOL_IP). + * Common {g,s}etsockopt(SOL_IP) options + * should be in sockipoptions.in instead. + */ + +ARPT_SO_GET_INFO +ARPT_SO_GET_ENTRIES +ARPT_SO_GET_REVISION_MATCH +ARPT_SO_GET_REVISION_TARGET + +EBT_SO_GET_INFO +EBT_SO_GET_ENTRIES +EBT_SO_GET_INIT_INFO +EBT_SO_GET_INIT_ENTRIES + +IP_VS_SO_GET_VERSION +IP_VS_SO_GET_INFO +IP_VS_SO_GET_SERVICES +IP_VS_SO_GET_SERVICE +IP_VS_SO_GET_DESTS +IP_VS_SO_GET_DEST +IP_VS_SO_GET_TIMEOUT +IP_VS_SO_GET_DAEMON + +IPT_SO_GET_INFO +IPT_SO_GET_ENTRIES +IPT_SO_GET_REVISION_MATCH +IPT_SO_GET_REVISION_TARGET diff --git a/xlat/getsockipv6options.in b/xlat/getsockipv6options.in new file mode 100644 index 00000000..da44a101 --- /dev/null +++ b/xlat/getsockipv6options.in @@ -0,0 +1,10 @@ +/* + * Options specific to getsockopt(SOL_IPV6). + * Common {g,s}etsockopt(SOL_IPV6) options + * should be in sockipv6options.in instead. + */ + +IP6T_SO_GET_INFO +IP6T_SO_GET_ENTRIES +IP6T_SO_GET_REVISION_MATCH +IP6T_SO_GET_REVISION_TARGET diff --git a/xlat/setsockipoptions.in b/xlat/setsockipoptions.in new file mode 100644 index 00000000..878a5945 --- /dev/null +++ b/xlat/setsockipoptions.in @@ -0,0 +1,31 @@ +/* + * Options specific to setsockopt(SOL_IP). + * Common {g,s}etsockopt(SOL_IP) options + * should be in sockipoptions.in instead. + */ + +ARPT_SO_SET_REPLACE +ARPT_SO_SET_ADD_COUNTERS + +EBT_SO_SET_ENTRIES +EBT_SO_SET_COUNTERS + +IP_VS_SO_SET_NONE +IP_VS_SO_SET_INSERT +IP_VS_SO_SET_ADD +IP_VS_SO_SET_EDIT +IP_VS_SO_SET_DEL +IP_VS_SO_SET_FLUSH +IP_VS_SO_SET_LIST +IP_VS_SO_SET_ADDDEST +IP_VS_SO_SET_DELDEST +IP_VS_SO_SET_EDITDEST +IP_VS_SO_SET_TIMEOUT +IP_VS_SO_SET_STARTDAEMON +IP_VS_SO_SET_STOPDAEMON +IP_VS_SO_SET_RESTORE +IP_VS_SO_SET_SAVE +IP_VS_SO_SET_ZERO + +IPT_SO_SET_REPLACE +IPT_SO_SET_ADD_COUNTERS diff --git a/xlat/setsockipv6options.in b/xlat/setsockipv6options.in new file mode 100644 index 00000000..a9eff851 --- /dev/null +++ b/xlat/setsockipv6options.in @@ -0,0 +1,8 @@ +/* + * Options specific to setsockopt(SOL_IPV6). + * Common {g,s}etsockopt(SOL_IPV6) options + * should be in sockipv6options.in instead. + */ + +IP6T_SO_SET_REPLACE +IP6T_SO_SET_ADD_COUNTERS