Fix decoding of sysctl() when oldval fields are NULL
authorMike Frysinger <vapier@gentoo.org>
Sat, 9 Feb 2013 00:10:07 +0000 (19:10 -0500)
committerDmitry V. Levin <ldv@altlinux.org>
Sat, 9 Feb 2013 01:39:43 +0000 (01:39 +0000)
If you call glibc's syscall wrapper like so:
static int name[] = { CTL_NET, NET_IPV4, NET_IPV4_LOCAL_PORT_RANGE };
int buffer[2] = { 32768, 61000 };
size_t size = sizeof(buffer);
sysctl(name, 3, 0, 0, buffer, size);
(note that oldval/oldlenp are NULL).

The current strace code complains like so:
_sysctl({{CTL_NET, NET_IPV4, NET_IPV4_LOCAL_PORT_RANGE, 38}, 3, process_vm_readv: Bad address
(nil), 0, 0x7fffe23c3960, 8}) = -1 EACCES (Permission denied)

Since passing NULL for the old values is valid, handle that explicitly.
This also simplifies the code a bit by splitting up the handling of the
new and old args so that we only handle the new args once.

Now the output looks like:
_sysctl({{CTL_NET, NET_IPV4, NET_IPV4_LOCAL_PORT_RANGE, 38}, 3, NULL, 0, 0x7fff8c0c91b0, 8) = -1 EACCES (Permission denied)

* system.c (sys_sysctl): Check if info.oldval is NULL first.  Move the
processing of oldlen/info.newval/info.newlen out so they always get
executed.  Fix the format strings so we use %lu for unsigned long rather
than a mix of %ld and %lu.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
system.c

index bc284aa2805978ac4bdc6a9b37225e3ac1159bcd..3d410061182d5f3e058a60c0979ca50de8847a1d 100644 (file)
--- a/system.c
+++ b/system.c
@@ -954,32 +954,32 @@ sys_sysctl(struct tcb *tcp)
                tprintf("}, %d, ", info.nlen);
        } else {
                size_t oldlen = 0;
-               if (umove(tcp, (long)info.oldlenp, &oldlen) >= 0
-                   && info.nlen >= 2
-                   && ((name[0] == CTL_KERN
-                        && (name[1] == KERN_OSRELEASE
-                            || name[1] == KERN_OSTYPE
+               if (info.oldval == NULL) {
+                       tprints("NULL");
+               } else if (umove(tcp, (long)info.oldlenp, &oldlen) >= 0
+                          && info.nlen >= 2
+                          && ((name[0] == CTL_KERN
+                               && (name[1] == KERN_OSRELEASE
+                                   || name[1] == KERN_OSTYPE
 #ifdef KERN_JAVA_INTERPRETER
-                            || name[1] == KERN_JAVA_INTERPRETER
+                                   || name[1] == KERN_JAVA_INTERPRETER
 #endif
 #ifdef KERN_JAVA_APPLETVIEWER
-                            || name[1] == KERN_JAVA_APPLETVIEWER
+                                   || name[1] == KERN_JAVA_APPLETVIEWER
 #endif
-                                )))) {
+                                       )))) {
                        printpath(tcp, (size_t)info.oldval);
-                       tprintf(", %lu, ", (unsigned long)oldlen);
-                       if (info.newval == 0)
-                               tprints("NULL");
-                       else if (syserror(tcp))
-                               tprintf("%p", info.newval);
-                       else
-                               printpath(tcp, (size_t)info.newval);
-                       tprintf(", %ld}", (unsigned long)info.newlen);
                } else {
-                       tprintf("%p, %ld, %p, %ld}",
-                               info.oldval, (unsigned long)oldlen,
-                               info.newval, (unsigned long)info.newlen);
+                       tprintf("%p", info.oldval);
                }
+               tprintf(", %lu, ", (unsigned long)oldlen);
+               if (info.newval == NULL)
+                       tprints("NULL");
+               else if (syserror(tcp))
+                       tprintf("%p", info.newval);
+               else
+                       printpath(tcp, (size_t)info.newval);
+               tprintf(", %lu", (unsigned long)info.newlen);
        }
 
        free(name);