1 /*
2 * Check decoding of netlink attribute.
3 *
4 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
5 * Copyright (c) 2017-2018 The strace developers.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "tests.h"
32
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/socket.h>
38 #include <netinet/tcp.h>
39 #include "netlink.h"
40 #include <linux/rtnetlink.h>
41 #include <linux/sock_diag.h>
42 #include <linux/unix_diag.h>
43
44 static void
test_nlattr(const int fd)45 test_nlattr(const int fd)
46 {
47 static const struct msg {
48 struct nlmsghdr nlh;
49 struct unix_diag_msg udm;
50 } c_msg = {
51 .nlh = {
52 .nlmsg_len = sizeof(struct msg),
53 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
54 .nlmsg_flags = NLM_F_DUMP
55 },
56 .udm = {
57 .udiag_family = AF_UNIX,
58 .udiag_type = SOCK_STREAM,
59 .udiag_state = TCP_FIN_WAIT1
60 }
61 };
62 struct msg *msg;
63 struct nlattr *nla;
64 unsigned int msg_len;
65 long rc;
66
67 /* fetch fail: len < sizeof(struct nlattr) */
68 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + 2;
69 msg = tail_memdup(&c_msg, msg_len);
70 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
71 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
72 memcpy(nla, "12", 2);
73 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
74 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
75 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
76 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
77 ", udiag_ino=0, udiag_cookie=[0, 0]}, \"\\x31\\x32\"}, %u"
78 ", MSG_DONTWAIT, NULL, 0) = %s\n",
79 fd, msg_len, msg_len, sprintrc(rc));
80
81 /* fetch fail: short read */
82 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
83 msg = tail_memdup(&c_msg, msg_len - 1);
84 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
85 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
86 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
87 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
88 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
89 ", udiag_ino=0, udiag_cookie=[0, 0]}, %p}, %u"
90 ", MSG_DONTWAIT, NULL, 0) = %s\n",
91 fd, msg_len, (void *) msg + NLMSG_SPACE(sizeof(msg->udm)),
92 msg_len, sprintrc(rc));
93
94 /* print one struct nlattr */
95 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
96 msg = tail_memdup(&c_msg, msg_len);
97 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
98 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
99 *nla = (struct nlattr) {
100 .nla_len = sizeof(*nla),
101 .nla_type = UNIX_DIAG_NAME
102 };
103 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
104 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
105 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
106 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
107 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
108 ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
109 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
110
111 /* print one struct nlattr with nla_len out of msg_len bounds */
112 nla->nla_len += 8;
113 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
114 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
115 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
116 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
117 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
118 ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
119 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
120
121 /* print one struct nlattr and some data */
122 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 4;
123 msg = tail_memdup(&c_msg, msg_len);
124 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
125 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
126 *nla = (struct nlattr) {
127 .nla_len = NLA_HDRLEN + 4,
128 .nla_type = UNIX_DIAG_SHUTDOWN + 1
129 };
130 memcpy(RTA_DATA(nla), "1234", 4);
131 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
132 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
133 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
134 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
135 ", udiag_ino=0, udiag_cookie=[0, 0]}, {{nla_len=%u"
136 ", nla_type=%#x /* UNIX_DIAG_??? */}"
137 ", \"\\x31\\x32\\x33\\x34\"}}"
138 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
139 fd, msg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1,
140 msg_len, sprintrc(rc));
141
142 /* print one struct nlattr and fetch fail second struct nlattr */
143 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 2;
144 msg = tail_memdup(&c_msg, msg_len);
145 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
146 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
147 SET_STRUCT(struct nlattr, nla,
148 .nla_len = NLA_HDRLEN,
149 .nla_type = UNIX_DIAG_NAME
150 );
151 memcpy(nla + 1, "12", 2);
152 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
153 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
154 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
155 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
156 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
157 ", nla_type=UNIX_DIAG_NAME}, \"\\x31\\x32\"]}, %u"
158 ", MSG_DONTWAIT, NULL, 0) = %s\n",
159 fd, msg_len, NLA_HDRLEN, msg_len, sprintrc(rc));
160
161 /* print one struct nlattr and short read of second struct nlattr */
162 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
163 msg = tail_memdup(&c_msg, msg_len - 1);
164 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
165 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
166 SET_STRUCT(struct nlattr, nla,
167 .nla_len = NLA_HDRLEN,
168 .nla_type = UNIX_DIAG_NAME
169 );
170 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
171 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
172 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
173 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
174 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
175 ", nla_type=UNIX_DIAG_NAME}, ... /* %p */]}, %u"
176 ", MSG_DONTWAIT, NULL, 0) = %s\n",
177 fd, msg_len, NLA_HDRLEN, nla + 1, msg_len, sprintrc(rc));
178
179 /* print two struct nlattr */
180 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
181 msg = tail_memdup(&c_msg, msg_len);
182 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
183 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
184 *nla = (struct nlattr) {
185 .nla_len = NLA_HDRLEN,
186 .nla_type = UNIX_DIAG_NAME
187 };
188 *(nla + 1) = (struct nlattr) {
189 .nla_len = NLA_HDRLEN,
190 .nla_type = UNIX_DIAG_PEER
191 };
192 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
193 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
194 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
195 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
196 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
197 ", nla_type=UNIX_DIAG_NAME}, {nla_len=%u"
198 ", nla_type=UNIX_DIAG_PEER}]}, %u"
199 ", MSG_DONTWAIT, NULL, 0) = %s\n",
200 fd, msg_len, nla->nla_len, nla->nla_len,
201 msg_len, sprintrc(rc));
202
203 /* print first nlattr only when its nla_len is less than NLA_HDRLEN */
204 nla->nla_len = NLA_HDRLEN - 1;
205 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
206 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
207 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
208 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
209 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
210 ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
211 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
212
213 /* unrecognized attribute data, abbreviated output */
214 #define ABBREV_LEN (DEFAULT_STRLEN + 1)
215 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * ABBREV_LEN * 2;
216 msg = tail_alloc(msg_len);
217 memcpy(msg, &c_msg, sizeof(c_msg));
218 msg->nlh.nlmsg_len = msg_len;
219 unsigned int i;
220 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
221 for (i = 0; i < ABBREV_LEN; ++i) {
222 nla[i * 2] = (struct nlattr) {
223 .nla_len = NLA_HDRLEN * 2 - 1,
224 .nla_type = UNIX_DIAG_SHUTDOWN + 1 + i
225 };
226 fill_memory_ex(&nla[i * 2 + 1], NLA_HDRLEN,
227 '0' + i, '~' - '0' - i);
228 }
229
230 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
231 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
232 ", flags=NLM_F_DUMP, seq=0, pid=0}"
233 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
234 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0"
235 ", udiag_cookie=[0, 0]}, [",
236 fd, msg_len);
237 for (i = 0; i < DEFAULT_STRLEN; ++i) {
238 if (i)
239 printf(", ");
240 printf("{{nla_len=%u, nla_type=%#x /* UNIX_DIAG_??? */}, ",
241 nla->nla_len, UNIX_DIAG_SHUTDOWN + 1 + i);
242 print_quoted_hex(&nla[i * 2 + 1], NLA_HDRLEN - 1);
243 printf("}");
244 }
245 printf(", ...]}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
246 msg_len, sprintrc(rc));
247 }
248
249 static void
test_nla_type(const int fd)250 test_nla_type(const int fd)
251 {
252 static const struct msg {
253 struct nlmsghdr nlh;
254 struct unix_diag_msg udm;
255 } c_msg = {
256 .nlh = {
257 .nlmsg_len = sizeof(struct msg),
258 .nlmsg_type = SOCK_DIAG_BY_FAMILY,
259 .nlmsg_flags = NLM_F_DUMP
260 },
261 .udm = {
262 .udiag_family = AF_UNIX,
263 .udiag_type = SOCK_STREAM,
264 .udiag_state = TCP_FIN_WAIT1
265 }
266 };
267 struct msg *msg;
268 struct nlattr *nla;
269 unsigned int msg_len;
270 long rc;
271
272 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
273 msg = tail_memdup(&c_msg, msg_len);
274 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
275 nla = NLMSG_ATTR(msg, sizeof(msg->udm));
276 *nla = (struct nlattr) {
277 .nla_len = sizeof(*nla),
278 .nla_type = NLA_F_NESTED | UNIX_DIAG_NAME
279 };
280 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
281 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
282 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
283 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
284 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
285 ", nla_type=NLA_F_NESTED|UNIX_DIAG_NAME}}"
286 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
287 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
288
289 nla->nla_type = NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
290 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
291 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
292 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
293 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
294 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
295 ", nla_type=NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}"
296 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
297 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
298
299 nla->nla_type = NLA_F_NESTED | NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
300 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
301 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
302 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
303 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
304 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
305 ", nla_type=NLA_F_NESTED|NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}"
306 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
307 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
308
309 nla->nla_type = NLA_F_NESTED | (UNIX_DIAG_SHUTDOWN + 1);
310 rc = sendto(fd, msg, msg->nlh.nlmsg_len, MSG_DONTWAIT, NULL, 0);
311 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
312 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
313 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
314 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
315 ", nla_type=NLA_F_NESTED|%#x /* UNIX_DIAG_??? */}}"
316 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
317 fd, msg->nlh.nlmsg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1,
318 msg->nlh.nlmsg_len, sprintrc(rc));
319 }
320
main(void)321 int main(void)
322 {
323 skip_if_unavailable("/proc/self/fd/");
324
325 const int fd = create_nl_socket(NETLINK_SOCK_DIAG);
326
327 test_nlattr(fd);
328 test_nla_type(fd);
329
330 puts("+++ exited with 0 +++");
331
332 return 0;
333 }
334