]> granicus.if.org Git - strace/commitdiff
net: enhance decoding of IP_ADD_MEMBERSHIP et al socket options
authorDmitry V. Levin <ldv@altlinux.org>
Sun, 9 Jul 2017 18:43:34 +0000 (18:43 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 9 Jul 2017 18:43:34 +0000 (18:43 +0000)
* 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.

NEWS
net.c
tests/ip_mreq.c

diff --git a/NEWS b/NEWS
index 50ca640a9026044416a5587ac007db7139b70e6b..8e4c69919c0ef4957a50fe4ae83ef3755d473f98 100644 (file)
--- 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 934e3ecfff491d57cf80d8c99a6001317cd3a3cf..127b70dd86aa72158cb9ddab73668fed2f29d9c7 100644 (file)
--- 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 */
 
index 4bfe00f3c8c16b47f6899ea048e9bfec5dec0723..d21f579405460f33555a1fe93b136aa822a554ce 100644 (file)
 
 # include <stdio.h>
 # include <unistd.h>
+# include <sys/param.h>
 # include <sys/socket.h>
 # include <arpa/inet.h>
 # include <net/if.h>
 
+#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 +++");