1 /*
2 * Copyright (c) 2017-2022 The strace developers.
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "tests.h"
9 #include "print_fields.h"
10
11 #include <inttypes.h>
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <string.h>
15 #include <sys/socket.h>
16 #include <unistd.h>
17 #include "netlink.h"
18 #include <linux/rtnetlink.h>
19
20 #ifndef PRINT_SOCK
21 # define PRINT_SOCK 0
22 #endif
23
24 static void
25 init_nlattr(struct nlattr *const nla,
26 const uint16_t nla_len,
27 const uint16_t nla_type,
28 const void *const src,
29 const size_t n)
30 {
31 SET_STRUCT(struct nlattr, nla,
32 .nla_len = nla_len,
33 .nla_type = nla_type,
34 );
35
36 memcpy(RTA_DATA(nla), src, n);
37 }
38
39 static void
40 print_nlattr(const unsigned int nla_len, const char *const nla_type, bool add_data)
41 {
42 printf(", %s[{nla_len=%u, nla_type=%s}, ",
43 add_data ? "[" : "", nla_len, nla_type);
44 }
45
46 static void
47 print_sockfd(int sockfd, const char *pfx, const char *sfx)
48 {
49 #if PRINT_SOCK
50 static int fd = -1;
51 static unsigned long inode;
52
53 if (sockfd < 0) {
54 printf("%s%d%s", pfx, sockfd, sfx);
55 return;
56 }
57
58 if (sockfd != fd) {
59 fd = sockfd;
60 inode = inode_of_sockfd(fd);
61 }
62
63 printf("%s%d<socket:[%lu]>%s", pfx, sockfd, inode, sfx);
64 #else
65 printf("%s%d%s", pfx, sockfd, sfx);
66 #endif
67 }
68
69 #define TEST_NLATTR_EX_(fd_, nlh0_, hdrlen_, \
70 init_msg_, print_msg_, \
71 nla_type_, nla_type_str_, \
72 nla_data_len_, nla_total_len_, \
73 src_, slen_, ...) \
74 do { \
75 struct nlmsghdr *const nlh = \
76 (nlh0_) - (NLA_HDRLEN + (slen_)); \
77 struct nlattr *const TEST_NLATTR_nla = \
78 NLMSG_ATTR(nlh, (hdrlen_)); \
79 const unsigned int nla_len = \
80 NLA_HDRLEN + (nla_data_len_); \
81 const unsigned int msg_len = \
82 NLMSG_SPACE(hdrlen_) + NLA_HDRLEN + (nla_total_len_); \
83 \
84 (init_msg_)(nlh, msg_len); \
85 init_nlattr(TEST_NLATTR_nla, nla_len, (nla_type_), \
86 (src_), (slen_)); \
87 \
88 const char *const errstr = \
89 sprintrc(sendto((fd_), nlh, msg_len, \
90 MSG_DONTWAIT, NULL, 0)); \
91 \
92 print_sockfd((fd_), "sendto(", ", ["); \
93 (print_msg_)(msg_len); \
94 print_nlattr(nla_len, (nla_type_str_), \
95 (nla_total_len_) > (nla_data_len_)); \
96 \
97 { __VA_ARGS__; } \
98 \
99 if ((nla_total_len_) > (nla_data_len_)) \
100 printf("]"); \
101 \
102 printf("]], %u, " XLAT_FMT ", NULL, 0) = %s\n", \
103 msg_len, XLAT_ARGS(MSG_DONTWAIT), errstr); \
104 } while (0)
105
106 #define TEST_NLATTR_(fd_, nlh0_, hdrlen_, \
107 init_msg_, print_msg_, \
108 nla_type_, nla_type_str_, \
109 nla_data_len_, src_, slen_, ...) \
110 TEST_NLATTR_EX_((fd_), (nlh0_), (hdrlen_), \
111 (init_msg_), (print_msg_), \
112 (nla_type_), (nla_type_str_), \
113 (nla_data_len_), (nla_data_len_), \
114 (src_), (slen_), __VA_ARGS__)
115
116 #define TEST_NLATTR(fd_, nlh0_, hdrlen_, \
117 init_msg_, print_msg_, \
118 nla_type_, \
119 nla_data_len_, src_, slen_, ...) \
120 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
121 (init_msg_), (print_msg_), \
122 (nla_type_), #nla_type_, \
123 (nla_data_len_), (src_), (slen_), __VA_ARGS__)
124
125 #define TEST_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_, \
126 init_msg_, print_msg_, \
127 nla_type_, nla_type_str_, \
128 pattern_, obj_, minsz_, fallback_func, ...) \
129 do { \
130 const unsigned int plen = MIN((minsz_) - 1, DEFAULT_STRLEN); \
131 /* len < sizeof(obj_) */ \
132 if (plen > 0) \
133 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
134 (init_msg_), (print_msg_), \
135 (nla_type_), (nla_type_str_), \
136 plen, (pattern_), plen, \
137 (fallback_func)((pattern_), plen)); \
138 /* short read of sizeof(obj_) */ \
139 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
140 (init_msg_), (print_msg_), \
141 (nla_type_), (nla_type_str_), \
142 sizeof(obj_), \
143 (pattern_), (minsz_) - 1, \
144 printf("%p", \
145 RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_))))); \
146 /* sizeof(obj_) */ \
147 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
148 (init_msg_), (print_msg_), \
149 (nla_type_), (nla_type_str_), \
150 sizeof(obj_), \
151 &(obj_), sizeof(obj_), \
152 __VA_ARGS__); \
153 } while (0)
154
155 #define TEST_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_, \
156 init_msg_, print_msg_, \
157 nla_type_, \
158 pattern_, obj_, minsz_, fallback_func, ...) \
159 TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
160 (init_msg_), (print_msg_), \
161 (nla_type_), #nla_type_, \
162 (pattern_), (obj_), (minsz_), \
163 (fallback_func), __VA_ARGS__)
164
165 #define TEST_NLATTR_OBJECT(fd_, nlh0_, hdrlen_, \
166 init_msg_, print_msg_, \
167 nla_type_, pattern_, obj_, ...) \
168 TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
169 (init_msg_), (print_msg_), \
170 (nla_type_), #nla_type_, \
171 (pattern_), (obj_), sizeof(obj_), \
172 print_quoted_hex, __VA_ARGS__)
173
174 #define TEST_NLATTR_OBJECT_(fd_, nlh0_, hdrlen_, \
175 init_msg_, print_msg_, \
176 nla_type_, nla_type_str_, pattern_, obj_, ...) \
177 TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
178 (init_msg_), (print_msg_), \
179 (nla_type_), (nla_type_str_), \
180 (pattern_), (obj_), sizeof(obj_), \
181 print_quoted_hex, __VA_ARGS__)
182
183 #define TEST_NLATTR_OBJECT_MINSZ(fd_, nlh0_, hdrlen_, \
184 init_msg_, print_msg_, \
185 nla_type_, pattern_, obj_, minsz_, ...) \
186 TEST_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
187 (init_msg_), (print_msg_), \
188 (nla_type_), #nla_type_, \
189 (pattern_), (obj_), (minsz_), \
190 print_quoted_hex, __VA_ARGS__)
191
192 #define TEST_NLATTR_ARRAY_(fd_, nlh0_, hdrlen_, \
193 init_msg_, print_msg_, \
194 nla_type_, nla_type_str_, \
195 pattern_, obj_, print_elem_) \
196 do { \
197 const unsigned int plen = \
198 sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN \
199 ? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1; \
200 /* len < sizeof((obj_)[0]) */ \
201 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
202 (init_msg_), (print_msg_), \
203 (nla_type_), (nla_type_str_), \
204 plen, (pattern_), plen, \
205 print_quoted_hex((pattern_), plen)); \
206 /* sizeof((obj_)[0]) < len < sizeof(obj_) */ \
207 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
208 (init_msg_), (print_msg_), \
209 (nla_type_), (nla_type_str_), \
210 sizeof(obj_) - 1, \
211 &(obj_), sizeof(obj_) - 1, \
212 printf("["); \
213 for (size_t i = 0; \
214 i < ARRAY_SIZE(obj_) - 1; ++i) { \
215 if (i) printf(", "); \
216 (print_elem_)(&(obj_)[i], i); \
217 } \
218 printf("]")); \
219 /* short read of sizeof(obj_) */ \
220 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
221 (init_msg_), (print_msg_), \
222 (nla_type_), (nla_type_str_), \
223 sizeof(obj_), \
224 &(obj_), sizeof(obj_) - 1, \
225 printf("["); \
226 for (size_t i = 0; \
227 i < ARRAY_SIZE(obj_) - 1; ++i) { \
228 if (i) printf(", "); \
229 (print_elem_)(&(obj_)[i], i); \
230 } \
231 printf(", ... /* %p */]", \
232 RTA_DATA(NLMSG_ATTR(nlh, (hdrlen_))) \
233 + sizeof(obj_) - sizeof((obj_)[0]))); \
234 /* sizeof(obj_) */ \
235 TEST_NLATTR_((fd_), (nlh0_), (hdrlen_), \
236 (init_msg_), (print_msg_), \
237 (nla_type_), (nla_type_str_), \
238 sizeof(obj_), \
239 &(obj_), sizeof(obj_), \
240 printf("["); \
241 for (size_t i = 0; i < ARRAY_SIZE(obj_); ++i) { \
242 if (i) printf(", "); \
243 (print_elem_)(&(obj_)[i], i); \
244 } \
245 printf("]")); \
246 } while (0)
247
248 #define TEST_NLATTR_ARRAY(fd_, nlh0_, hdrlen_, \
249 init_msg_, print_msg_, \
250 nla_type_, pattern_, obj_, print_elem_) \
251 TEST_NLATTR_ARRAY_((fd_), (nlh0_), (hdrlen_), \
252 (init_msg_), (print_msg_), \
253 (nla_type_), #nla_type_, \
254 (pattern_), (obj_), (print_elem_))
255
256 #define TEST_NESTED_NLATTR_(fd_, nlh0_, hdrlen_, \
257 init_msg_, print_msg_, \
258 nla_type_, nla_type_str_, \
259 nla_data_len_, src_, slen_, depth_, ...) \
260 TEST_NLATTR_((fd_), (nlh0_) - NLA_HDRLEN * (depth_), \
261 (hdrlen_) + NLA_HDRLEN * (depth_), \
262 (init_msg_), (print_msg_), \
263 (nla_type_), (nla_type_str_), \
264 (nla_data_len_), (src_), (slen_), \
265 __VA_ARGS__; \
266 for (size_t i = 0; i < (depth_); ++i) \
267 printf("]"))
268
269 #define TEST_NESTED_NLATTR_OBJECT_EX_MINSZ_(fd_, nlh0_, hdrlen_, \
270 init_msg_, print_msg_, \
271 nla_type_, nla_type_str_, \
272 pattern_, obj_, minsz_, \
273 fallback_func, depth_, ...) \
274 do { \
275 const unsigned int plen = \
276 sizeof(obj_) - 1 > DEFAULT_STRLEN \
277 ? DEFAULT_STRLEN : (int) sizeof(obj_) - 1; \
278 /* len < sizeof(obj_) */ \
279 if (plen > 0) \
280 TEST_NESTED_NLATTR_((fd_), (nlh0_), (hdrlen_), \
281 (init_msg_), (print_msg_), \
282 (nla_type_), (nla_type_str_), \
283 plen, (pattern_), plen, (depth_), \
284 (fallback_func)((pattern_), plen)); \
285 /* short read of sizeof(obj_) */ \
286 TEST_NESTED_NLATTR_((fd_), (nlh0_), (hdrlen_), \
287 (init_msg_), (print_msg_), \
288 (nla_type_), (nla_type_str_), \
289 sizeof(obj_), (pattern_), (minsz_) - 1, (depth_), \
290 printf("%p", RTA_DATA(TEST_NLATTR_nla))); \
291 /* sizeof(obj_) */ \
292 TEST_NESTED_NLATTR_((fd_), (nlh0_), (hdrlen_), \
293 (init_msg_), (print_msg_), \
294 (nla_type_), (nla_type_str_), \
295 sizeof(obj_), &(obj_), sizeof(obj_), (depth_), \
296 __VA_ARGS__); \
297 } while (0)
298
299 #define TEST_NESTED_NLATTR_OBJECT_EX_(fd_, nlh0_, hdrlen_, \
300 init_msg_, print_msg_, \
301 nla_type_, nla_type_str_, \
302 pattern_, obj_, \
303 fallback_func, depth_, ...) \
304 TEST_NESTED_NLATTR_OBJECT_EX_MINSZ_((fd_), (nlh0_), (hdrlen_), \
305 (init_msg_), (print_msg_), \
306 (nla_type_), (nla_type_str_), \
307 (pattern_), (obj_), sizeof(obj_), \
308 (fallback_func), (depth_), \
309 __VA_ARGS__)
310
311 #define TEST_NESTED_NLATTR_OBJECT_EX(fd_, nlh0_, hdrlen_, \
312 init_msg_, print_msg_, \
313 nla_type_, pattern_, obj_, \
314 depth_, ...) \
315 TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
316 (init_msg_), (print_msg_), \
317 (nla_type_), #nla_type_, \
318 (pattern_), (obj_), \
319 print_quoted_hex, (depth_), \
320 __VA_ARGS__)
321
322 #define TEST_NESTED_NLATTR_OBJECT(fd_, nlh0_, hdrlen_, \
323 init_msg_, print_msg_, \
324 nla_type_, pattern_, obj_, ...) \
325 TEST_NESTED_NLATTR_OBJECT_EX_((fd_), (nlh0_), (hdrlen_), \
326 (init_msg_), (print_msg_), \
327 (nla_type_), #nla_type_, \
328 (pattern_), (obj_), \
329 print_quoted_hex, 1, \
330 __VA_ARGS__)
331
332 #define TEST_NESTED_NLATTR_ARRAY_EX_(fd_, nlh0_, hdrlen_, \
333 init_msg_, print_msg_, \
334 nla_type_, nla_type_str_, \
335 pattern_, obj_, depth_, \
336 print_elem_) \
337 do { \
338 const unsigned int plen = \
339 sizeof((obj_)[0]) - 1 > DEFAULT_STRLEN \
340 ? DEFAULT_STRLEN : (int) sizeof((obj_)[0]) - 1; \
341 /* len < sizeof((obj_)[0]) */ \
342 TEST_NESTED_NLATTR_((fd_), (nlh0_), (hdrlen_), \
343 (init_msg_), (print_msg_), \
344 (nla_type_), (nla_type_str_), \
345 plen, (pattern_), plen, (depth_), \
346 print_quoted_hex((pattern_), plen)); \
347 /* sizeof((obj_)[0]) < len < sizeof(obj_) */ \
348 TEST_NESTED_NLATTR_((fd_), (nlh0_), (hdrlen_), \
349 (init_msg_), (print_msg_), \
350 (nla_type_), (nla_type_str_), \
351 sizeof(obj_) - 1, \
352 &(obj_), sizeof(obj_) - 1, (depth_), \
353 printf("["); \
354 for (size_t i = 0; \
355 i < ARRAY_SIZE(obj_) - 1; ++i) { \
356 if (i) printf(", "); \
357 (print_elem_)(&(obj_)[i], i); \
358 } \
359 printf("]")); \
360 /* short read of sizeof(obj_) */ \
361 TEST_NESTED_NLATTR_((fd_), (nlh0_), (hdrlen_), \
362 (init_msg_), (print_msg_), \
363 (nla_type_), (nla_type_str_), \
364 sizeof(obj_), \
365 &(obj_), sizeof(obj_) - 1, (depth_), \
366 printf("["); \
367 for (size_t i = 0; \
368 i < ARRAY_SIZE(obj_) - 1; ++i) { \
369 if (i) printf(", "); \
370 (print_elem_)(&(obj_)[i], i); \
371 } \
372 printf(", ... /* %p */]", \
373 RTA_DATA(TEST_NLATTR_nla) \
374 + sizeof(obj_) - sizeof((obj_)[0]))); \
375 /* sizeof(obj_) */ \
376 TEST_NESTED_NLATTR_((fd_), (nlh0_), (hdrlen_), \
377 (init_msg_), (print_msg_), \
378 (nla_type_), (nla_type_str_), \
379 sizeof(obj_), &(obj_), sizeof(obj_), (depth_), \
380 printf("["); \
381 for (size_t i = 0; i < ARRAY_SIZE(obj_); ++i) { \
382 if (i) printf(", "); \
383 (print_elem_)(&(obj_)[i], i); \
384 } \
385 printf("]")); \
386 } while (0)
387
388 #define TEST_NESTED_NLATTR_ARRAY_EX(fd_, nlh0_, hdrlen_, \
389 init_msg_, print_msg_, \
390 nla_type_, pattern_, obj_, depth_, \
391 print_elem_) \
392 TEST_NESTED_NLATTR_ARRAY_EX_(fd_, nlh0_, hdrlen_, \
393 init_msg_, print_msg_, \
394 nla_type_, #nla_type_, pattern_, \
395 obj_, depth_, print_elem_)
396
397 #define TEST_NESTED_NLATTR_ARRAY(fd_, nlh0_, hdrlen_, \
398 init_msg_, print_msg_, \
399 nla_type_, pattern_, obj_, print_elem_)\
400 TEST_NESTED_NLATTR_ARRAY_EX((fd_), (nlh0_), (hdrlen_), \
401 (init_msg_), (print_msg_), \
402 nla_type_, (pattern_), (obj_), 1, \
403 (print_elem_))
404
405
406 /* Checks for specific typical decoders */
407 #define DEF_NLATTR_INTEGER_CHECK_(nla_data_name_, nla_data_type_, fmt_) \
408 static inline void \
409 check_##nla_data_name_##_nlattr(int fd, void *nlh0, size_t hdrlen, \
410 void (*init_msg)(struct nlmsghdr *, \
411 unsigned int), \
412 void (*print_msg)(unsigned int), \
413 unsigned int nla_type, \
414 const char *nla_type_str, \
415 void *pattern, size_t depth) \
416 { \
417 static const nla_data_type_ vecs[] = { \
418 (nla_data_type_) 0, \
419 (nla_data_type_) 1, \
420 (nla_data_type_) 0xdeadfacebeeffeedULL, \
421 }; \
422 static char buf[sizeof(nla_data_type_) + 8]; \
423 for (size_t i = 0; i < ARRAY_SIZE(vecs); i++) { \
424 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, \
425 init_msg, print_msg, \
426 nla_type, nla_type_str, \
427 pattern, vecs[i], \
428 print_quoted_hex, depth, \
429 printf(fmt_, vecs[i])); \
430 fill_memory(buf, sizeof(buf)); \
431 memcpy(buf, vecs + i, sizeof(vecs[i])); \
432 TEST_NLATTR_(fd, nlh0 - NLA_HDRLEN * depth, \
433 hdrlen + NLA_HDRLEN * depth, \
434 init_msg, print_msg, \
435 nla_type, nla_type_str, \
436 sizeof(vecs[i]) + 8, \
437 buf, sizeof(vecs[i]) + 8, \
438 printf(fmt_, vecs[i]); \
439 for (size_t i = 0; i < depth; i++) \
440 printf("]")); \
441 } \
442 }
443
444 DEF_NLATTR_INTEGER_CHECK_(u8, uint8_t, "%hhu")
445 DEF_NLATTR_INTEGER_CHECK_(u16, uint16_t, "%hu")
446 DEF_NLATTR_INTEGER_CHECK_(u32, uint32_t, "%u")
447 DEF_NLATTR_INTEGER_CHECK_(u64, uint64_t, "%" PRIu64)
448
449 DEF_NLATTR_INTEGER_CHECK_(x16, uint16_t, "%#hx")
450 DEF_NLATTR_INTEGER_CHECK_(x32, uint32_t, "%#x")
451
452 #define TEST_NLATTR_VAL(type_, fd_, nlh0_, hdrlen_, \
453 init_msg_, print_msg_, \
454 nla_type_, pattern_, depth_) \
455 check_##type_##_nlattr((fd_), (nlh0_), (hdrlen_), \
456 (init_msg_), (print_msg_), \
457 (nla_type_), #nla_type_, (pattern_), (depth_))
458
459 static inline void
460 check_clock_t_nlattr(int fd, void *nlh0, size_t hdrlen,
461 void (*init_msg)(struct nlmsghdr *, unsigned int),
462 void (*print_msg)(unsigned int),
463 unsigned int nla_type, const char *nla_type_str,
464 size_t depth)
465 {
466 static const uint64_t vecs[] = { 0, 1, 9, 10, 99, 100, 249, 250, 999,
467 1000, 1023, 1024, 0xdefacebeeffedULL };
468 static char buf[sizeof(uint64_t) + 1];
469 #if !XLAT_RAW
470 static long clk_tck;
471 static int precision;
472
473 if (!clk_tck) {
474 clk_tck = sysconf(_SC_CLK_TCK);
475 precision = clk_tck > 100000000 ? 9
476 : clk_tck > 10000000 ? 8
477 : clk_tck > 1000000 ? 7
478 : clk_tck > 100000 ? 6
479 : clk_tck > 10000 ? 5
480 : clk_tck > 1000 ? 4
481 : clk_tck > 100 ? 3
482 : clk_tck > 10 ? 2
483 : clk_tck > 1 ? 1 : 0;
484 }
485 #endif
486
487 fill_memory(buf, sizeof(buf));
488 TEST_NLATTR_(fd, nlh0 - NLA_HDRLEN * depth, hdrlen + NLA_HDRLEN * depth,
489 init_msg, print_msg, nla_type, nla_type_str,
490 sizeof(vecs[0]) + 1, buf, sizeof(vecs[0]) + 1,
491 print_quoted_hex(buf, sizeof(vecs[0]) + 1);
492 for (size_t i = 0; i < depth; i++)
493 printf("]"));
494
495 for (size_t i = 0; i < ARRAY_SIZE(vecs); i++) {
496 memcpy(buf, vecs + i, sizeof(vecs[i]));
497 TEST_NLATTR_(fd, nlh0 - NLA_HDRLEN * depth,
498 hdrlen + NLA_HDRLEN * depth,
499 init_msg, print_msg, nla_type, nla_type_str,
500 sizeof(vecs[i]),
501 buf, sizeof(vecs[i]),
502 printf("%" PRIu64, vecs[i]);
503 #if !XLAT_RAW
504 if (i)
505 printf(" /* %.*f s */", precision,
506 (double) vecs[i] / clk_tck);
507 #endif
508 for (size_t i = 0; i < depth; i++)
509 printf("]"));
510 }
511 for (size_t i = 1; i < sizeof(vecs[0]); i++) {
512 uint64_t val = vecs[ARRAY_SIZE(vecs) - 1] & MASK64(i * 8);
513 TEST_NLATTR_(fd, nlh0 - NLA_HDRLEN * depth,
514 hdrlen + NLA_HDRLEN * depth,
515 init_msg, print_msg, nla_type, nla_type_str,
516 i, buf + BE_LE(sizeof(vecs[0]) - i, 0), i,
517 printf("%" PRIu64, val);
518 #if !XLAT_RAW
519 printf(" /* %.*f s */", precision,
520 (double) val / clk_tck);
521 #endif
522 for (size_t i = 0; i < depth; i++)
523 printf("]"));
524 }
525 }