• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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