tprints(")");
}
+static bool
+print_uint32(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
+{
+ tprintf("%u", *(uint32_t *) elem_buf);
+
+ return true;
+}
+
static void
print_getsockopt(struct tcb *const tcp, const unsigned int level,
const unsigned int name, const kernel_ulong_t addr,
- const int len)
+ const int ulen, const int rlen)
{
if (addr && verbose(tcp))
switch (level) {
case SOL_SOCKET:
switch (name) {
case SO_LINGER:
- print_get_linger(tcp, addr, len);
+ print_get_linger(tcp, addr, rlen);
return;
#ifdef SO_PEERCRED
case SO_PEERCRED:
- print_ucred(tcp, addr, len);
+ print_ucred(tcp, addr, rlen);
return;
#endif
#ifdef SO_ATTACH_FILTER
case SO_ATTACH_FILTER:
- if (len && (unsigned short) len == (unsigned int) len)
- print_sock_fprog(tcp, addr, len);
+ if (rlen && (unsigned short) rlen == (unsigned int) rlen)
+ print_sock_fprog(tcp, addr, rlen);
else
printaddr(addr);
return;
switch (name) {
#ifdef PACKET_STATISTICS
case PACKET_STATISTICS:
- print_tpacket_stats(tcp, addr, len);
+ print_tpacket_stats(tcp, addr, rlen);
return;
#endif
}
case SOL_RAW:
switch (name) {
case ICMP_FILTER:
- print_icmp_filter(tcp, addr, len);
+ print_icmp_filter(tcp, addr, rlen);
return;
}
break;
case SOL_NETLINK:
- if (len < (int) sizeof(int))
- printaddr(addr); /* unlikely */
- else
+ if (ulen < 0 || rlen < 0) {
+ /*
+ * As the kernel neither accepts nor returns a negative
+ * length, in case of successful getsockopt syscall
+ * invocation these negative values must have come
+ * from userspace.
+ */
+ printaddr(addr);
+ return;
+ }
+ switch (name) {
+ case NETLINK_LIST_MEMBERSHIPS: {
+ uint32_t buf;
+ print_array(tcp, addr, MIN(ulen, rlen) / sizeof(buf),
+ &buf, sizeof(buf),
+ umoven_or_printaddr, print_uint32, 0);
+ break;
+ }
+ default:
printnum_int(tcp, addr, "%d");
+ break;
+ }
return;
}
/* default arg printing */
if (verbose(tcp)) {
- if (len == sizeof(int)) {
+ if (rlen == sizeof(int)) {
printnum_int(tcp, addr, "%d");
} else {
- printstrn(tcp, addr, len);
+ printstrn(tcp, addr, rlen);
}
} else {
printaddr(addr);
tprintf(", [%d]", ulen);
} else {
print_getsockopt(tcp, tcp->u_arg[1], tcp->u_arg[2],
- tcp->u_arg[3], rlen);
+ tcp->u_arg[3], ulen, rlen);
if (ulen != rlen)
tprintf(", [%d->%d]", ulen, rlen);
else
#ifdef NETLINK_LISTEN_ALL_NSID
{ ARG_STR(NETLINK_LISTEN_ALL_NSID) },
#endif
+#ifdef NETLINK_LIST_MEMBERSHIPS
+ { ARG_STR(NETLINK_LIST_MEMBERSHIPS) },
+#endif
#ifdef NETLINK_CAP_ACK
{ ARG_STR(NETLINK_CAP_ACK) },
#endif
printf("->%d", *len);
printf("]) = %s\n", errstr);
- /* optlen shorter than necessary - print address */
- *len = sizeof(*val) - 1;
- get_sockopt(fd, names[i].val, val, len);
- printf("getsockopt(%d, SOL_NETLINK, %s, %p, [%d",
- fd, names[i].str, val, (int) sizeof(*val) - 1);
- if ((int) sizeof(*val) - 1 != *len)
- printf("->%d", *len);
- printf("]) = %s\n", errstr);
+#ifdef NETLINK_LIST_MEMBERSHIPS
+ if (names[i].val != NETLINK_LIST_MEMBERSHIPS) {
+#endif
+ /* optlen shorter than necessary - print address */
+ *len = sizeof(*val) - 1;
+ get_sockopt(fd, names[i].val, val, len);
+ printf("getsockopt(%d, SOL_NETLINK, %s, %p, [%d",
+ fd, names[i].str, val, (int) sizeof(*val) - 1);
+ if ((int) sizeof(*val) - 1 != *len)
+ printf("->%d", *len);
+ printf("]) = %s\n", errstr);
+#ifdef NETLINK_LIST_MEMBERSHIPS
+ } else {
+ /* optlen shorter than required for the first element */
+ *len = sizeof(*val) - 1;
+ get_sockopt(fd, names[i].val, efault, len);
+ printf("getsockopt(%d, SOL_NETLINK, %s, ",
+ fd, names[i].str);
+ if (rc)
+ printf("%p", efault);
+ else
+ printf("[]");
+ printf(", [%d", (int) sizeof(*val) - 1);
+ if ((int) sizeof(*val) - 1 != *len)
+ printf("->%d", *len);
+ printf("]) = %s\n", errstr);
+ }
+#endif
/* optval EFAULT - print address */
*len = sizeof(*val);