]> granicus.if.org Git - strace/commitdiff
Impove struct cmsghdr decoding
authorDmitry V. Levin <ldv@altlinux.org>
Sat, 24 Jan 2015 15:20:31 +0000 (15:20 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sat, 24 Jan 2015 15:54:33 +0000 (15:54 +0000)
Print all cmsghdr structures in msg_control array,
not just the first one.
Change output format to be consistent with other parts of strace
where structures and arrays are printed.
Implement decoder for SCM_SECURITY message type.

* net.c (print_scm_rights, print_scm_creds, print_scm_security):
New functions.
(printcmsghdr): Use them.  Iterate over all members of the array.
* xlat/scmvals.in: Add SCM_SECURITY.
* tests/scm_rights.c (main): Pass one more descriptor to the receiver.
Set SO_PASSCRED on the receiver part.  Reserve enough space to receive
SCM_CREDENTIALS and SCM_RIGHTS.
* tests/scm_rights-fd.test: Update.

net.c
tests/scm_rights-fd.test
tests/scm_rights.c
xlat/scmvals.in

diff --git a/net.c b/net.c
index c235116c5abe264eac4e4c82c5dd62f04b1ed334..829f3ad849abda74a4119af7138c2d0416efb410 100644 (file)
--- a/net.c
+++ b/net.c
@@ -339,7 +339,10 @@ printsock(struct tcb *tcp, long addr, int addrlen)
 }
 
 #if HAVE_SENDMSG
-#include "xlat/scmvals.h"
+# ifndef SCM_SECURITY
+#  define SCM_SECURITY 0x03
+# endif
+# include "xlat/scmvals.h"
 
 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
 struct cmsghdr32 {
@@ -350,91 +353,152 @@ struct cmsghdr32 {
 #endif
 
 typedef union {
-       char *buf;
+       char *ptr;
        struct cmsghdr *cmsg;
 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
        struct cmsghdr32 *cmsg32;
 #endif
 } union_cmsghdr;
 
-static void
-printcmsghdr(struct tcb *tcp, unsigned long addr, unsigned long len)
+static bool
+print_scm_rights(struct tcb *tcp, size_t cmsg_size, char *ptr, size_t cmsg_len)
 {
-       union_cmsghdr u;
-       size_t cmsg_size;
-       unsigned long cmsg_len;
-       int cmsg_level;
-       int cmsg_type;
+       if (cmsg_size + sizeof(int) > cmsg_len)
+               return false;
+
+       int *fds = (int *) (ptr + cmsg_size);
+       bool seen = false;
+
+       tprints(", [");
+       while ((char *) fds < (ptr + cmsg_len)) {
+               if (seen)
+                       tprints(", ");
+               else
+                       seen = true;
+               printfd(tcp, *fds++);
+       }
+       tprints("]}");
+       return true;
+}
+
+static bool
+print_scm_creds(struct tcb *tcp, size_t cmsg_size, char *ptr, size_t cmsg_len)
+{
+       if (cmsg_size + sizeof(struct ucred) > cmsg_len)
+               return false;
+
+       const struct ucred *uc = (void *) (ptr + cmsg_size);
+
+       tprintf(", {pid=%u, uid=%u, gid=%u}}",
+               (unsigned) uc->pid, (unsigned) uc->uid, (unsigned) uc->gid);
+       return true;
+}
+
+static bool
+print_scm_security(struct tcb *tcp, size_t cmsg_size, char *ptr, size_t cmsg_len)
+{
+       if (cmsg_size + sizeof(char) > cmsg_len)
+               return false;
+
+       const char *label = (const char *) (ptr + cmsg_size);
+       const size_t label_len = cmsg_len - cmsg_size;
+       char *outstr;
+       const size_t alloc_len = 4 * label_len + 3;
 
-       cmsg_size =
+       if (label_len != alloc_len / 4 ||
+           !(outstr = malloc(alloc_len)))
+               return false;
+
+       string_quote(label, outstr, 0, label_len);
+       tprintf(", %s}", outstr);
+
+       free(outstr);
+       return true;
+}
+
+static void
+printcmsghdr(struct tcb *tcp, unsigned long addr, size_t len)
+{
+       const size_t cmsg_size =
 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
                (current_wordsize < sizeof(long)) ? sizeof(struct cmsghdr32) :
 #endif
                        sizeof(struct cmsghdr);
 
-       u.buf = len < cmsg_size ? NULL : malloc(len);
-       if (!u.buf || umoven(tcp, addr, len, u.buf) < 0) {
+       char *buf = len < cmsg_size ? NULL : malloc(len);
+       if (!buf || umoven(tcp, addr, len, buf) < 0) {
                tprintf(", msg_control=%#lx", addr);
-               free(u.buf);
+               free(buf);
                return;
        }
 
-       cmsg_len =
+       union_cmsghdr u = { .ptr = buf };
+
+       tprints(", [");
+       while (len >= cmsg_size) {
+               size_t cmsg_len =
 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
-               (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_len :
+                       (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_len :
 #endif
-                       u.cmsg->cmsg_len;
-       cmsg_level =
+                               u.cmsg->cmsg_len;
+               int cmsg_level =
 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
-               (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_level :
+                       (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_level :
 #endif
-                       u.cmsg->cmsg_level;
-       cmsg_type =
+                               u.cmsg->cmsg_level;
+               int cmsg_type =
 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
-               (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_type :
+                       (current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_type :
 #endif
-                       u.cmsg->cmsg_type;
-
-       tprintf(", {cmsg_len=%lu, cmsg_level=", cmsg_len);
-       printxval(socketlayers, cmsg_level, "SOL_???");
-       tprints(", cmsg_type=");
-
-       if (cmsg_len > len)
-               cmsg_len = len;
-
-       if (cmsg_level == SOL_SOCKET) {
-               printxval(scmvals, cmsg_type, "SCM_???");
-
-               if (cmsg_type == SCM_RIGHTS
-                   && cmsg_size + sizeof(int) <= cmsg_len) {
-                       int *fds = (int *) (u.buf + cmsg_size);
-                       int first = 1;
+                               u.cmsg->cmsg_type;
 
-                       tprints(", {");
-                       while ((char *) fds < (u.buf + cmsg_len)) {
-                               if (!first)
-                                       tprints(", ");
-                               printfd(tcp, *fds++);
-                               first = 0;
+               if (u.ptr != buf)
+                       tprints(", ");
+               tprintf("{cmsg_len=%lu, cmsg_level=", (unsigned long) cmsg_len);
+               printxval(socketlayers, cmsg_level, "SOL_???");
+               tprints(", cmsg_type=");
+
+               if (cmsg_len > len)
+                       cmsg_len = len;
+
+               if (cmsg_level == SOL_SOCKET) {
+                       printxval(scmvals, cmsg_type, "SCM_???");
+                       switch (cmsg_type) {
+                       case SCM_RIGHTS:
+                               if (print_scm_rights(tcp, cmsg_size, u.ptr, cmsg_len))
+                                       goto next_cmsg;
+                               break;
+                       case SCM_CREDENTIALS:
+                               if (print_scm_creds(tcp, cmsg_size, u.ptr, cmsg_len))
+                                       goto next_cmsg;
+                               break;
+                       case SCM_SECURITY:
+                               if (print_scm_security(tcp, cmsg_size, u.ptr, cmsg_len))
+                                       goto next_cmsg;
+                               break;
                        }
-                       tprints("}}");
-                       free(u.buf);
-                       return;
+               } else {
+                       tprintf("%u", cmsg_type);
                }
-               if (cmsg_type == SCM_CREDENTIALS
-                   && cmsg_size + sizeof(struct ucred) <= cmsg_len) {
-                       struct ucred *uc = (void *) (u.buf + cmsg_size);
-
-                       tprintf("{pid=%ld, uid=%ld, gid=%ld}}",
-                               (long)uc->pid, (long)uc->uid, (long)uc->gid);
-                       free(u.buf);
-                       return;
+               tprints(", ...}");
+next_cmsg:
+               if (cmsg_len < cmsg_size) {
+                       len -= cmsg_size;
+                       break;
                }
-       } else {
-               tprintf("%u", cmsg_type);
+               cmsg_len = (cmsg_len + current_wordsize - 1) &
+                       (size_t) ~(current_wordsize - 1);
+               if (cmsg_len >= len) {
+                       len = 0;
+                       break;
+               }
+               u.ptr += cmsg_len;
+               len -= cmsg_len;
        }
-       free(u.buf);
-       tprints(", ...}");
+       if (len)
+               tprints(", ...");
+       tprints("]");
+       free(buf);
 }
 
 static void
index ecf447509632465b35d34f0f3cf51c1bde66649a..c4d94509c5f7bf75f84ec768508dfdbbf7eea69a 100755 (executable)
@@ -36,7 +36,11 @@ grep_log()
        }
 }
 
-grep_log sendmsg '\(1<socket:\[[0-9]+\]>, \{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x00\\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\)=\[\{"\\x00\\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]*'
+n='[1-9][0-9]*'
+msg='\{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x00\\x00\\x00\\x00[^"]*", '"$n"'\}\], msg_controllen='"$n"
+rights='\{cmsg_len='"$n"', cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, \[3</dev/null>, 4</dev/zero>\]\}'
+creds='\{cmsg_len='"$n"', cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, \{pid='"$n"', uid=[0-9]+, gid=[0-9]+\}\}'
+grep_log sendmsg '\(1<socket:\[[0-9]+\]>, '"$msg"', \['"$rights"'\], msg_flags=0\}, 0\) += '"$n"
+grep_log recvmsg '\(0<socket:\[[0-9]+\]>, '"$msg"', \['"$creds"', '"$rights"'\], msg_flags=0\}, 0\) += '"$n"
 
 exit 0
index 0cced9becbcebc7ab644bd966f229df44f04c7f9..fa6e8f046a3b9f37578c9fc178746c091ddca233 100644 (file)
@@ -9,11 +9,6 @@
 
 int main(void)
 {
-       union {
-               struct cmsghdr cmsghdr;
-               char buf[CMSG_SPACE(sizeof(int))];
-       } control = {};
-
        int fd;
        int data = 0;
        struct iovec iov = {
@@ -21,19 +16,14 @@ int main(void)
                .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);
+       int one = 1;
+       assert(setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) == 0);
 
        pid_t pid = fork();
        assert(pid >= 0);
@@ -43,14 +33,29 @@ int main(void)
                assert(dup2(sv[1], 1) == 1);
                assert(close(sv[1]) == 0);
 
-               assert((fd = open("/dev/null", O_RDWR)) == 3);
+               int fds[2];
+               assert((fds[0] = open("/dev/null", O_RDWR)) == 3);
+               assert((fds[1] = open("/dev/zero", O_RDONLY)) == 4);
+
+               union {
+                       struct cmsghdr cmsg;
+                       char buf[CMSG_LEN(sizeof(fds))];
+               } control = {
+                       .cmsg = {
+                               .cmsg_level = SOL_SOCKET,
+                               .cmsg_type = SCM_RIGHTS,
+                               .cmsg_len = CMSG_LEN(sizeof(fds))
+                       }
+               };
 
-               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;
+               memcpy(CMSG_DATA(&control.cmsg), fds, sizeof(fds));
+
+               struct msghdr mh = {
+                       .msg_iov = &iov,
+                       .msg_iovlen = 1,
+                       .msg_control = &control,
+                       .msg_controllen = sizeof(control)
+               };
 
                assert(sendmsg(1, &mh, 0) == sizeof(iov));
                assert(close(1) == 0);
@@ -63,6 +68,15 @@ int main(void)
                assert(dup2(sv[0], 0) == 0);
                assert(close(sv[0]) == 0);
 
+               struct cmsghdr control[4];
+
+               struct msghdr mh = {
+                       .msg_iov = &iov,
+                       .msg_iovlen = 1,
+                       .msg_control = control,
+                       .msg_controllen = sizeof(control)
+               };
+
                assert(recvmsg(0, &mh, 0) == sizeof(iov));
                assert(close(0) == 0);
        }
index 04322e84e7c5f3e965fa25024b1174fa24632be6..86d9a15b0134ddd0f286c4a9c0431ecfc8995518 100644 (file)
@@ -1,2 +1,3 @@
 SCM_RIGHTS
 SCM_CREDENTIALS
+SCM_SECURITY