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 nlmsghdr *nlh; |
152 | int ret; |
153 | |
154 | ret = recvmsg(self->netlink_fd, &msg, 0); |
155 | ASSERT_GT(ret, 0); |
156 | |
157 | nlh = (struct nlmsghdr *)buf; |
158 | ASSERT_NE(NLMSG_OK(nlh, ret), 0); |
159 | ASSERT_EQ(nlh->nlmsg_type, SOCK_DIAG_BY_FAMILY); |
160 | |
161 | render_response(_metadata, NLMSG_DATA(nlh), len: nlh->nlmsg_len); |
162 | |
163 | nlh = NLMSG_NEXT(nlh, ret); |
164 | ASSERT_EQ(NLMSG_OK(nlh, ret), 0); |
165 | } |
166 | |
167 | TEST_F(diag_uid, 1) |
168 | { |
169 | int ret; |
170 | |
171 | ret = send_request(_metadata, self, variant); |
172 | ASSERT_GT(ret, 0); |
173 | |
174 | receive_response(_metadata, self); |
175 | } |
176 | |
177 | TEST_HARNESS_MAIN |
178 | |