From: Dmitry V. Levin Date: Sun, 9 Jul 2017 18:43:34 +0000 (+0000) Subject: net: enhance decoding of IP_ADD_MEMBERSHIP et al socket options X-Git-Tag: v4.19~293 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=492517e35f7a73d9e352710324bd0ca3f6583b05;p=strace net: enhance decoding of IP_ADD_MEMBERSHIP et al socket options * net.c (print_mreq, print_mreq6): Treat negative option length as invalid to match the kernel behaviour. When the option length is invalid, print the address. * NEWS: Mention it. * tests/ip_mreq.c (main): Check it. Update expected output. --- diff --git a/NEWS b/NEWS index 50ca640a..8e4c6991 100644 --- a/NEWS +++ b/NEWS @@ -3,8 +3,11 @@ Noteworthy changes in release ?.?? (????-??-??) * Improvements * Enhanced decoding of optlen argument of getsockopt syscall. - * Enhanced decoding of SO_LINGER and SO_PEERCRED options - of getsockopt and setsockopt syscalls. + * Enhanced decoding of SO_LINGER option of getsockopt and setsockopt syscalls. + * Enhanced decoding of SO_PEERCRED option of getsockopt syscall. + * Enhanced decoding of IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, + IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_JOIN_ANYCAST, + and IPV6_LEAVE_ANYCAST options of setsockopt syscall. * Implemented decoding of linux socket filter programs specified for SO_ATTACH_FILTER and SO_ATTACH_REUSEPORT_CBPF socket options. diff --git a/net.c b/net.c index 934e3ecf..127b70dd 100644 --- a/net.c +++ b/net.c @@ -651,40 +651,34 @@ SYS_FUNC(getsockopt) #ifdef IP_ADD_MEMBERSHIP static void print_mreq(struct tcb *const tcp, const kernel_ulong_t addr, - const unsigned int len) + const int len) { struct ip_mreq mreq; - if (len < sizeof(mreq)) { - printstrn(tcp, addr, len); - return; + if (len < (int) sizeof(mreq)) { + printaddr(addr); + } else if (!umove_or_printaddr(tcp, addr, &mreq)) { + PRINT_FIELD_INET4_ADDR("{", mreq, imr_multiaddr); + PRINT_FIELD_INET4_ADDR(", ", mreq, imr_interface); + tprints("}"); } - if (umove_or_printaddr(tcp, addr, &mreq)) - return; - - PRINT_FIELD_INET4_ADDR("{", mreq, imr_multiaddr); - PRINT_FIELD_INET4_ADDR(", ", mreq, imr_interface); - tprints("}"); } #endif /* IP_ADD_MEMBERSHIP */ #ifdef IPV6_ADD_MEMBERSHIP static void print_mreq6(struct tcb *const tcp, const kernel_ulong_t addr, - const unsigned int len) + const int len) { struct ipv6_mreq mreq; - if (len < sizeof(mreq)) { - printstrn(tcp, addr, len); - return; + if (len < (int) sizeof(mreq)) { + printaddr(addr); + } else if (!umove_or_printaddr(tcp, addr, &mreq)) { + PRINT_FIELD_INET_ADDR("{", mreq, ipv6mr_multiaddr, AF_INET6); + PRINT_FIELD_IFINDEX(", ", mreq, ipv6mr_interface); + tprints("}"); } - if (umove_or_printaddr(tcp, addr, &mreq)) - return; - - PRINT_FIELD_INET_ADDR("{", mreq, ipv6mr_multiaddr, AF_INET6); - PRINT_FIELD_IFINDEX(", ", mreq, ipv6mr_interface); - tprints("}"); } #endif /* IPV6_ADD_MEMBERSHIP */ diff --git a/tests/ip_mreq.c b/tests/ip_mreq.c index 4bfe00f3..d21f5794 100644 --- a/tests/ip_mreq.c +++ b/tests/ip_mreq.c @@ -34,17 +34,18 @@ # include # include +# include # include # include # include +#define multi4addr "224.0.0.3" +#define multi6addr "ff01::c" +#define interface "127.0.0.1" + int main(void) { - static const char multi4addr[] = "224.0.0.3"; - static const char multi6addr[] = "ff01::c"; - static const char interface[] = "127.0.0.1"; - TAIL_ALLOC_OBJECT_CONST_PTR(struct ip_mreq, m4); TAIL_ALLOC_OBJECT_CONST_PTR(struct ipv6_mreq, m6); unsigned int i; @@ -63,87 +64,91 @@ main(void) perror_msg_and_skip("socket"); struct { - int level; - const char *str_level; - int optname; - const char *str_optname; - void *optval; - unsigned int optsize; - } short_any[] = { + const int level; + const char *const str_level; + const int name; + const char *str_name; + const void *const val; + unsigned int size; + const char *const addr; + } opts[] = { { ARG_STR(SOL_IP), ARG_STR(IP_ADD_MEMBERSHIP), - m4, sizeof(*m4) + m4, sizeof(*m4), + "{imr_multiaddr=inet_addr(\"" multi4addr + "\"), imr_interface=inet_addr(\"" interface "\")}" }, { ARG_STR(SOL_IP), ARG_STR(IP_DROP_MEMBERSHIP), - m4, sizeof(*m4) + m4, sizeof(*m4), + "{imr_multiaddr=inet_addr(\"" multi4addr + "\"), imr_interface=inet_addr(\"" interface "\")}" }, { ARG_STR(SOL_IPV6), ARG_STR(IPV6_ADD_MEMBERSHIP), - m6, sizeof(*m6) + m6, sizeof(*m6), + "{inet_pton(AF_INET6, \"" multi6addr + "\", &ipv6mr_multiaddr)" + ", ipv6mr_interface=if_nametoindex(\"lo\")}" }, { ARG_STR(SOL_IPV6), ARG_STR(IPV6_DROP_MEMBERSHIP), - m6, sizeof(*m6) + m6, sizeof(*m6), + "{inet_pton(AF_INET6, \"" multi6addr + "\", &ipv6mr_multiaddr)" + ", ipv6mr_interface=if_nametoindex(\"lo\")}" }, { ARG_STR(SOL_IPV6), ARG_STR(IPV6_JOIN_ANYCAST), - m6, sizeof(*m6) + m6, sizeof(*m6), + "{inet_pton(AF_INET6, \"" multi6addr + "\", &ipv6mr_multiaddr)" + ", ipv6mr_interface=if_nametoindex(\"lo\")}" }, { ARG_STR(SOL_IPV6), ARG_STR(IPV6_LEAVE_ANYCAST), - m6, sizeof(*m6) + m6, sizeof(*m6), + "{inet_pton(AF_INET6, \"" multi6addr + "\", &ipv6mr_multiaddr)" + ", ipv6mr_interface=if_nametoindex(\"lo\")}" } }; - for (i = 0; i < ARRAY_SIZE(short_any); ++i) { - rc = setsockopt(0, short_any[i].level, short_any[i].optname, - short_any[i].optval, 1); - printf("setsockopt(0, %s, %s, \"\\%hho\", 1) = %s\n", - short_any[i].str_level, short_any[i].str_optname, - *(unsigned char *) short_any[i].optval, - sprintrc(rc)); - - rc = setsockopt(0, short_any[i].level, short_any[i].optname, - short_any[i].optval + 1, short_any[i].optsize); + for (i = 0; i < ARRAY_SIZE(opts); ++i) { + /* optlen < 0, EINVAL */ + rc = setsockopt(0, opts[i].level, opts[i].name, + opts[i].val, -1); + printf("setsockopt(0, %s, %s, %p, -1) = %s\n", + opts[i].str_level, opts[i].str_name, + opts[i].val, sprintrc(rc)); + + /* optlen < sizeof(struct), EINVAL */ + rc = setsockopt(0, opts[i].level, opts[i].name, + opts[i].val, opts[i].size - 1); printf("setsockopt(0, %s, %s, %p, %u) = %s\n", - short_any[i].str_level, short_any[i].str_optname, - short_any[i].optval + 1, short_any[i].optsize, - sprintrc(rc)); - } - - struct { - int optname; - const char *str_optname; - } long_ip[] = { - { ARG_STR(IP_ADD_MEMBERSHIP) }, - { ARG_STR(IP_DROP_MEMBERSHIP) } - }, long_ipv6[] = { - { ARG_STR(IPV6_ADD_MEMBERSHIP) }, - { ARG_STR(IPV6_DROP_MEMBERSHIP) }, - { ARG_STR(IPV6_JOIN_ANYCAST) }, - { ARG_STR(IPV6_LEAVE_ANYCAST) } - }; + opts[i].str_level, opts[i].str_name, + opts[i].val, opts[i].size - 1, sprintrc(rc)); - for (i = 0; i < ARRAY_SIZE(long_ip); ++i) { - rc = setsockopt(0, SOL_IP, long_ip[i].optname, - m4, sizeof(*m4)); - printf("setsockopt(0, SOL_IP, %s" - ", {imr_multiaddr=inet_addr(\"%s\")" - ", imr_interface=inet_addr(\"%s\")}, %u) = %s\n", - long_ip[i].str_optname, multi4addr, - interface, (unsigned) sizeof(*m4), sprintrc(rc)); - } - - for (i = 0; i < ARRAY_SIZE(long_ipv6); ++i) { - rc = setsockopt(0, SOL_IPV6, long_ipv6[i].optname, - m6, sizeof(*m6)); - printf("setsockopt(0, SOL_IPV6, %s" - ", {inet_pton(AF_INET6, \"%s\", &ipv6mr_multiaddr)" - ", ipv6mr_interface=if_nametoindex(\"lo\")}" - ", %u) = %s\n", - long_ipv6[i].str_optname, multi6addr, - (unsigned) sizeof(*m6), sprintrc(rc)); + /* optval EFAULT */ + rc = setsockopt(0, opts[i].level, opts[i].name, + opts[i].val + 1, opts[i].size); + printf("setsockopt(0, %s, %s, %p, %u) = %s\n", + opts[i].str_level, opts[i].str_name, + opts[i].val + 1, opts[i].size, sprintrc(rc)); + + /* classic */ + rc = setsockopt(0, opts[i].level, opts[i].name, + opts[i].val, opts[i].size); + printf("setsockopt(0, %s, %s, %s, %u) = %s\n", + opts[i].str_level, opts[i].str_name, + opts[i].addr, opts[i].size, sprintrc(rc)); + + /* optlen > sizeof(struct), shortened */ + rc = setsockopt(0, opts[i].level, opts[i].name, + opts[i].val, INT_MAX); + printf("setsockopt(0, %s, %s, %s, %u) = %s\n", + opts[i].str_level, opts[i].str_name, + opts[i].addr, INT_MAX, sprintrc(rc)); } puts("+++ exited with 0 +++");