net: fix SOL_NETLINK NETLINK_LIST_MEMBERSHIPS decoding
NETLINK_LIST_MEMBERSHIPS, unlike all other SOL_NETLINK options, requests not just a single integer but an array of integers. The kernel also supports a zero optlen NETLINK_LIST_MEMBERSHIPS request. * net.c (print_uint32): New function. (print_getsockopt): Add ulen argument, rename len argument to rlen, <SOL_NETLINK> Handle NETLINK_LIST_MEMBERSHIPS using print_array and print_uint32. (SYS_FUNC(getsockopt)): Pass ulen to print_getsockopt. * tests/sockopt-sol_netlink.c (main): Check NETLINK_LIST_MEMBERSHIPS decoding.
This commit is contained in:
parent
8d481bf4c2
commit
ba41dc8a70
52
net.c
52
net.c
@ -556,27 +556,35 @@ print_icmp_filter(struct tcb *const tcp, const kernel_ulong_t addr, int len)
|
||||
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;
|
||||
@ -588,7 +596,7 @@ print_getsockopt(struct tcb *const tcp, const unsigned int level,
|
||||
switch (name) {
|
||||
#ifdef PACKET_STATISTICS
|
||||
case PACKET_STATISTICS:
|
||||
print_tpacket_stats(tcp, addr, len);
|
||||
print_tpacket_stats(tcp, addr, rlen);
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
@ -597,26 +605,44 @@ print_getsockopt(struct tcb *const tcp, const unsigned int level,
|
||||
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);
|
||||
@ -649,7 +675,7 @@ SYS_FUNC(getsockopt)
|
||||
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
|
||||
|
@ -85,6 +85,9 @@ main(void)
|
||||
#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
|
||||
@ -136,14 +139,34 @@ main(void)
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user