]> granicus.if.org Git - strace/commitdiff
Decode file descriptors passed via SCM_RIGHTS control messages
authorDmitry V. Levin <ldv@altlinux.org>
Thu, 29 May 2014 21:35:34 +0000 (21:35 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Fri, 30 May 2014 00:20:53 +0000 (00:20 +0000)
* net.c (printcmsghdr): Print descriptors from SCM_RIGHTS control
messages using printfd.
* tests/scm_rights.c: New file.
* tests/scm_rights-fd.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add scm_rights.
(TESTS): Add scm_rights-fd.test.
* tests/.gitignore: Add scm_rights and uio.

net.c
tests/.gitignore
tests/Makefile.am
tests/scm_rights-fd.test [new file with mode: 0755]
tests/scm_rights.c [new file with mode: 0644]

diff --git a/net.c b/net.c
index a466efe0519d87fbe6c638de83a10e5551e57a86..e0b225e2319981b2a3dd431e3effe40f95772b27 100644 (file)
--- a/net.c
+++ b/net.c
@@ -1574,7 +1574,7 @@ printcmsghdr(struct tcb *tcp, unsigned long addr, unsigned long len)
                        while ((char *) fds < ((char *) cmsg + cmsg_len)) {
                                if (!first)
                                        tprints(", ");
-                               tprintf("%d", *fds++);
+                               printfd(tcp, *fds++);
                                first = 0;
                        }
                        tprints("}}");
index c400a79b88556559dd0fa752d91857d43fa079bf..7a87842d73f25e43839ff38f5541b4bdb12cdd2c 100644 (file)
@@ -1,6 +1,8 @@
 net-accept-connect
+scm_rights
 set_ptracer_any
 sigaction
+uio
 *.log
 *.log.*
 *.o
index e65312c2d96095e1b018940b90b0ea6cfff1746e..b561ce3e4add14821bf3b5b68aae52c632478528 100644 (file)
@@ -2,7 +2,12 @@
 
 AM_CFLAGS = $(WARN_CFLAGS)
 
-check_PROGRAMS = net-accept-connect set_ptracer_any sigaction uio
+check_PROGRAMS = \
+       net-accept-connect \
+       scm_rights \
+       set_ptracer_any \
+       sigaction \
+       uio
 
 uio_CFLAGS = $(AM_CFLAGS) -D_FILE_OFFSET_BITS=64
 
@@ -10,6 +15,7 @@ TESTS = \
        ptrace_setoptions.test \
        strace-f.test \
        qual_syscall.test \
+       scm_rights-fd.test \
        sigaction.test \
        stat.test \
        net.test \
diff --git a/tests/scm_rights-fd.test b/tests/scm_rights-fd.test
new file mode 100755 (executable)
index 0000000..e0b8f4a
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Check how SCM_RIGHTS control messages are decoded in -y mode.
+
+. "${srcdir=.}/init.sh"
+
+# strace -y is implemented using /proc/$pid/fd
+[ -d /proc/self/fd/ ] ||
+       framework_skip_ '/proc/self/fd/ is not available'
+
+check_prog grep
+check_prog rm
+
+rm -f $LOG.*
+
+./scm_rights ||
+       fail_ 'scm_rights failed'
+
+args="-tt -ff -y -xx -enetwork -o $LOG ./scm_rights"
+$STRACE $args ||
+       fail_ "$STRACE $args failed"
+
+"$srcdir"/../strace-log-merge $LOG > $LOG || {
+       cat $LOG
+       fail_ 'strace-log-merge failed'
+}
+rm -f $LOG.*
+
+grep_log()
+{
+       local syscall="$1"; shift
+       local prefix='[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +'
+
+       LC_ALL=C grep -E -x "$prefix$syscall$*" $LOG > /dev/null || {
+               cat $LOG
+               fail_ "$STRACE $args failed to trace \"$syscall\" properly"
+       }
+}
+
+grep_log sendmsg '\(1<socket:\[[0-9]+\]>, \{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x03\\x00\\x00\\x00[^"]*", [1-9][0-9]*\}\], msg_controllen=[1-9][0-9]*, \{cmsg_len=[1-9][0-9]*, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, \{3</dev/null>\}\}, msg_flags=0\}, 0\) += [1-9][0-9]*'
+grep_log recvmsg '\(0<socket:\[[0-9]+\]>, \{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x03\\x00\\x00\\x00[^"]*", [1-9][0-9]*\}\], msg_controllen=[1-9][0-9]*, \{cmsg_len=[1-9][0-9]*, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, \{3</dev/null>\}\}, msg_flags=0\}, 0\) += [1-9][0-9]*'
+
+exit 0
diff --git a/tests/scm_rights.c b/tests/scm_rights.c
new file mode 100644 (file)
index 0000000..9522ba1
--- /dev/null
@@ -0,0 +1,70 @@
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+int main(void)
+{
+       union {
+               struct cmsghdr cmsghdr;
+               char buf[CMSG_SPACE(sizeof(int))];
+       } control = {};
+
+       int fd;
+       struct iovec iov = {
+               .iov_base = &fd,
+               .iov_len = sizeof(iov)
+       };
+
+       struct msghdr mh = {
+               .msg_iov = &iov,
+               .msg_iovlen = 1,
+               .msg_control = &control,
+               .msg_controllen = sizeof(control)
+       };
+
+       while ((fd = open("/dev/null", O_RDWR)) < 3)
+               assert(fd >= 0);
+       (void) close(3);
+
+       int sv[2];
+       assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
+
+       pid_t pid = fork();
+       assert(pid >= 0);
+
+       if (pid) {
+               assert(close(sv[0]) == 0);
+               assert(dup2(sv[1], 1) == 1);
+               assert(close(sv[1]) == 0);
+
+               assert((fd = open("/dev/null", O_RDWR)) == 3);
+
+               struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
+               cmsg->cmsg_level = SOL_SOCKET;
+               cmsg->cmsg_type = SCM_RIGHTS;
+               cmsg->cmsg_len = CMSG_LEN(sizeof fd);
+               memcpy(CMSG_DATA(cmsg), &fd, sizeof fd);
+               mh.msg_controllen = cmsg->cmsg_len;
+
+               assert(sendmsg(1, &mh, 0) == sizeof(iov));
+               assert(close(1) == 0);
+
+                int status;
+               assert(waitpid(pid, &status, 0) == pid);
+               assert(status == 0);
+       } else {
+               assert(close(sv[1]) == 0);
+               assert(dup2(sv[0], 0) == 0);
+               assert(close(sv[0]) == 0);
+
+               assert(recvmsg(0, &mh, 0) == sizeof(iov));
+               assert(close(0) == 0);
+       }
+
+       return 0;
+}