1 /* 2 * Copyright (c) 2016 Fabien Siron <fabien.siron (at) epita.fr> 3 * Copyright (c) 2016 Dmitry V. Levin <ldv (at) altlinux.org> 4 * Copyright (c) 2016-2018 The strace developers. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "defs.h" 31 #include "netlink.h" 32 #include "nlattr.h" 33 #include <linux/audit.h> 34 #include <linux/rtnetlink.h> 35 #include <linux/xfrm.h> 36 #include "xlat/netlink_ack_flags.h" 37 #include "xlat/netlink_delete_flags.h" 38 #include "xlat/netlink_flags.h" 39 #include "xlat/netlink_get_flags.h" 40 #include "xlat/netlink_new_flags.h" 41 #include "xlat/netlink_protocols.h" 42 #include "xlat/netlink_types.h" 43 #include "xlat/nf_acct_msg_types.h" 44 #include "xlat/nf_cthelper_msg_types.h" 45 #include "xlat/nf_ctnetlink_exp_msg_types.h" 46 #include "xlat/nf_ctnetlink_msg_types.h" 47 #include "xlat/nf_cttimeout_msg_types.h" 48 #include "xlat/nf_ipset_msg_types.h" 49 #include "xlat/nf_nft_compat_msg_types.h" 50 #include "xlat/nf_nftables_msg_types.h" 51 #include "xlat/nf_osf_msg_types.h" 52 #include "xlat/nf_queue_msg_types.h" 53 #include "xlat/nf_ulog_msg_types.h" 54 #include "xlat/nl_audit_types.h" 55 #include "xlat/nl_crypto_types.h" 56 #include "xlat/nl_netfilter_subsys_ids.h" 57 #include "xlat/nl_selinux_types.h" 58 #include "xlat/nl_sock_diag_types.h" 59 #include "xlat/nl_xfrm_types.h" 60 #include "xlat/nlmsgerr_attrs.h" 61 62 /* 63 * Fetch a struct nlmsghdr from the given address. 64 */ 65 static bool 66 fetch_nlmsghdr(struct tcb *const tcp, struct nlmsghdr *const nlmsghdr, 67 const kernel_ulong_t addr, const kernel_ulong_t len, 68 const bool in_array) 69 { 70 if (len < sizeof(struct nlmsghdr)) { 71 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); 72 return false; 73 } 74 75 if (tfetch_obj(tcp, addr, nlmsghdr)) 76 return true; 77 78 if (in_array) { 79 tprints("..."); 80 printaddr_comment(addr); 81 } else { 82 printaddr(addr); 83 } 84 85 return false; 86 } 87 88 static int 89 get_fd_nl_family(struct tcb *const tcp, const int fd) 90 { 91 const unsigned long inode = getfdinode(tcp, fd); 92 if (!inode) 93 return -1; 94 95 const char *const details = get_sockaddr_by_inode(tcp, fd, inode); 96 if (!details) 97 return -1; 98 99 const char *const nl_details = STR_STRIP_PREFIX(details, "NETLINK:["); 100 if (nl_details == details) 101 return -1; 102 103 const struct xlat *xlats = netlink_protocols; 104 for (; xlats->str; ++xlats) { 105 const char *name = STR_STRIP_PREFIX(xlats->str, "NETLINK_"); 106 if (!strncmp(nl_details, name, strlen(name))) 107 return xlats->val; 108 } 109 110 if (*nl_details >= '0' && *nl_details <= '9') 111 return atoi(nl_details); 112 113 return -1; 114 } 115 116 static void 117 decode_nlmsg_type_default(struct tcb *tcp, const struct xlat *const xlat, 118 const uint16_t type, 119 const char *const dflt) 120 { 121 printxval(xlat, type, dflt); 122 } 123 124 static void 125 decode_nlmsg_type_generic(struct tcb *tcp, const struct xlat *const xlat, 126 const uint16_t type, 127 const char *const dflt) 128 { 129 printxval(genl_families_xlat(tcp), type, dflt); 130 } 131 132 static const struct { 133 const struct xlat *const xlat; 134 const char *const dflt; 135 } nf_nlmsg_types[] = { 136 [NFNL_SUBSYS_CTNETLINK] = { 137 nf_ctnetlink_msg_types, 138 "IPCTNL_MSG_CT_???" 139 }, 140 [NFNL_SUBSYS_CTNETLINK_EXP] = { 141 nf_ctnetlink_exp_msg_types, 142 "IPCTNL_MSG_EXP_???" 143 }, 144 [NFNL_SUBSYS_QUEUE] = { nf_queue_msg_types, "NFQNL_MSG_???" }, 145 [NFNL_SUBSYS_ULOG] = { nf_ulog_msg_types, "NFULNL_MSG_???" }, 146 [NFNL_SUBSYS_OSF] = { nf_osf_msg_types, "OSF_MSG_???" }, 147 [NFNL_SUBSYS_IPSET] = { nf_ipset_msg_types, "IPSET_CMD_???" }, 148 [NFNL_SUBSYS_ACCT] = { nf_acct_msg_types, "NFNL_MSG_ACCT_???" }, 149 [NFNL_SUBSYS_CTNETLINK_TIMEOUT] = { 150 nf_cttimeout_msg_types, 151 "IPCTNL_MSG_TIMEOUT_???" 152 }, 153 [NFNL_SUBSYS_CTHELPER] = { 154 nf_cthelper_msg_types, 155 "NFNL_MSG_CTHELPER_???" 156 }, 157 [NFNL_SUBSYS_NFTABLES] = { nf_nftables_msg_types, "NFT_MSG_???" }, 158 [NFNL_SUBSYS_NFT_COMPAT] = { 159 nf_nft_compat_msg_types, 160 "NFNL_MSG_COMPAT_???" 161 } 162 }; 163 164 static void 165 decode_nlmsg_type_netfilter(struct tcb *tcp, const struct xlat *const xlat, 166 const uint16_t type, 167 const char *const dflt) 168 { 169 /* Reserved control nfnetlink messages first. */ 170 const char *const text = xlookup(nl_netfilter_msg_types, type); 171 if (text) { 172 print_xlat_ex(type, text, XLAT_STYLE_DEFAULT); 173 return; 174 } 175 176 /* 177 * Other netfilter message types are split 178 * in two pieces: 8 bits subsystem and 8 bits type. 179 */ 180 const uint8_t subsys_id = (uint8_t) (type >> 8); 181 const uint8_t msg_type = (uint8_t) type; 182 183 printxval(xlat, subsys_id, dflt); 184 185 tprints("<<8|"); 186 if (subsys_id < ARRAY_SIZE(nf_nlmsg_types)) 187 printxval(nf_nlmsg_types[subsys_id].xlat, 188 msg_type, nf_nlmsg_types[subsys_id].dflt); 189 else 190 tprintf("%#x", msg_type); 191 } 192 193 typedef void (*nlmsg_types_decoder_t)(struct tcb *, const struct xlat *, 194 uint16_t type, 195 const char *dflt); 196 197 static const struct { 198 const nlmsg_types_decoder_t decoder; 199 const struct xlat *const xlat; 200 const char *const dflt; 201 } nlmsg_types[] = { 202 [NETLINK_AUDIT] = { NULL, nl_audit_types, "AUDIT_???" }, 203 [NETLINK_CRYPTO] = { NULL, nl_crypto_types, "CRYPTO_MSG_???" }, 204 [NETLINK_GENERIC] = { 205 decode_nlmsg_type_generic, 206 NULL, 207 "GENERIC_FAMILY_???" 208 }, 209 [NETLINK_NETFILTER] = { 210 decode_nlmsg_type_netfilter, 211 nl_netfilter_subsys_ids, 212 "NFNL_SUBSYS_???" 213 }, 214 [NETLINK_ROUTE] = { NULL, nl_route_types, "RTM_???" }, 215 [NETLINK_SELINUX] = { NULL, nl_selinux_types, "SELNL_MSG_???" }, 216 [NETLINK_SOCK_DIAG] = { NULL, nl_sock_diag_types, "SOCK_DIAG_???" }, 217 [NETLINK_XFRM] = { NULL, nl_xfrm_types, "XFRM_MSG_???" } 218 }; 219 220 /* 221 * As all valid netlink families are positive integers, use unsigned int 222 * for family here to filter out -1. 223 */ 224 static void 225 decode_nlmsg_type(struct tcb *tcp, const uint16_t type, 226 const unsigned int family) 227 { 228 nlmsg_types_decoder_t decoder = decode_nlmsg_type_default; 229 const struct xlat *xlat = netlink_types; 230 const char *dflt = "NLMSG_???"; 231 232 /* 233 * type < NLMSG_MIN_TYPE are reserved control messages 234 * that need no family-specific decoding. 235 */ 236 if (type >= NLMSG_MIN_TYPE && family < ARRAY_SIZE(nlmsg_types)) { 237 if (nlmsg_types[family].decoder) 238 decoder = nlmsg_types[family].decoder; 239 if (nlmsg_types[family].xlat) 240 xlat = nlmsg_types[family].xlat; 241 if (nlmsg_types[family].dflt) 242 dflt = nlmsg_types[family].dflt; 243 } 244 245 decoder(tcp, xlat, type, dflt); 246 } 247 248 static const struct xlat * 249 decode_nlmsg_flags_crypto(const uint16_t type) 250 { 251 switch (type) { 252 case CRYPTO_MSG_NEWALG: 253 return netlink_new_flags; 254 case CRYPTO_MSG_DELALG: 255 case CRYPTO_MSG_DELRNG: 256 return netlink_delete_flags; 257 case CRYPTO_MSG_GETALG: 258 return netlink_get_flags; 259 } 260 261 return NULL; 262 } 263 264 static const struct xlat * 265 decode_nlmsg_flags_netfilter(const uint16_t type) 266 { 267 const uint8_t subsys_id = (uint8_t) (type >> 8); 268 const uint8_t msg_type = (uint8_t) type; 269 270 switch (subsys_id) { 271 case NFNL_SUBSYS_CTNETLINK: 272 switch (msg_type) { 273 case IPCTNL_MSG_CT_NEW: 274 return netlink_new_flags; 275 case IPCTNL_MSG_CT_GET: 276 case IPCTNL_MSG_CT_GET_CTRZERO: 277 case IPCTNL_MSG_CT_GET_STATS_CPU: 278 case IPCTNL_MSG_CT_GET_STATS: 279 case IPCTNL_MSG_CT_GET_DYING: 280 case IPCTNL_MSG_CT_GET_UNCONFIRMED: 281 return netlink_get_flags; 282 case IPCTNL_MSG_CT_DELETE: 283 return netlink_delete_flags; 284 } 285 break; 286 case NFNL_SUBSYS_CTNETLINK_EXP: 287 switch (msg_type) { 288 case IPCTNL_MSG_EXP_NEW: 289 return netlink_new_flags; 290 case IPCTNL_MSG_EXP_GET: 291 case IPCTNL_MSG_EXP_GET_STATS_CPU: 292 return netlink_get_flags; 293 case IPCTNL_MSG_EXP_DELETE: 294 return netlink_delete_flags; 295 } 296 break; 297 case NFNL_SUBSYS_ACCT: 298 switch (msg_type) { 299 case NFNL_MSG_ACCT_NEW: 300 return netlink_new_flags; 301 case NFNL_MSG_ACCT_GET: 302 case NFNL_MSG_ACCT_GET_CTRZERO: 303 return netlink_get_flags; 304 case NFNL_MSG_ACCT_DEL: 305 return netlink_delete_flags; 306 } 307 break; 308 case NFNL_SUBSYS_CTNETLINK_TIMEOUT: 309 switch (msg_type) { 310 case IPCTNL_MSG_TIMEOUT_NEW: 311 return netlink_new_flags; 312 case IPCTNL_MSG_TIMEOUT_GET: 313 return netlink_get_flags; 314 case IPCTNL_MSG_TIMEOUT_DELETE: 315 return netlink_delete_flags; 316 } 317 break; 318 case NFNL_SUBSYS_CTHELPER: 319 switch (msg_type) { 320 case NFNL_MSG_CTHELPER_NEW: 321 return netlink_new_flags; 322 case NFNL_MSG_CTHELPER_GET: 323 return netlink_get_flags; 324 case NFNL_MSG_CTHELPER_DEL: 325 return netlink_delete_flags; 326 } 327 break; 328 case NFNL_SUBSYS_NFTABLES: 329 switch (msg_type) { 330 case NFT_MSG_NEWTABLE: 331 case NFT_MSG_NEWCHAIN: 332 case NFT_MSG_NEWRULE: 333 case NFT_MSG_NEWSET: 334 case NFT_MSG_NEWSETELEM: 335 case NFT_MSG_NEWGEN: 336 case NFT_MSG_NEWOBJ: 337 return netlink_new_flags; 338 case NFT_MSG_GETTABLE: 339 case NFT_MSG_GETCHAIN: 340 case NFT_MSG_GETRULE: 341 case NFT_MSG_GETSET: 342 case NFT_MSG_GETSETELEM: 343 case NFT_MSG_GETGEN: 344 case NFT_MSG_GETOBJ: 345 case NFT_MSG_GETOBJ_RESET: 346 return netlink_get_flags; 347 case NFT_MSG_DELTABLE: 348 case NFT_MSG_DELCHAIN: 349 case NFT_MSG_DELRULE: 350 case NFT_MSG_DELSET: 351 case NFT_MSG_DELSETELEM: 352 case NFT_MSG_DELOBJ: 353 return netlink_delete_flags; 354 } 355 break; 356 case NFNL_SUBSYS_NFT_COMPAT: 357 switch (msg_type) { 358 case NFNL_MSG_COMPAT_GET: 359 return netlink_get_flags; 360 } 361 break; 362 } 363 364 return NULL; 365 } 366 367 static const struct xlat * 368 decode_nlmsg_flags_route(const uint16_t type) 369 { 370 /* RTM_DELACTION uses NLM_F_ROOT flags */ 371 if (type == RTM_DELACTION) 372 return netlink_get_flags; 373 switch (type & 3) { 374 case 0: 375 return netlink_new_flags; 376 case 1: 377 return netlink_delete_flags; 378 case 2: 379 return netlink_get_flags; 380 } 381 382 return NULL; 383 } 384 385 static const struct xlat * 386 decode_nlmsg_flags_sock_diag(const uint16_t type) 387 { 388 return netlink_get_flags; 389 } 390 391 static const struct xlat * 392 decode_nlmsg_flags_xfrm(const uint16_t type) 393 { 394 switch (type) { 395 case XFRM_MSG_NEWSA: 396 case XFRM_MSG_NEWPOLICY: 397 case XFRM_MSG_NEWAE: 398 case XFRM_MSG_NEWSADINFO: 399 case XFRM_MSG_NEWSPDINFO: 400 return netlink_new_flags; 401 case XFRM_MSG_DELSA: 402 case XFRM_MSG_DELPOLICY: 403 return netlink_delete_flags; 404 case XFRM_MSG_GETSA: 405 case XFRM_MSG_GETPOLICY: 406 case XFRM_MSG_GETAE: 407 case XFRM_MSG_GETSADINFO: 408 case XFRM_MSG_GETSPDINFO: 409 return netlink_get_flags; 410 } 411 412 return NULL; 413 } 414 415 typedef const struct xlat *(*nlmsg_flags_decoder_t)(const uint16_t type); 416 417 static const nlmsg_flags_decoder_t nlmsg_flags[] = { 418 [NETLINK_CRYPTO] = decode_nlmsg_flags_crypto, 419 [NETLINK_NETFILTER] = decode_nlmsg_flags_netfilter, 420 [NETLINK_ROUTE] = decode_nlmsg_flags_route, 421 [NETLINK_SOCK_DIAG] = decode_nlmsg_flags_sock_diag, 422 [NETLINK_XFRM] = decode_nlmsg_flags_xfrm 423 }; 424 425 /* 426 * As all valid netlink families are positive integers, use unsigned int 427 * for family here to filter out -1. 428 */ 429 static void 430 decode_nlmsg_flags(const uint16_t flags, const uint16_t type, 431 const unsigned int family) 432 { 433 const struct xlat *table = NULL; 434 435 if (type < NLMSG_MIN_TYPE) { 436 if (type == NLMSG_ERROR) 437 table = netlink_ack_flags; 438 } else if (family < ARRAY_SIZE(nlmsg_flags) && nlmsg_flags[family]) 439 table = nlmsg_flags[family](type); 440 441 printflags_ex(flags, "NLM_F_???", XLAT_STYLE_DEFAULT, 442 netlink_flags, table, NULL); 443 } 444 445 static void 446 print_nlmsghdr(struct tcb *tcp, 447 const int fd, 448 const int family, 449 const struct nlmsghdr *const nlmsghdr) 450 { 451 /* print the whole structure regardless of its nlmsg_len */ 452 453 tprintf("{len=%u, type=", nlmsghdr->nlmsg_len); 454 455 decode_nlmsg_type(tcp, nlmsghdr->nlmsg_type, family); 456 457 tprints(", flags="); 458 decode_nlmsg_flags(nlmsghdr->nlmsg_flags, 459 nlmsghdr->nlmsg_type, family); 460 461 tprintf(", seq=%u, pid=%u}", nlmsghdr->nlmsg_seq, 462 nlmsghdr->nlmsg_pid); 463 } 464 465 static bool 466 print_cookie(struct tcb *const tcp, void *const elem_buf, 467 const size_t elem_size, void *const opaque_data) 468 { 469 tprintf("%" PRIu8, *(uint8_t *) elem_buf); 470 471 return true; 472 } 473 474 static bool 475 decode_nlmsgerr_attr_cookie(struct tcb *const tcp, 476 const kernel_ulong_t addr, 477 const unsigned int len, 478 const void *const opaque_data) 479 { 480 uint8_t cookie; 481 const size_t nmemb = len / sizeof(cookie); 482 483 print_array(tcp, addr, nmemb, &cookie, sizeof(cookie), 484 tfetch_mem, print_cookie, 0); 485 486 return true; 487 } 488 489 static const nla_decoder_t nlmsgerr_nla_decoders[] = { 490 [NLMSGERR_ATTR_MSG] = decode_nla_str, 491 [NLMSGERR_ATTR_OFFS] = decode_nla_u32, 492 [NLMSGERR_ATTR_COOKIE] = decode_nlmsgerr_attr_cookie 493 }; 494 495 static void 496 decode_nlmsghdr_with_payload(struct tcb *const tcp, 497 const int fd, 498 const int family, 499 const struct nlmsghdr *const nlmsghdr, 500 const kernel_ulong_t addr, 501 const kernel_ulong_t len); 502 503 static void 504 decode_nlmsgerr(struct tcb *const tcp, 505 const int fd, 506 const int family, 507 kernel_ulong_t addr, 508 unsigned int len, 509 const bool capped) 510 { 511 struct nlmsgerr err; 512 513 if (len < sizeof(err.error)) { 514 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); 515 return; 516 } 517 518 if (umove_or_printaddr(tcp, addr, &err.error)) 519 return; 520 521 tprints("{error="); 522 if (err.error < 0 && (unsigned) -err.error < nerrnos) { 523 tprintf("-%s", errnoent[-err.error]); 524 } else { 525 tprintf("%d", err.error); 526 } 527 528 addr += offsetof(struct nlmsgerr, msg); 529 len -= offsetof(struct nlmsgerr, msg); 530 531 if (len) { 532 tprints(", msg="); 533 if (fetch_nlmsghdr(tcp, &err.msg, addr, len, false)) { 534 unsigned int payload = 535 capped ? sizeof(err.msg) : err.msg.nlmsg_len; 536 if (payload > len) 537 payload = len; 538 539 decode_nlmsghdr_with_payload(tcp, fd, family, 540 &err.msg, addr, payload); 541 if (len > payload) { 542 tprints(", "); 543 decode_nlattr(tcp, addr + payload, 544 len - payload, nlmsgerr_attrs, 545 "NLMSGERR_ATTR_???", 546 nlmsgerr_nla_decoders, 547 ARRAY_SIZE(nlmsgerr_nla_decoders), 548 NULL); 549 } 550 } 551 } 552 553 tprints("}"); 554 } 555 556 static const netlink_decoder_t netlink_decoders[] = { 557 #ifdef HAVE_LINUX_CRYPTOUSER_H 558 [NETLINK_CRYPTO] = decode_netlink_crypto, 559 #endif 560 #ifdef HAVE_LINUX_NETFILTER_NFNETLINK_H 561 [NETLINK_NETFILTER] = decode_netlink_netfilter, 562 #endif 563 [NETLINK_ROUTE] = decode_netlink_route, 564 [NETLINK_SELINUX] = decode_netlink_selinux, 565 [NETLINK_SOCK_DIAG] = decode_netlink_sock_diag 566 }; 567 568 static void 569 decode_payload(struct tcb *const tcp, 570 const int fd, 571 const int family, 572 const struct nlmsghdr *const nlmsghdr, 573 const kernel_ulong_t addr, 574 const unsigned int len) 575 { 576 if (nlmsghdr->nlmsg_type == NLMSG_ERROR) { 577 decode_nlmsgerr(tcp, fd, family, addr, len, 578 nlmsghdr->nlmsg_flags & NLM_F_CAPPED); 579 return; 580 } 581 582 /* 583 * While most of NLMSG_DONE messages indeed have payloads 584 * containing just a single integer, there are few exceptions, 585 * so pass payloads of NLMSG_DONE messages to family-specific 586 * netlink payload decoders. 587 * 588 * Other types of reserved control messages need no family-specific 589 * netlink payload decoding. 590 */ 591 if ((nlmsghdr->nlmsg_type >= NLMSG_MIN_TYPE 592 || nlmsghdr->nlmsg_type == NLMSG_DONE) 593 && (unsigned int) family < ARRAY_SIZE(netlink_decoders) 594 && netlink_decoders[family] 595 && netlink_decoders[family](tcp, nlmsghdr, addr, len)) { 596 return; 597 } 598 599 if (nlmsghdr->nlmsg_type == NLMSG_DONE && len == sizeof(int)) { 600 int num; 601 602 if (!umove_or_printaddr(tcp, addr, &num)) 603 tprintf("%d", num); 604 return; 605 } 606 607 printstr_ex(tcp, addr, len, QUOTE_FORCE_HEX); 608 } 609 610 static void 611 decode_nlmsghdr_with_payload(struct tcb *const tcp, 612 const int fd, 613 const int family, 614 const struct nlmsghdr *const nlmsghdr, 615 const kernel_ulong_t addr, 616 const kernel_ulong_t len) 617 { 618 const unsigned int nlmsg_len = MIN(nlmsghdr->nlmsg_len, len); 619 620 if (nlmsg_len > NLMSG_HDRLEN) 621 tprints("{"); 622 623 print_nlmsghdr(tcp, fd, family, nlmsghdr); 624 625 if (nlmsg_len > NLMSG_HDRLEN) { 626 tprints(", "); 627 decode_payload(tcp, fd, family, nlmsghdr, addr + NLMSG_HDRLEN, 628 nlmsg_len - NLMSG_HDRLEN); 629 tprints("}"); 630 } 631 } 632 633 void 634 decode_netlink(struct tcb *const tcp, 635 const int fd, 636 kernel_ulong_t addr, 637 kernel_ulong_t len) 638 { 639 const int family = get_fd_nl_family(tcp, fd); 640 641 if (family == NETLINK_KOBJECT_UEVENT) { 642 decode_netlink_kobject_uevent(tcp, addr, len); 643 return; 644 } 645 646 struct nlmsghdr nlmsghdr; 647 bool is_array = false; 648 unsigned int elt; 649 650 for (elt = 0; fetch_nlmsghdr(tcp, &nlmsghdr, addr, len, is_array); 651 elt++) { 652 if (abbrev(tcp) && elt == max_strlen) { 653 tprints("..."); 654 break; 655 } 656 657 unsigned int nlmsg_len = NLMSG_ALIGN(nlmsghdr.nlmsg_len); 658 kernel_ulong_t next_addr = 0; 659 kernel_ulong_t next_len = 0; 660 661 if (nlmsghdr.nlmsg_len >= NLMSG_HDRLEN) { 662 next_len = (len >= nlmsg_len) ? len - nlmsg_len : 0; 663 664 if (next_len && addr + nlmsg_len > addr) 665 next_addr = addr + nlmsg_len; 666 } 667 668 if (!is_array && next_addr) { 669 tprints("["); 670 is_array = true; 671 } 672 673 decode_nlmsghdr_with_payload(tcp, fd, family, 674 &nlmsghdr, addr, len); 675 676 if (!next_addr) 677 break; 678 679 tprints(", "); 680 addr = next_addr; 681 len = next_len; 682 } 683 684 if (is_array) { 685 tprints("]"); 686 } 687 } 688