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 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 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