Skip to content

Commit ac01136

Browse files
q2venPaolo Abeni
authored and
Paolo Abeni
committed
af_unix: Add test for sock_diag and UDIAG_SHOW_UID.
The test prog dumps a single AF_UNIX socket's UID with and without unshare(CLONE_NEWUSER) and checks if it matches the result of getuid(). Without the preceding patch, the test prog is killed by a NULL deref in sk_diag_dump_uid(). # ./diag_uid TAP version 13 1..2 # Starting 2 tests from 3 test cases. # RUN diag_uid.uid.1 ... BUG: kernel NULL pointer dereference, address: 0000000000000270 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 105212067 P4D 105212067 PUD 1051fe067 PMD 0 Oops: 0000 [#1] PREEMPT SMP NOPTI Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.0-1.amzn2022.0.1 04/01/2014 RIP: 0010:sk_diag_fill (./include/net/sock.h:920 net/unix/diag.c:119 net/unix/diag.c:170) ... # 1: Test terminated unexpectedly by signal 9 # FAIL diag_uid.uid.1 not ok 1 diag_uid.uid.1 # RUN diag_uid.uid_unshare.1 ... # 1: Test terminated by timeout # FAIL diag_uid.uid_unshare.1 not ok 2 diag_uid.uid_unshare.1 # FAILED: 0 / 2 tests passed. # Totals: pass:0 fail:2 xfail:0 xpass:0 skip:0 error:0 With the patch, the test succeeds. # ./diag_uid TAP version 13 1..2 # Starting 2 tests from 3 test cases. # RUN diag_uid.uid.1 ... # OK diag_uid.uid.1 ok 1 diag_uid.uid.1 # RUN diag_uid.uid_unshare.1 ... # OK diag_uid.uid_unshare.1 ok 2 diag_uid.uid_unshare.1 # PASSED: 2 / 2 tests passed. # Totals: pass:2 fail:0 xfail:0 xpass:0 skip:0 error:0 Signed-off-by: Kuniyuki Iwashima <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent b3abe42 commit ac01136

File tree

3 files changed

+180
-1
lines changed

3 files changed

+180
-1
lines changed

tools/testing/selftests/net/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
bind_bhash
33
cmsg_sender
4+
diag_uid
45
fin_ack_lat
56
gro
67
hwtstamp_config
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
TEST_GEN_PROGS := test_unix_oob unix_connect
1+
TEST_GEN_PROGS := diag_uid test_unix_oob unix_connect
22

33
include ../../lib.mk
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright Amazon.com Inc. or its affiliates. */
3+
4+
#define _GNU_SOURCE
5+
#include <sched.h>
6+
7+
#include <unistd.h>
8+
#include <linux/netlink.h>
9+
#include <linux/rtnetlink.h>
10+
#include <linux/sock_diag.h>
11+
#include <linux/unix_diag.h>
12+
#include <sys/socket.h>
13+
#include <sys/stat.h>
14+
#include <sys/types.h>
15+
#include <sys/un.h>
16+
17+
#include "../../kselftest_harness.h"
18+
19+
FIXTURE(diag_uid)
20+
{
21+
int netlink_fd;
22+
int unix_fd;
23+
__u32 inode;
24+
__u64 cookie;
25+
};
26+
27+
FIXTURE_VARIANT(diag_uid)
28+
{
29+
int unshare;
30+
int udiag_show;
31+
};
32+
33+
FIXTURE_VARIANT_ADD(diag_uid, uid)
34+
{
35+
.unshare = 0,
36+
.udiag_show = UDIAG_SHOW_UID
37+
};
38+
39+
FIXTURE_VARIANT_ADD(diag_uid, uid_unshare)
40+
{
41+
.unshare = CLONE_NEWUSER,
42+
.udiag_show = UDIAG_SHOW_UID
43+
};
44+
45+
FIXTURE_SETUP(diag_uid)
46+
{
47+
struct stat file_stat;
48+
socklen_t optlen;
49+
int ret;
50+
51+
if (variant->unshare)
52+
ASSERT_EQ(unshare(variant->unshare), 0);
53+
54+
self->netlink_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
55+
ASSERT_NE(self->netlink_fd, -1);
56+
57+
self->unix_fd = socket(AF_UNIX, SOCK_STREAM, 0);
58+
ASSERT_NE(self->unix_fd, -1);
59+
60+
ret = fstat(self->unix_fd, &file_stat);
61+
ASSERT_EQ(ret, 0);
62+
63+
self->inode = file_stat.st_ino;
64+
65+
optlen = sizeof(self->cookie);
66+
ret = getsockopt(self->unix_fd, SOL_SOCKET, SO_COOKIE, &self->cookie, &optlen);
67+
ASSERT_EQ(ret, 0);
68+
}
69+
70+
FIXTURE_TEARDOWN(diag_uid)
71+
{
72+
close(self->netlink_fd);
73+
close(self->unix_fd);
74+
}
75+
76+
int send_request(struct __test_metadata *_metadata,
77+
FIXTURE_DATA(diag_uid) *self,
78+
const FIXTURE_VARIANT(diag_uid) *variant)
79+
{
80+
struct {
81+
struct nlmsghdr nlh;
82+
struct unix_diag_req udr;
83+
} req = {
84+
.nlh = {
85+
.nlmsg_len = sizeof(req),
86+
.nlmsg_type = SOCK_DIAG_BY_FAMILY,
87+
.nlmsg_flags = NLM_F_REQUEST
88+
},
89+
.udr = {
90+
.sdiag_family = AF_UNIX,
91+
.udiag_ino = self->inode,
92+
.udiag_cookie = {
93+
(__u32)self->cookie,
94+
(__u32)(self->cookie >> 32)
95+
},
96+
.udiag_show = variant->udiag_show
97+
}
98+
};
99+
struct sockaddr_nl nladdr = {
100+
.nl_family = AF_NETLINK
101+
};
102+
struct iovec iov = {
103+
.iov_base = &req,
104+
.iov_len = sizeof(req)
105+
};
106+
struct msghdr msg = {
107+
.msg_name = &nladdr,
108+
.msg_namelen = sizeof(nladdr),
109+
.msg_iov = &iov,
110+
.msg_iovlen = 1
111+
};
112+
113+
return sendmsg(self->netlink_fd, &msg, 0);
114+
}
115+
116+
void render_response(struct __test_metadata *_metadata,
117+
struct unix_diag_req *udr, __u32 len)
118+
{
119+
unsigned int rta_len = len - NLMSG_LENGTH(sizeof(*udr));
120+
struct rtattr *attr;
121+
uid_t uid;
122+
123+
ASSERT_GT(len, sizeof(*udr));
124+
ASSERT_EQ(udr->sdiag_family, AF_UNIX);
125+
126+
attr = (struct rtattr *)(udr + 1);
127+
ASSERT_NE(RTA_OK(attr, rta_len), 0);
128+
ASSERT_EQ(attr->rta_type, UNIX_DIAG_UID);
129+
130+
uid = *(uid_t *)RTA_DATA(attr);
131+
ASSERT_EQ(uid, getuid());
132+
}
133+
134+
void receive_response(struct __test_metadata *_metadata,
135+
FIXTURE_DATA(diag_uid) *self)
136+
{
137+
long buf[8192 / sizeof(long)];
138+
struct sockaddr_nl nladdr = {
139+
.nl_family = AF_NETLINK
140+
};
141+
struct iovec iov = {
142+
.iov_base = buf,
143+
.iov_len = sizeof(buf)
144+
};
145+
struct msghdr msg = {
146+
.msg_name = &nladdr,
147+
.msg_namelen = sizeof(nladdr),
148+
.msg_iov = &iov,
149+
.msg_iovlen = 1
150+
};
151+
struct unix_diag_req *udr;
152+
struct nlmsghdr *nlh;
153+
int ret;
154+
155+
ret = recvmsg(self->netlink_fd, &msg, 0);
156+
ASSERT_GT(ret, 0);
157+
158+
nlh = (struct nlmsghdr *)buf;
159+
ASSERT_NE(NLMSG_OK(nlh, ret), 0);
160+
ASSERT_EQ(nlh->nlmsg_type, SOCK_DIAG_BY_FAMILY);
161+
162+
render_response(_metadata, NLMSG_DATA(nlh), nlh->nlmsg_len);
163+
164+
nlh = NLMSG_NEXT(nlh, ret);
165+
ASSERT_EQ(NLMSG_OK(nlh, ret), 0);
166+
}
167+
168+
TEST_F(diag_uid, 1)
169+
{
170+
int ret;
171+
172+
ret = send_request(_metadata, self, variant);
173+
ASSERT_GT(ret, 0);
174+
175+
receive_response(_metadata, self);
176+
}
177+
178+
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)