1 /*
2  * Copyright (c) 2017-2018 The strace developers.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "tests.h"
29 #include "print_fields.h"
30 
31 #include <stdio.h>
32 #include <stdint.h>
33 #include <string.h>
34 #include <sys/socket.h>
35 #include "netlink.h"
36 #include <linux/rtnetlink.h>
37 
38 static void
init_nlattr(struct nlattr * const nla,const uint16_t nla_len,const uint16_t nla_type,const void * const src,const size_t n)39 init_nlattr(struct nlattr *const nla,
40 	    const uint16_t nla_len,
41 	    const uint16_t nla_type,
42 	    const void *const src,
43 	    const size_t n)
44 {
45 	SET_STRUCT(struct nlattr, nla,
46 		.nla_len = nla_len,
47 		.nla_type = nla_type,
48 	);
49 
50 	memcpy(RTA_DATA(nla), src, n);
51 }
52 
53 static void
print_nlattr(const unsigned int nla_len,const char * const nla_type,bool add_data)54 print_nlattr(const unsigned int nla_len, const char *const nla_type, bool add_data)
55 {
56 	printf(", %s{{nla_len=%u, nla_type=%s}, ",
57 	       add_data ? "[" : "", nla_len, nla_type);
58 }
59 
60 #define TEST_NLATTR_EX_(fd_, nlh0_, hdrlen_,				\
61 		     init_msg_, print_msg_,				\
62 		     nla_type_, nla_type_str_,				\
63 		     nla_data_len_, nla_total_len_,			\
64 		     src_, slen_, ...)					\
65 	do {								\
66 		struct nlmsghdr *const nlh =				\
67 			(nlh0_) - (NLA_HDRLEN + (slen_));		\
68 		struct nlattr *const TEST_NLATTR_nla =			\
69 			NLMSG_ATTR(nlh, (hdrlen_));			\
70 		const unsigned int nla_len =				\
71 			NLA_HDRLEN + (nla_data_len_);			\
72 		const unsigned int msg_len =				\
73 			NLMSG_SPACE(hdrlen_) + NLA_HDRLEN + (nla_total_len_); \
74 									\
75 		(init_msg_)(nlh, msg_len);				\
76 		init_nlattr(TEST_NLATTR_nla, nla_len, (nla_type_),	\
77 			   (src_), (slen_));				\
78 									\
79 		const char *const errstr =				\
80 			sprintrc(sendto((fd_), nlh, msg_len,		\
81 					MSG_DONTWAIT, NULL, 0));	\
82 									\
83 		printf("sendto(%d, {", (fd_));				\
84 		(print_msg_)(msg_len);					\
85 		print_nlattr(nla_len, (nla_type_str_),			\
86 			     (nla_total_len_) > (nla_data_len_));	\
87 									\
88 		{ __VA_ARGS__; }					\
89 									\
90 		if ((nla_total_len_) > (nla_data_len_))			\
91 			printf("]");					\
92 									\
93 		printf("}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",		\
94 		       msg_len, errstr);				\
95 	} while (0)
96 
97 #define TEST_NLATTR_(fd_, nlh0_, hdrlen_,				\
98 		     init_msg_, print_msg_,				\
99 		     nla_type_, nla_type_str_,				\
100 		     nla_data_len_, src_, slen_, ...)			\
101 	TEST_NLATTR_EX_((fd_), (nlh0_), (hdrlen_),			\
102 			(init_msg_), (print_msg_),			\
103 			(nla_type_), (nla_type_str_),			\
104 			(nla_data_len_), (nla_data_len_),		\
105 			(src_), (slen_), __VA_ARGS__)
106 
107 #define TEST_NLATTR(fd_, nlh0_, hdrlen_,				\
108 		    init_msg_, print_msg_,				\
109 		    nla_type_,						\
110 		    nla_data_len_, src_, slen_, ...)			\
111 	TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),				\
112 		(init_msg_), (print_msg_),				\
113 		(nla_type_), #nla_type_,				\
114 		(nla_data_len_), (src_), (slen_), __VA_ARGS__)
115 
116 #define TEST_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_,			\
117 			       init_msg_, print_msg_,			\
118 			       nla_type_, nla_type_str_,		\
119 			       pattern_, obj_, fallback_func, ...)	\
120 	do {								\
121 		const unsigned int plen =				\
122 			sizeof(obj_) - 1 > DEFAULT_STRLEN		\
123 			? DEFAULT_STRLEN : (int) sizeof(obj_) - 1;	\
124 		/* len < sizeof(obj_) */				\
125 		if (plen > 0)						\
126 			TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),		\
127 				(init_msg_), (print_msg_),		\
128 				(nla_type_), (nla_type_str_),		\
129 				plen, (pattern_), plen,			\
130 				(fallback_func)((pattern_), plen));	\
131 		/* short read of sizeof(obj_) */			\
132 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
133 			(init_msg_), (print_msg_),			\
134 			(nla_type_), (nla_type_str_),			\
135 			sizeof(obj_),					\
136 			(pattern_), sizeof(obj_) - 1,			\
137 			printf("%p",					\
138 			       RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))));	\
139 		/* sizeof(obj_) */					\
140 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
141 			(init_msg_), (print_msg_),			\
142 			(nla_type_), (nla_type_str_),			\
143 			sizeof(obj_),					\
144 			&(obj_), sizeof(obj_),				\
145 			__VA_ARGS__);					\
146 	} while (0)
147 
148 #define TEST_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_,			\
149 			      init_msg_, print_msg_,			\
150 			      nla_type_,				\
151 			      pattern_, obj_, fallback_func, ...)	\
152 	TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),		\
153 			       (init_msg_), (print_msg_),		\
154 			       (nla_type_), #nla_type_,			\
155 			       (pattern_), (obj_), (fallback_func),	\
156 			       __VA_ARGS__)
157 
158 #define TEST_NLATTR_OBJECT(fd_, nlh0_, hdrlen_,				\
159 			   init_msg_, print_msg_,			\
160 			   nla_type_, pattern_, obj_, ...)		\
161 	TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),		\
162 			       (init_msg_), (print_msg_),		\
163 			       (nla_type_), #nla_type_,			\
164 			       (pattern_), (obj_), print_quoted_hex,	\
165 			       __VA_ARGS__)
166 
167 #define TEST_NLATTR_ARRAY(fd_, nlh0_, hdrlen_,				\
168 			  init_msg_, print_msg_,			\
169 			  nla_type_, pattern_, obj_, print_elem_)	\
170 	do {								\
171 		const unsigned int plen =				\
172 			sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN		\
173 			? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1;	\
174 		/* len < sizeof((obj_)[0]) */				\
175 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
176 			(init_msg_), (print_msg_),			\
177 			(nla_type_), #nla_type_,			\
178 			plen, (pattern_), plen,				\
179 			print_quoted_hex((pattern_), plen));		\
180 		/* sizeof((obj_)[0]) < len < sizeof(obj_) */		\
181 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
182 			(init_msg_), (print_msg_),			\
183 			(nla_type_), #nla_type_,			\
184 			sizeof(obj_) - 1,				\
185 			&(obj_), sizeof(obj_) - 1,			\
186 			printf("[");					\
187 			size_t i;					\
188 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
189 				if (i) printf(", ");			\
190 				(print_elem_)(&(obj_)[i], i);		\
191 			}						\
192 			printf("]"));					\
193 		/* short read of sizeof(obj_) */			\
194 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
195 			(init_msg_), (print_msg_),			\
196 			(nla_type_), #nla_type_,			\
197 			sizeof(obj_),					\
198 			&(obj_), sizeof(obj_) - 1,			\
199 			printf("[");					\
200 			size_t i;					\
201 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
202 				if (i) printf(", ");			\
203 				(print_elem_)(&(obj_)[i], i);		\
204 			}						\
205 			printf(", ... /* %p */]",			\
206 			       RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))	\
207 			        + sizeof(obj_) - sizeof((obj_)[0])));	\
208 		/* sizeof(obj_) */					\
209 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
210 			(init_msg_), (print_msg_),			\
211 			(nla_type_), #nla_type_,			\
212 			sizeof(obj_),					\
213 			&(obj_), sizeof(obj_),				\
214 			printf("[");					\
215 			size_t i;					\
216 			for (i = 0; i < ARRAY_SIZE(obj_); ++i) {	\
217 				if (i) printf(", ");			\
218 				(print_elem_)(&(obj_)[i], i);		\
219 			}						\
220 			printf("]"));					\
221 	} while (0)
222 
223 #define TEST_NESTED_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_,		\
224 				      init_msg_, print_msg_,		\
225 				      nla_type_, nla_type_str_,		\
226 				      pattern_, obj_, fallback_func,	\
227 				      depth_, ...)	\
228 	do {								\
229 		const unsigned int plen =				\
230 			sizeof(obj_) - 1 > DEFAULT_STRLEN		\
231 			? DEFAULT_STRLEN : (int) sizeof(obj_) - 1;	\
232 		/* len < sizeof(obj_) */				\
233 		if (plen > 0)						\
234 			TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_, \
235 				(hdrlen_) + NLA_HDRLEN * depth_,	\
236 				(init_msg_), (print_msg_),		\
237 				(nla_type_), (nla_type_str_),		\
238 				plen, (pattern_), plen,			\
239 				(fallback_func)((pattern_), plen);	\
240 				size_t i;				\
241 				for (i = 0; i < depth_; ++i)		\
242 					printf("}"));			\
243 		/* short read of sizeof(obj_) */			\
244 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
245 			(hdrlen_) + NLA_HDRLEN * depth_,		\
246 			(init_msg_), (print_msg_),			\
247 			(nla_type_), (nla_type_str_),			\
248 			sizeof(obj_),					\
249 			(pattern_), sizeof(obj_) - 1,			\
250 			printf("%p", RTA_DATA(TEST_NLATTR_nla));	\
251 			size_t i;					\
252 			for (i = 0; i < depth_; ++i)			\
253 				printf("}"));				\
254 		/* sizeof(obj_) */					\
255 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
256 			(hdrlen_) + NLA_HDRLEN * depth_,		\
257 			(init_msg_), (print_msg_),			\
258 			(nla_type_), (nla_type_str_),			\
259 			sizeof(obj_),					\
260 			&(obj_), sizeof(obj_),				\
261 			__VA_ARGS__;					\
262 			size_t i;					\
263 			for (i = 0; i < depth_; ++i)			\
264 				printf("}"));				\
265 	} while (0)
266 
267 #define TEST_NESTED_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_,		\
268 				     init_msg_, print_msg_,		\
269 				     nla_type_, pattern_, obj_,		\
270 				     depth_, ...)			\
271 	TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),	\
272 				      (init_msg_), (print_msg_),	\
273 				      (nla_type_), #nla_type_,		\
274 				      (pattern_), (obj_),		\
275 				      print_quoted_hex, (depth_),	\
276 				      __VA_ARGS__)
277 
278 #define TEST_NESTED_NLATTR_OBJECT(fd_, nlh0_, hdrlen_,			\
279 				  init_msg_, print_msg_,		\
280 				  nla_type_, pattern_, obj_, ...)	\
281 	TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),	\
282 				      (init_msg_), (print_msg_),	\
283 				      (nla_type_), #nla_type_,		\
284 				      (pattern_), (obj_),		\
285 				      print_quoted_hex, 1,		\
286 				      __VA_ARGS__)
287 
288 #define TEST_NESTED_NLATTR_ARRAY_EX(fd_, nlh0_, hdrlen_,		\
289 				 init_msg_, print_msg_,			\
290 				 nla_type_, pattern_, obj_, depth_,	\
291 				 print_elem_)				\
292 	do {								\
293 		const unsigned int plen =				\
294 			sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN		\
295 			? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1;	\
296 		/* len < sizeof((obj_)[0]) */				\
297 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
298 			(hdrlen_) + NLA_HDRLEN * depth_,		\
299 			(init_msg_), (print_msg_),			\
300 			(nla_type_), #nla_type_,			\
301 			plen, (pattern_), plen,				\
302 			print_quoted_hex((pattern_), plen);		\
303 			for (size_t i = 0; i < depth_; ++i)		\
304 				printf("}"));				\
305 		/* sizeof((obj_)[0]) < len < sizeof(obj_) */		\
306 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
307 			(hdrlen_) + NLA_HDRLEN * depth_,		\
308 			(init_msg_), (print_msg_),			\
309 			(nla_type_), #nla_type_,			\
310 			sizeof(obj_) - 1,				\
311 			&(obj_), sizeof(obj_) - 1,			\
312 			printf("[");					\
313 			size_t i;					\
314 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
315 				if (i) printf(", ");			\
316 				(print_elem_)(&(obj_)[i], i);		\
317 			}						\
318 			printf("]");					\
319 			for (i = 0; i < depth_; ++i)			\
320 				printf("}"));				\
321 		/* short read of sizeof(obj_) */			\
322 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
323 			(hdrlen_) + NLA_HDRLEN * depth_,		\
324 			(init_msg_), (print_msg_),			\
325 			(nla_type_), #nla_type_,			\
326 			sizeof(obj_),					\
327 			&(obj_), sizeof(obj_) - 1,			\
328 			printf("[");					\
329 			size_t i;					\
330 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
331 				if (i) printf(", ");			\
332 				(print_elem_)(&(obj_)[i], i);		\
333 			}						\
334 			printf(", ... /* %p */]",			\
335 			       RTA_DATA(TEST_NLATTR_nla)		\
336 			        + sizeof(obj_) - sizeof((obj_)[0]));	\
337 			for (i = 0; i < depth_; ++i)			\
338 				printf("}"));				\
339 		/* sizeof(obj_) */					\
340 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
341 			(hdrlen_) + NLA_HDRLEN * depth_,		\
342 			(init_msg_), (print_msg_),			\
343 			(nla_type_), #nla_type_,			\
344 			sizeof(obj_),					\
345 			&(obj_), sizeof(obj_),				\
346 			printf("[");					\
347 			size_t i;					\
348 			for (i = 0; i < ARRAY_SIZE(obj_); ++i) {	\
349 				if (i) printf(", ");			\
350 				(print_elem_)(&(obj_)[i], i);		\
351 			}						\
352 			printf("]");					\
353 			for (i = 0; i < depth_; ++i)			\
354 				printf("}"));				\
355 	} while (0)
356 
357 #define TEST_NESTED_NLATTR_ARRAY(fd_, nlh0_, hdrlen_,			\
358 				 init_msg_, print_msg_,			\
359 				 nla_type_, pattern_, obj_, print_elem_)\
360 	TEST_NESTED_NLATTR_ARRAY_EX((fd_), (nlh0_), (hdrlen_),		\
361 				    (init_msg_), (print_msg_),		\
362 				    nla_type_, (pattern_), (obj_), 1,	\
363 				    (print_elem_))
364