printuid: fix uid_t decoding on 64-bit architectures
authorDmitry V. Levin <ldv@altlinux.org>
Sat, 13 Dec 2014 18:24:13 +0000 (18:24 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sun, 14 Dec 2014 03:54:04 +0000 (03:54 +0000)
It was not a good idea to treat uid_t as a long int type because
the latter is twice larger than uid_t on 64-bit architectures.

* defs.h (printuid): Change uid argument type from "unsigned long"
to "unsigned int".
* util.c (printuid): Likewise.  When uid equals to -1, print "-1".
* tests/uid.awk: New file.
* tests/uid.c: New file.
* tests/uid32.c: Likewise.
* tests/uid.test: New test.
* tests/uid32.test: Likewise.
* tests/Makefile.am (CHECK_PROGRAMS): Add uid and uid32.
(TESTS): Add uid.test and uid32.test.
(EXTRA_DIST): Add uid.awk.
* tests/.gitignore: Add uid and uid32.

defs.h
tests/.gitignore
tests/Makefile.am
tests/uid.awk [new file with mode: 0644]
tests/uid.c [new file with mode: 0644]
tests/uid.test [new file with mode: 0755]
tests/uid32.c [new file with mode: 0644]
tests/uid32.test [new file with mode: 0755]
util.c

diff --git a/defs.h b/defs.h
index ddffbf209a95be2a39177c810e69e20627978858..92b35723fcd98743615d7036df6d56468a1794c2 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -706,7 +706,7 @@ extern void printrusage(struct tcb *, long);
 #ifdef ALPHA
 extern void printrusage32(struct tcb *, long);
 #endif
-extern void printuid(const char *, unsigned long);
+extern void printuid(const char *, const unsigned int);
 extern void print_sigset_addr_len(struct tcb *, long, long);
 extern void printsignal(int);
 extern void tprint_iov(struct tcb *, unsigned long, unsigned long, int decode_iov);
index aa808c20d278ccadb8badaf0520fc899587b86df..ef0545eff6daf09074da7b91ca12250b773e9f1f 100644 (file)
@@ -1,3 +1,4 @@
+caps
 inet-accept-connect-send-recv
 mmsg
 net-accept-connect
@@ -7,6 +8,8 @@ set_ptracer_any
 sigaction
 stack-fcall
 statfs
+uid
+uid32
 uio
 *.log
 *.log.*
index 0784f24eae119a1eade1c8e032f8fd1275887e42..85fe9c6fe8cbbd75cb81118d3a4b39b186ebc21f 100644 (file)
@@ -13,6 +13,8 @@ check_PROGRAMS = \
        sigaction \
        stack-fcall \
        statfs \
+       uid \
+       uid32 \
        uio
 
 statfs_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64
@@ -34,6 +36,8 @@ TESTS = \
        net.test \
        net-fd.test \
        net-yy.test \
+       uid.test \
+       uid32.test \
        uio.test \
        count.test \
        detach-sleeping.test \
@@ -52,6 +56,7 @@ EXTRA_DIST = init.sh run.sh \
             net-yy-accept.awk \
             net-yy-connect.awk \
             sigaction.awk \
+            uid.awk \
             $(TESTS)
 
 CLEANFILES = $(TESTS:=.tmp)
diff --git a/tests/uid.awk b/tests/uid.awk
new file mode 100644 (file)
index 0000000..7c431aa
--- /dev/null
@@ -0,0 +1,86 @@
+BEGIN {
+  ok = 0
+  fail = 0
+  r_uid = "(0|[1-9][0-9]*)"
+  r_getuid = "^getuid" suffix "\\(\\)[[:space:]]+= " r_uid "$"
+  r_setuid = "^/$"
+  r_getresuid = "^/$"
+  r_setreuid = "^/$"
+  r_setresuid = "^/$"
+  r_chown = "^/$"
+  s_last = "/"
+}
+
+ok == 1 {
+  fail = 1
+  next
+}
+
+$0 == s_last {
+  ok = 1
+  next
+}
+
+{
+  if (match($0, r_getuid, a)) {
+    r_uid = a[1]
+    r_setuid = "^setuid" suffix "\\(" r_uid "\\)[[:space:]]+= 0$"
+    next
+  }
+  if (match($0, r_setuid)) {
+    r_getresuid = "^getresuid" suffix "\\(\\[" r_uid "\\], \\[" r_uid "\\], \\[" r_uid "\\]\\)[[:space:]]+= 0$"
+    next
+  }
+  if (match($0, r_getresuid)) {
+    r_setreuid = "^setreuid" suffix "\\(-1, -1\\)[[:space:]]+= 0$"
+    next
+  }
+  if (match($0, r_setreuid)) {
+    r_setresuid = "^setresuid" suffix "\\(-1, " r_uid ", -1\\)[[:space:]]+= 0$"
+    next
+  }
+  if (match($0, r_setresuid)) {
+    r_chown = "^chown" suffix "\\(\".\", -1, -1\\)[[:space:]]+= 0$"
+    next
+  }
+  if (match($0, r_chown)) {
+    s_last = "+++ exited with 0 +++"
+    next
+  }
+  next
+}
+
+END {
+  if (fail) {
+    print "Unexpected output after exit"
+    exit 1
+  }
+  if (ok)
+    exit 0
+  if (r_setuid == "^/$") {
+    print "getuid doesn't match"
+    exit 1
+  }
+  if (r_getresuid == "^/$") {
+    print "setuid doesn't match"
+    exit 1
+  }
+  if (r_setreuid == "^/$") {
+    print "getresuid doesn't match"
+    exit 1
+  }
+  if (r_setresuid == "^/$") {
+    print "setreuid doesn't match"
+    exit 1
+  }
+  if (r_chown == "^/$") {
+    print "setresuid doesn't match"
+    exit 1
+  }
+  if (s_last == "/") {
+    print "chown doesn't match"
+    exit 1
+  }
+  print "The last line doesn't match"
+  exit 1
+}
diff --git a/tests/uid.c b/tests/uid.c
new file mode 100644 (file)
index 0000000..b4b9813
--- /dev/null
@@ -0,0 +1,29 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <assert.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+int
+main(void)
+{
+#if defined(__NR_getuid) \
+ && defined(__NR_setuid) \
+ && defined(__NR_getresuid) \
+ && defined(__NR_setreuid) \
+ && defined(__NR_setresuid) \
+ && defined(__NR_chown)
+       uid_t r, e, s;
+
+       e = syscall(__NR_getuid);
+       assert(syscall(__NR_setuid, e) == 0);
+       assert(syscall(__NR_getresuid, &r, &e, &s) == 0);
+       assert(syscall(__NR_setreuid, -1, -1L) == 0);
+       assert(syscall(__NR_setresuid, -1, e, -1L) == 0);
+       assert(syscall(__NR_chown, ".", -1, -1L) == 0);
+       return 0;
+#else
+       return 77;
+#endif
+}
diff --git a/tests/uid.test b/tests/uid.test
new file mode 100755 (executable)
index 0000000..02fea2a
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+# Check uid decoding.
+
+. "${srcdir=.}/init.sh"
+
+check_prog awk
+
+s="${uid_syscall_suffix-}"
+w="${uid_t_size-}"
+uid="uid$s$w"
+./"$uid" || {
+       if [ $? -eq 77 ]; then
+               framework_skip_ "some uid$s or uid${w}_t syscalls are not available"
+       else
+               fail_ "$uid failed"
+       fi
+}
+
+syscalls="getuid$s,setuid$s,getresuid$s,setreuid$s,setresuid$s,chown$s"
+args="-e trace=$syscalls"
+$STRACE -o "$LOG" $args ./"$uid"|| {
+       cat "$LOG"
+       fail_ "$STRACE $args ./$uid failed"
+}
+
+awk -f "$srcdir"/uid.awk -v suffix="$s" "$LOG" || {
+       cat "$LOG"
+       fail_ 'unexpected output'
+}
+
+exit 0
diff --git a/tests/uid32.c b/tests/uid32.c
new file mode 100644 (file)
index 0000000..94301b7
--- /dev/null
@@ -0,0 +1,29 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <assert.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+int
+main(void)
+{
+#if defined(__NR_getuid32) \
+ && defined(__NR_setuid32) \
+ && defined(__NR_getresuid32) \
+ && defined(__NR_setreuid32) \
+ && defined(__NR_setresuid32) \
+ && defined(__NR_chown32)
+       uid_t r, e, s;
+
+       e = syscall(__NR_getuid32);
+       assert(syscall(__NR_setuid32, e) == 0);
+       assert(syscall(__NR_getresuid32, &r, &e, &s) == 0);
+       assert(syscall(__NR_setreuid32, -1, -1L) == 0);
+       assert(syscall(__NR_setresuid32, -1, e, -1L) == 0);
+       assert(syscall(__NR_chown32, ".", -1, -1L) == 0);
+       return 0;
+#else
+       return 77;
+#endif
+}
diff --git a/tests/uid32.test b/tests/uid32.test
new file mode 100755 (executable)
index 0000000..82ba9b7
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Check uid32 decoding.
+
+uid_syscall_suffix=32
+
+. "${srcdir=.}/uid.test"
diff --git a/util.c b/util.c
index 71e921d02cfda2bb4ad4bb307e153aaa5084cc4b..3201b09d6f00e80a4439caaf41863ac532db44eb 100644 (file)
--- a/util.c
+++ b/util.c
@@ -504,9 +504,12 @@ printfd(struct tcb *tcp, int fd)
 }
 
 void
-printuid(const char *text, unsigned long uid)
+printuid(const char *text, const unsigned int uid)
 {
-       tprintf(((long) uid == -1) ? "%s%ld" : "%s%lu", text, uid);
+       if ((unsigned int) -1 == uid)
+               tprintf("%s-1", text);
+       else
+               tprintf("%s%u", text, uid);
 }
 
 /*