#ifdef SO_PEERCRED
static void
-print_ucred(struct tcb *const tcp, const kernel_ulong_t addr, unsigned int len)
+print_get_ucred(struct tcb *const tcp, const kernel_ulong_t addr,
+ unsigned int len)
{
struct ucred uc;
- if (len < sizeof(uc)) {
- if (len != sizeof(uc.pid)
- && len != offsetofend(struct ucred, uid)) {
- printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX);
- return;
- }
- } else {
+ /*
+ * The kernel is very unlikely to return len > sizeof(uc)
+ * because struct ucred is very unlikely to change,
+ * but extra safety won't harm either.
+ */
+ if (len > sizeof(uc))
len = sizeof(uc);
- }
- if (umoven(tcp, addr, len, &uc) < 0) {
- printaddr(addr);
+ if (umoven_or_printaddr(tcp, addr, len, &uc))
return;
- }
- PRINT_FIELD_D("{", uc, pid);
- if (len > sizeof(uc.pid))
- PRINT_FIELD_UID(", ", uc, uid);
- if (len == sizeof(uc))
- PRINT_FIELD_UID(", ", uc, gid);
+ if (len < sizeof(uc.pid)) {
+ tprints("{pid=");
+ print_quoted_string((void *) &uc.pid,
+ len, QUOTE_FORCE_HEX);
+ } else {
+ PRINT_FIELD_D("{", uc, pid);
+
+ if (len > offsetof(struct ucred, uid)) {
+ len -= offsetof(struct ucred, uid);
+ if (len < sizeof(uc.uid)) {
+ tprints(", uid=");
+ print_quoted_string((void *) &uc.uid,
+ len, QUOTE_FORCE_HEX);
+ } else {
+ PRINT_FIELD_UID(", ", uc, uid);
+
+ if (len > offsetof(struct ucred, gid) -
+ offsetof(struct ucred, uid)) {
+ len -= offsetof(struct ucred, gid) -
+ offsetof(struct ucred, uid);
+ if (len < sizeof(uc.gid)) {
+ tprints(", gid=");
+ print_quoted_string((void *) &uc.gid,
+ len,
+ QUOTE_FORCE_HEX);
+ } else {
+ PRINT_FIELD_UID(", ", uc, gid);
+ }
+ }
+ }
+ }
+ }
tprints("}");
}
#endif /* SO_PEERCRED */
return;
#ifdef SO_PEERCRED
case SO_PEERCRED:
- print_ucred(tcp, addr, rlen);
+ print_get_ucred(tcp, addr, rlen);
return;
#endif
#ifdef SO_ATTACH_FILTER
#include <stddef.h>
#include <stdio.h>
+#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
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");
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;