1/*
2 * Check decoding of netlink attribute.
3 *
4 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
5 * Copyright (c) 2017 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
44static void
45test_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]}, \"12\"}, %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_??? */}, \"1234\"}}"
137	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
138	       fd, msg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1,
139	       msg_len, sprintrc(rc));
140
141	/* print one struct nlattr and fetch fail second struct nlattr */
142	msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 2;
143	msg = tail_memdup(&c_msg, msg_len);
144	memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
145	nla = NLMSG_ATTR(msg, sizeof(msg->udm));
146	*nla = (struct nlattr) {
147		.nla_len = NLA_HDRLEN,
148		.nla_type = UNIX_DIAG_NAME
149	};
150	memcpy(nla + 1, "12", 2);
151	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
152	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
153	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
154	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
155	       ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
156	       ", nla_type=UNIX_DIAG_NAME}, \"12\"]}, %u"
157	       ", MSG_DONTWAIT, NULL, 0) = %s\n",
158	       fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
159
160	/* print one struct nlattr and short read of second struct nlattr */
161	msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
162	msg = tail_memdup(&c_msg, msg_len - 1);
163	memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
164	nla = NLMSG_ATTR(msg, sizeof(msg->udm));
165	*nla = (struct nlattr) {
166		.nla_len = NLA_HDRLEN,
167		.nla_type = UNIX_DIAG_NAME
168	};
169	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
170	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
171	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
172	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
173	       ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
174	       ", nla_type=UNIX_DIAG_NAME}, %p]}, %u"
175	       ", MSG_DONTWAIT, NULL, 0) = %s\n",
176	       fd, msg_len, nla->nla_len, nla + 1, msg_len, sprintrc(rc));
177
178	/* print two struct nlattr */
179	msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2;
180	msg = tail_memdup(&c_msg, msg_len);
181	memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
182	nla = NLMSG_ATTR(msg, sizeof(msg->udm));
183	*nla = (struct nlattr) {
184		.nla_len = NLA_HDRLEN,
185		.nla_type = UNIX_DIAG_NAME
186	};
187	*(nla + 1) = (struct nlattr) {
188		.nla_len = NLA_HDRLEN,
189		.nla_type = UNIX_DIAG_PEER
190	};
191	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
192	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
193	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
194	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
195	       ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u"
196	       ", nla_type=UNIX_DIAG_NAME}, {nla_len=%u"
197	       ", nla_type=UNIX_DIAG_PEER}]}, %u"
198	       ", MSG_DONTWAIT, NULL, 0) = %s\n",
199	       fd, msg_len, nla->nla_len, nla->nla_len,
200	       msg_len, sprintrc(rc));
201
202	/* print first nlattr only when its nla_len is less than NLA_HDRLEN */
203	nla->nla_len = NLA_HDRLEN - 1;
204	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
205	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
206	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
207	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
208	       ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
209	       ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
210	       fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
211
212	/* abbreviated output */
213#define ABBREV_LEN (DEFAULT_STRLEN + 1)
214	msg_len = NLA_HDRLEN * ABBREV_LEN + NLMSG_SPACE(sizeof(msg->udm));
215	msg = tail_memdup(&c_msg, msg_len);
216	memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
217	unsigned int i;
218	nla = NLMSG_ATTR(msg, sizeof(msg->udm));
219	for (i = 0; i < ABBREV_LEN; ++i)
220		nla[i] = (struct nlattr) {
221			.nla_len = NLA_HDRLEN,
222			.nla_type = UNIX_DIAG_SHUTDOWN + 1 + i
223		};
224
225	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
226	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
227	       ", flags=NLM_F_DUMP, seq=0, pid=0}"
228	       ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM"
229	       ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0"
230	       ", udiag_cookie=[0, 0]}, [",
231	       fd, msg_len);
232	for (i = 0; i < DEFAULT_STRLEN; ++i) {
233		if (i)
234			printf(", ");
235		printf("{nla_len=%u, nla_type=%#x /* UNIX_DIAG_??? */}",
236		       nla->nla_len, UNIX_DIAG_SHUTDOWN + 1 + i);
237	}
238	printf(", ...]}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",
239	       msg_len, sprintrc(rc));
240}
241
242static void
243test_nla_type(const int fd)
244{
245	static const struct msg {
246		struct nlmsghdr nlh;
247		struct unix_diag_msg udm;
248	} c_msg = {
249		.nlh = {
250			.nlmsg_len = sizeof(struct msg),
251			.nlmsg_type = SOCK_DIAG_BY_FAMILY,
252			.nlmsg_flags = NLM_F_DUMP
253		},
254		.udm = {
255			.udiag_family = AF_UNIX,
256			.udiag_type = SOCK_STREAM,
257			.udiag_state = TCP_FIN_WAIT1
258		}
259	};
260	struct msg *msg;
261	struct nlattr *nla;
262	unsigned int msg_len;
263	long rc;
264
265	msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla);
266	msg = tail_memdup(&c_msg, msg_len);
267	memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len));
268	nla = NLMSG_ATTR(msg, sizeof(msg->udm));
269	*nla = (struct nlattr) {
270		.nla_len = sizeof(*nla),
271		.nla_type = NLA_F_NESTED | UNIX_DIAG_NAME
272	};
273	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
274	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
275	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
276	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
277	       ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
278	       ", nla_type=NLA_F_NESTED|UNIX_DIAG_NAME}}"
279	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
280	       fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
281
282	nla->nla_type = NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
283	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
284	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
285	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
286	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
287	       ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
288	       ", nla_type=NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}"
289	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
290	       fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
291
292	nla->nla_type = NLA_F_NESTED | NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME;
293	rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0);
294	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
295	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
296	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
297	       ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
298	       ", nla_type=NLA_F_NESTED|NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}"
299	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
300	       fd, msg_len, nla->nla_len, msg_len, sprintrc(rc));
301
302	nla->nla_type = NLA_F_NESTED | (UNIX_DIAG_SHUTDOWN + 1);
303	rc = sendto(fd, msg, msg->nlh.nlmsg_len, MSG_DONTWAIT, NULL, 0);
304	printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY"
305	       ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX"
306	       ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1"
307	       ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u"
308	       ", nla_type=NLA_F_NESTED|%#x /* UNIX_DIAG_??? */}}"
309	       ", %u, MSG_DONTWAIT, NULL, 0) = %s\n",
310	       fd, msg->nlh.nlmsg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1,
311	       msg->nlh.nlmsg_len, sprintrc(rc));
312}
313
314int main(void)
315{
316	skip_if_unavailable("/proc/self/fd/");
317
318	const int fd = create_nl_socket(NETLINK_SOCK_DIAG);
319
320	test_nlattr(fd);
321	test_nla_type(fd);
322
323	puts("+++ exited with 0 +++");
324
325	return 0;
326}
327