]> granicus.if.org Git - strace/blobdiff - tests/so_peercred.c
net: enhance decoding of getsockopt(SO_PEERCRED)
[strace] / tests / so_peercred.c
index 6eac8467b5c851f124ea2f9d5f2dc09bf73b7668..e4fab6d4f6b38d9b24e1842d3f24a0c7b09bdcea 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <stddef.h>
 #include <stdio.h>
+#include <string.h>
 #include <sys/socket.h>
 #include <unistd.h>
 
@@ -75,6 +76,25 @@ main(void)
        TAIL_ALLOC_OBJECT_CONST_PTR(struct ucred, peercred);
        TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
 
+       const unsigned int sizeof_pid = sizeof(peercred->pid);
+       struct ucred *const pid = tail_alloc(sizeof_pid);
+
+       const unsigned int sizeof_pid_truncated = sizeof_pid - 1;
+       struct ucred *const pid_truncated =
+               tail_alloc(sizeof_pid_truncated);
+
+       const unsigned int sizeof_uid = offsetofend(struct ucred, uid);
+       struct ucred *const uid = tail_alloc(sizeof_uid);
+
+       const unsigned int sizeof_uid_truncated = sizeof_uid - 1;
+       struct ucred *const uid_truncated =
+               tail_alloc(sizeof_uid_truncated);
+
+       const unsigned int sizeof_gid_truncated =
+               offsetofend(struct ucred, gid) - 1;
+       struct ucred *const gid_truncated =
+               tail_alloc(sizeof_gid_truncated);
+
        int sv[2];
        if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
                 perror_msg_and_skip("socketpair AF_UNIX SOCK_STREAM");
@@ -88,52 +108,102 @@ main(void)
        PRINT_FIELD_UID(", ", *peercred, gid);
        printf("}, [%d]) = %s\n", *len, errstr);
 
-       int fd = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (fd < 0)
-               perror_msg_and_skip("socket AF_UNIX SOCK_STREAM");
+       /* getsockopt with zero optlen */
+       *len = 0;
+       get_peercred(sv[0], peercred, len);
+       printf("getsockopt(%d, %s, %p, [0]) = %s\n",
+              sv[0], so_str(), peercred, errstr);
 
        /* getsockopt with optlen larger than necessary - shortened */
        *len = sizeof(*peercred) + 1;
-       get_peercred(fd, peercred, len);
-       printf("getsockopt(%d, %s", fd, so_str());
+       get_peercred(sv[0], peercred, len);
+       printf("getsockopt(%d, %s", sv[0], so_str());
        PRINT_FIELD_D(", {", *peercred, pid);
        PRINT_FIELD_UID(", ", *peercred, uid);
        PRINT_FIELD_UID(", ", *peercred, gid);
        printf("}, [%u->%d]) = %s\n",
               (unsigned int) sizeof(*peercred) + 1, *len, errstr);
 
-       /* getsockopt with optlen smaller than usual - truncated to ucred.pid */
-       *len = sizeof(peercred->pid);
-       get_peercred(fd, peercred, len);
-       printf("getsockopt(%d, %s", fd, so_str());
-       PRINT_FIELD_D(", {", *peercred, pid);
+       /*
+        * getsockopt with optlen less than offsetofend(struct ucred, pid):
+        * the part of struct ucred.pid is printed in hex.
+        */
+       *len = sizeof_pid_truncated;
+       get_peercred(sv[0], pid_truncated, len);
+       printf("getsockopt(%d, %s, {pid=", sv[0], so_str());
+       print_quoted_hex(pid_truncated, *len);
+       printf("}, [%d]) = %s\n", *len, errstr);
+
+       /*
+        * getsockopt with optlen equals to sizeof(struct ucred.pid):
+        * struct ucred.uid and struct ucred.gid are not printed.
+        */
+       *len = sizeof_pid;
+       get_peercred(sv[0], pid, len);
+       printf("getsockopt(%d, %s", sv[0], so_str());
+       PRINT_FIELD_D(", {", *pid, pid);
+       printf("}, [%d]) = %s\n", *len, errstr);
+
+       /*
+        * getsockopt with optlen greater than sizeof(struct ucred.pid)
+        * but smaller than offsetofend(struct ucred, uid):
+        * the part of struct ucred.uid is printed in hex.
+        */
+       *len = sizeof_uid_truncated;
+       get_peercred(sv[0], uid_truncated, len);
+       /*
+        * Copy to a properly aligned structure to avoid unaligned access
+        * to struct ucred.pid field.
+        */
+       memcpy(uid, uid_truncated, sizeof_uid_truncated);
+       printf("getsockopt(%d, %s", sv[0], so_str());
+       PRINT_FIELD_D(", {", *uid, pid);
+       printf(", uid=");
+       print_quoted_hex(&uid->uid, sizeof_uid_truncated -
+                                   offsetof(struct ucred, uid));
        printf("}, [%d]) = %s\n", *len, errstr);
 
-       /* getsockopt with optlen smaller than usual - truncated to ucred.uid */
-       *len = offsetof(struct ucred, gid);
-       get_peercred(fd, peercred, len);
-       printf("getsockopt(%d, %s", fd, so_str());
+       /*
+        * getsockopt with optlen equals to offsetofend(struct ucred, uid):
+        * struct ucred.gid is not printed.
+        */
+       *len = sizeof_uid;
+       get_peercred(sv[0], uid, len);
+       printf("getsockopt(%d, %s", sv[0], so_str());
+       PRINT_FIELD_D(", {", *uid, pid);
+       PRINT_FIELD_UID(", ", *uid, uid);
+       printf("}, [%d]) = %s\n", *len, errstr);
+
+       /*
+        * getsockopt with optlen greater than sizeof(struct ucred.uid)
+        * but smaller than offsetofend(struct ucred, gid):
+        * the part of struct ucred.gid is printed in hex.
+        */
+       *len = sizeof_gid_truncated;
+       get_peercred(sv[0], gid_truncated, len);
+       /*
+        * Copy to a properly aligned structure to avoid unaligned access
+        * to struct ucred.pid and struct ucred.uid fields.
+        */
+       memcpy(peercred, gid_truncated, sizeof_gid_truncated);
+       printf("getsockopt(%d, %s", sv[0], so_str());
        PRINT_FIELD_D(", {", *peercred, pid);
        PRINT_FIELD_UID(", ", *peercred, uid);
+       printf(", gid=");
+       print_quoted_hex(&peercred->gid, sizeof_gid_truncated -
+                                   offsetof(struct ucred, gid));
        printf("}, [%d]) = %s\n", *len, errstr);
 
-       /* getsockopt with optlen larger than usual - truncated to raw */
-       *len = sizeof(*peercred) - 1;
-       get_peercred(fd, peercred, len);
-       printf("getsockopt(%d, %s, ", fd, so_str());
-       print_quoted_hex(peercred, *len);
-       printf(", [%d]) = %s\n", *len, errstr);
-
        /* getsockopt optval EFAULT */
        *len = sizeof(*peercred);
-       get_peercred(fd, &peercred->uid, len);
+       get_peercred(sv[0], &peercred->uid, len);
        printf("getsockopt(%d, %s, %p, [%d]) = %s\n",
-              fd, so_str(), &peercred->uid, *len, errstr);
+              sv[0], so_str(), &peercred->uid, *len, errstr);
 
        /* getsockopt optlen EFAULT */
-       get_peercred(fd, peercred, len + 1);
+       get_peercred(sv[0], peercred, len + 1);
        printf("getsockopt(%d, %s, %p, %p) = %s\n",
-              fd, so_str(), peercred, len + 1, errstr);
+              sv[0], so_str(), peercred, len + 1, errstr);
 
        puts("+++ exited with 0 +++");
        return 0;