]> granicus.if.org Git - strace/commitdiff
net: accept arbitrary option length for getsockopt's SO_LINGER
authorDmitry V. Levin <ldv@altlinux.org>
Sat, 8 Jul 2017 14:57:44 +0000 (14:57 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sat, 8 Jul 2017 14:57:44 +0000 (14:57 +0000)
* net.c (print_linger): Rename to print_set_linger.
(print_setsockopt): Replace print_linger with print_set_linger.
(print_get_linger): New function that accepts arbitrary option length
to match the kernel behaviour.
(print_getsockopt): Replace print_linger with print_get_linger.
* NEWS: Mention this.

NEWS
net.c

diff --git a/NEWS b/NEWS
index 70f9fa2f699a954fa1cb395e1f1be0b9c9b82f40..4cb22a3f68ad5a4c23a6145a54c16809a7b6b2c1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ Noteworthy changes in release ?.?? (????-??-??)
 
 * Improvements
   * Enhanced decoding of optlen argument of getsockopt syscall.
+  * Enhanced decoding of SO_LINGER option of getsockopt and setsockopt syscalls.
 
 Noteworthy changes in release 4.18 (2017-07-05)
 ===============================================
diff --git a/net.c b/net.c
index 5e20abc6ddf477d104d33337abf870d7ed864959..58a1bbf3c905f50a162941984e8975053d94ac20 100644 (file)
--- a/net.c
+++ b/net.c
@@ -489,8 +489,8 @@ print_sockopt_fd_level_name(struct tcb *tcp, int fd, unsigned int level,
 }
 
 static void
-print_linger(struct tcb *const tcp, const kernel_ulong_t addr,
-            const unsigned int len)
+print_set_linger(struct tcb *const tcp, const kernel_ulong_t addr,
+                const unsigned int len)
 {
        struct linger linger;
 
@@ -505,6 +505,32 @@ print_linger(struct tcb *const tcp, const kernel_ulong_t addr,
        tprints("}");
 }
 
+static void
+print_get_linger(struct tcb *const tcp, const kernel_ulong_t addr,
+                unsigned int len)
+{
+       struct linger linger;
+
+       if (len < sizeof(linger)) {
+               if (len != sizeof(linger.l_onoff)) {
+                       printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
+                       return;
+               }
+       } else {
+               len = sizeof(linger);
+       }
+
+       if (umoven(tcp, addr, len, &linger) < 0) {
+               printaddr(addr);
+               return;
+       }
+
+       PRINT_FIELD_D("{", linger, l_onoff);
+       if (len == sizeof(linger))
+               PRINT_FIELD_D(", ", linger, l_linger);
+       tprints("}");
+}
+
 #ifdef SO_PEERCRED
 static void
 print_ucred(struct tcb *const tcp, const kernel_ulong_t addr, const int len)
@@ -573,7 +599,7 @@ print_getsockopt(struct tcb *const tcp, const unsigned int level,
        case SOL_SOCKET:
                switch (name) {
                case SO_LINGER:
-                       print_linger(tcp, addr, len);
+                       print_get_linger(tcp, addr, len);
                        return;
 #ifdef SO_PEERCRED
                case SO_PEERCRED:
@@ -771,7 +797,7 @@ print_setsockopt(struct tcb *const tcp, const unsigned int level,
        case SOL_SOCKET:
                switch (name) {
                case SO_LINGER:
-                       print_linger(tcp, addr, len);
+                       print_set_linger(tcp, addr, len);
                        return;
                }
                break;