1 /*
2  * Copyright (c) 2017 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)54 print_nlattr(const unsigned int nla_len, const char *const nla_type)
55 {
56 	printf(", {{nla_len=%u, nla_type=%s}, ", nla_len, nla_type);
57 }
58 
59 #define TEST_NLATTR_(fd_, nlh0_, hdrlen_,				\
60 		     init_msg_, print_msg_,				\
61 		     nla_type_, nla_type_str_,				\
62 		     nla_data_len_, src_, slen_, ...)			\
63 	do {								\
64 		struct nlmsghdr *const nlh =				\
65 			(nlh0_) - (NLA_HDRLEN + (slen_));		\
66 		struct nlattr *const TEST_NLATTR_nla =			\
67 			NLMSG_ATTR(nlh, (hdrlen_));			\
68 		const unsigned int nla_len =				\
69 			NLA_HDRLEN + (nla_data_len_);			\
70 		const unsigned int msg_len =				\
71 			NLMSG_SPACE(hdrlen_) + nla_len;			\
72 									\
73 		(init_msg_)(nlh, msg_len);				\
74 		init_nlattr(TEST_NLATTR_nla, nla_len, (nla_type_),	\
75 			   (src_), (slen_));				\
76 									\
77 		const char *const errstr =				\
78 			sprintrc(sendto((fd_), nlh, msg_len,		\
79 					MSG_DONTWAIT, NULL, 0));	\
80 									\
81 		printf("sendto(%d, {", (fd_));				\
82 		(print_msg_)(msg_len);					\
83 		print_nlattr(nla_len, (nla_type_str_));			\
84 									\
85 		{ __VA_ARGS__; }					\
86 									\
87 		printf("}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n",		\
88 		       msg_len, errstr);				\
89 	} while (0)
90 
91 #define TEST_NLATTR(fd_, nlh0_, hdrlen_,				\
92 		    init_msg_, print_msg_,				\
93 		    nla_type_,						\
94 		    nla_data_len_, src_, slen_, ...)			\
95 	TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),				\
96 		(init_msg_), (print_msg_),				\
97 		(nla_type_), #nla_type_,				\
98 		(nla_data_len_), (src_), (slen_), __VA_ARGS__)
99 
100 #define TEST_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_,			\
101 			       init_msg_, print_msg_,			\
102 			       nla_type_, nla_type_str_,		\
103 			       pattern_, obj_, fallback_func, ...)	\
104 	do {								\
105 		const unsigned int plen =				\
106 			sizeof(obj_) - 1 > DEFAULT_STRLEN		\
107 			? DEFAULT_STRLEN : (int) sizeof(obj_) - 1;	\
108 		/* len < sizeof(obj_) */				\
109 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
110 			(init_msg_), (print_msg_),			\
111 			(nla_type_), (nla_type_str_),			\
112 			plen, (pattern_), plen,				\
113 			(fallback_func)((pattern_), plen));		\
114 		/* short read of sizeof(obj_) */			\
115 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
116 			(init_msg_), (print_msg_),			\
117 			(nla_type_), (nla_type_str_),			\
118 			sizeof(obj_),					\
119 			(pattern_), sizeof(obj_) - 1,			\
120 			printf("%p",					\
121 			       RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))));	\
122 		/* sizeof(obj_) */					\
123 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
124 			(init_msg_), (print_msg_),			\
125 			(nla_type_), (nla_type_str_),			\
126 			sizeof(obj_),					\
127 			&(obj_), sizeof(obj_),				\
128 			__VA_ARGS__);					\
129 	} while (0)
130 
131 #define TEST_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_,			\
132 			      init_msg_, print_msg_,			\
133 			      nla_type_,				\
134 			      pattern_, obj_, fallback_func, ...)	\
135 	TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),		\
136 			       (init_msg_), (print_msg_),		\
137 			       (nla_type_), #nla_type_,			\
138 			       (pattern_), (obj_), (fallback_func),	\
139 			       __VA_ARGS__)
140 
141 #define TEST_NLATTR_OBJECT(fd_, nlh0_, hdrlen_,				\
142 			   init_msg_, print_msg_,			\
143 			   nla_type_, pattern_, obj_, ...)		\
144 	TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),		\
145 			       (init_msg_), (print_msg_),		\
146 			       (nla_type_), #nla_type_,			\
147 			       (pattern_), (obj_), print_quoted_hex,	\
148 			       __VA_ARGS__)
149 
150 #define TEST_NLATTR_ARRAY(fd_, nlh0_, hdrlen_,				\
151 			  init_msg_, print_msg_,			\
152 			  nla_type_, pattern_, obj_, print_elem_)	\
153 	do {								\
154 		const unsigned int plen =				\
155 			sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN		\
156 			? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1;	\
157 		/* len < sizeof((obj_)[0]) */				\
158 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
159 			(init_msg_), (print_msg_),			\
160 			(nla_type_), #nla_type_,			\
161 			plen, (pattern_), plen,				\
162 			print_quoted_hex((pattern_), plen));		\
163 		/* sizeof((obj_)[0]) < len < sizeof(obj_) */		\
164 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
165 			(init_msg_), (print_msg_),			\
166 			(nla_type_), #nla_type_,			\
167 			sizeof(obj_) - 1,				\
168 			&(obj_), sizeof(obj_) - 1,			\
169 			printf("[");					\
170 			size_t i;					\
171 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
172 				if (i) printf(", ");			\
173 				(print_elem_)(&(obj_)[i]);		\
174 			}						\
175 			printf("]"));					\
176 		/* short read of sizeof(obj_) */			\
177 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
178 			(init_msg_), (print_msg_),			\
179 			(nla_type_), #nla_type_,			\
180 			sizeof(obj_),					\
181 			&(obj_), sizeof(obj_) - 1,			\
182 			printf("[");					\
183 			size_t i;					\
184 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
185 				if (i) printf(", ");			\
186 				(print_elem_)(&(obj_)[i]);		\
187 			}						\
188 			printf(", %p]",					\
189 			       RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_)))	\
190 			        + sizeof((obj_)[0])));			\
191 		/* sizeof(obj_) */					\
192 		TEST_NLATTR_((fd_), (nlh0_), (hdrlen_),			\
193 			(init_msg_), (print_msg_),			\
194 			(nla_type_), #nla_type_,			\
195 			sizeof(obj_),					\
196 			&(obj_), sizeof(obj_),				\
197 			printf("[");					\
198 			size_t i;					\
199 			for (i = 0; i < ARRAY_SIZE(obj_); ++i) {	\
200 				if (i) printf(", ");			\
201 				(print_elem_)(&(obj_)[i]);		\
202 			}						\
203 			printf("]"));					\
204 	} while (0)
205 
206 #define TEST_NESTED_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_,		\
207 				      init_msg_, print_msg_,		\
208 				      nla_type_, nla_type_str_,		\
209 				      pattern_, obj_, depth_, ...)	\
210 	do {								\
211 		const unsigned int plen =				\
212 			sizeof(obj_) - 1 > DEFAULT_STRLEN		\
213 			? DEFAULT_STRLEN : (int) sizeof(obj_) - 1;	\
214 		/* len < sizeof(obj_) */				\
215 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
216 			(hdrlen_) + NLA_HDRLEN * depth_,		\
217 			(init_msg_), (print_msg_),			\
218 			(nla_type_), (nla_type_str_),			\
219 			plen, (pattern_), plen,				\
220 			print_quoted_hex((pattern_), plen);		\
221 			size_t i;					\
222 			for (i = 0; i < depth_; ++i)			\
223 				printf("}"));				\
224 		/* short read of sizeof(obj_) */			\
225 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
226 			(hdrlen_) + NLA_HDRLEN * depth_,		\
227 			(init_msg_), (print_msg_),			\
228 			(nla_type_), (nla_type_str_),			\
229 			sizeof(obj_),					\
230 			(pattern_), sizeof(obj_) - 1,			\
231 			printf("%p", RTA_DATA(TEST_NLATTR_nla));	\
232 			size_t i;					\
233 			for (i = 0; i < depth_; ++i)			\
234 				printf("}"));				\
235 		/* sizeof(obj_) */					\
236 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * depth_,	\
237 			(hdrlen_) + NLA_HDRLEN * depth_,		\
238 			(init_msg_), (print_msg_),			\
239 			(nla_type_), (nla_type_str_),			\
240 			sizeof(obj_),					\
241 			&(obj_), sizeof(obj_),				\
242 			__VA_ARGS__;					\
243 			size_t i;					\
244 			for (i = 0; i < depth_; ++i)			\
245 				printf("}"));				\
246 	} while (0)
247 
248 #define TEST_NESTED_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_,		\
249 				     init_msg_, print_msg_,		\
250 				     nla_type_, pattern_, obj_,		\
251 				     depth_, ...)			\
252 	TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),	\
253 				      (init_msg_), (print_msg_),	\
254 				      (nla_type_), #nla_type_,		\
255 				      (pattern_), (obj_), (depth_),	\
256 				      __VA_ARGS__)
257 
258 #define TEST_NESTED_NLATTR_OBJECT(fd_, nlh0_, hdrlen_,			\
259 				  init_msg_, print_msg_,		\
260 				  nla_type_, pattern_, obj_, ...)	\
261 	TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_),	\
262 				      (init_msg_), (print_msg_),	\
263 				      (nla_type_), #nla_type_,		\
264 				      (pattern_), (obj_), 1,		\
265 				      __VA_ARGS__)
266 
267 #define TEST_NESTED_NLATTR_ARRAY(fd_, nlh0_, hdrlen_,			\
268 				 init_msg_, print_msg_,			\
269 				 nla_type_, pattern_, obj_, print_elem_)\
270 	do {								\
271 		const unsigned int plen =				\
272 			sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN		\
273 			? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1;	\
274 		/* len < sizeof((obj_)[0]) */				\
275 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN,		\
276 			(hdrlen_) + NLA_HDRLEN,				\
277 			(init_msg_), (print_msg_),			\
278 			(nla_type_), #nla_type_,			\
279 			plen, (pattern_), plen,				\
280 			print_quoted_hex((pattern_), plen);		\
281 			printf("}"));					\
282 		/* sizeof((obj_)[0]) < len < sizeof(obj_) */		\
283 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN,		\
284 			(hdrlen_) + NLA_HDRLEN,				\
285 			(init_msg_), (print_msg_),			\
286 			(nla_type_), #nla_type_,			\
287 			sizeof(obj_) - 1,				\
288 			&(obj_), sizeof(obj_) - 1,			\
289 			printf("[");					\
290 			size_t i;					\
291 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
292 				if (i) printf(", ");			\
293 				(print_elem_)(&(obj_)[i]);		\
294 			}						\
295 			printf("]}"));					\
296 		/* short read of sizeof(obj_) */			\
297 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN,		\
298 			(hdrlen_) + NLA_HDRLEN,				\
299 			(init_msg_), (print_msg_),			\
300 			(nla_type_), #nla_type_,			\
301 			sizeof(obj_),					\
302 			&(obj_), sizeof(obj_) - 1,			\
303 			printf("[");					\
304 			size_t i;					\
305 			for (i = 0; i < ARRAY_SIZE(obj_) - 1; ++i) {	\
306 				if (i) printf(", ");			\
307 				(print_elem_)(&(obj_)[i]);		\
308 			}						\
309 			printf(", %p]}",				\
310 			       RTA_DATA(TEST_NLATTR_nla)		\
311 			        + sizeof((obj_)[0])));			\
312 		/* sizeof(obj_) */					\
313 		TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN,		\
314 			(hdrlen_) + NLA_HDRLEN,				\
315 			(init_msg_), (print_msg_),			\
316 			(nla_type_), #nla_type_,			\
317 			sizeof(obj_),					\
318 			&(obj_), sizeof(obj_),				\
319 			printf("[");					\
320 			size_t i;					\
321 			for (i = 0; i < ARRAY_SIZE(obj_); ++i) {	\
322 				if (i) printf(", ");			\
323 				(print_elem_)(&(obj_)[i]);		\
324 			}						\
325 			printf("]}"));					\
326 	} while (0)
327