/* * IFLA_AF_SPEC netlink attribute decoding check. * * Copyright (c) 2018-2021 The strace developers. * All rights reserved. * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "tests.h" #include #include #include #include "test_nlattr.h" #include #include #include #include #include #include "xlat.h" #include "xlat/addrfams.h" #define XLAT_MACROS_ONLY #include "xlat/rtnl_ifla_af_spec_inet_attrs.h" #include "xlat/rtnl_ifla_af_spec_inet6_attrs.h" #undef XLAT_MACROS_ONLY static uint8_t msg_af = AF_UNIX; static char msg_af_str[32] = "AF_UNIX"; #define IFLA_AF msg_af #define IFLA_AF_STR msg_af_str #define IFLA_ATTR IFLA_AF_SPEC #include "nlattr_ifla.h" #include "nlattr_ifla_af_inet6.h" #define AF_SPEC_FUNCS(family_) \ static void \ init_##family_##_msg(struct nlmsghdr *const nlh, \ const unsigned int msg_len) \ { \ init_ifinfomsg(nlh, msg_len); \ \ struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen); \ nla += 1; \ SET_STRUCT(struct nlattr, nla, \ .nla_len = msg_len - NLMSG_SPACE(hdrlen) \ - NLA_HDRLEN, \ .nla_type = family_, \ ); \ } \ \ static void \ print_##family_##_msg(const unsigned int msg_len) \ { \ print_ifinfomsg(msg_len); \ printf(", [{nla_len=%u, nla_type=" #family_ "}", \ msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN); \ } \ /* end of AF_SPEC_FUNCS definition */ AF_SPEC_FUNCS(AF_INET) AF_SPEC_FUNCS(AF_INET6) AF_SPEC_FUNCS(AF_MCTP) AF_SPEC_FUNCS(IFLA_BRIDGE_VLAN_TUNNEL_INFO) static void print_inet_conf_val(uint32_t *val, size_t idx) { static const char * const strs[] = { "IPV4_DEVCONF_FORWARDING-1", "IPV4_DEVCONF_MC_FORWARDING-1", }; print_arr_val(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL); } int main(void) { static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd }; skip_if_unavailable("/proc/self/fd/"); const int fd = create_nl_socket(NETLINK_ROUTE); const unsigned int hdrlen = sizeof(struct ifinfomsg); void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), 3 * NLA_HDRLEN + 256); static char pattern[4096]; fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1); /* unknown AF_* */ static uint8_t skip_afs[] = { AF_INET, AF_INET6, AF_MCTP }; size_t pos = 0; static uint8_t skip_afs_msg[] = { AF_BRIDGE }; size_t pos2 = 0; for (size_t j = 0; j < 64; j++) { if (pos2 < ARRAY_SIZE(skip_afs_msg) && skip_afs_msg[pos2] == j) { pos2 += 1; continue; } msg_af = j; msg_af_str[0] = '\0'; strncat(msg_af_str, sprintxval(addrfams, j, "AF_???"), sizeof(msg_af_str) - 1); pos = 0; for (size_t i = 0; i < 64; i++) { if (pos < ARRAY_SIZE(skip_afs) && skip_afs[pos] == i) { pos += 1; continue; } const char *af_str = sprintxval(addrfams, i, "AF_???"); TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_ifinfomsg, print_ifinfomsg, i, af_str, pattern, unknown_msg, print_quoted_hex, 1, printf("\"\\xab\\xac\\xdb" "\\xcd\"")); } } /* AF_INET */ TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_AF_INET_msg, print_AF_INET_msg, 0, "IFLA_INET_UNSPEC", pattern, unknown_msg, print_quoted_hex, 2, printf("\"\\xab\\xac\\xdb\\xcd\"")); TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_AF_INET_msg, print_AF_INET_msg, 2, "0x2 /* IFLA_INET_??? */", pattern, unknown_msg, print_quoted_hex, 2, printf("\"\\xab\\xac\\xdb\\xcd\"")); /* AF_INET: IFLA_INET_CONF */ uint32_t inet_conf_vals[] = { 0xdeadc0de, 0xda7aface }; TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen, init_AF_INET_msg, print_AF_INET_msg, IFLA_INET_CONF, pattern, inet_conf_vals, 2, print_inet_conf_val); /* AF_BRIDGE */ msg_af = AF_BRIDGE; strcpy(msg_af_str, "AF_BRIDGE"); /* AF_BRIDGE: unknown, unimplemented */ static const struct strval16 unk_attrs[] = { { ENUM_KNOWN(0x4, IFLA_BRIDGE_MRP) }, { ENUM_KNOWN(0x5, IFLA_BRIDGE_CFM) }, { ARG_XLAT_UNKNOWN(0x6, "IFLA_BRIDGE_???") }, { ARG_XLAT_UNKNOWN(0xbad, "IFLA_BRIDGE_???") }, }; for (size_t i = 0; i < ARRAY_SIZE(unk_attrs); i++) { TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_ifinfomsg, print_ifinfomsg, unk_attrs[i].val, unk_attrs[i].str, pattern, unknown_msg, print_quoted_hex, 1, printf("\"\\xab\\xac\\xdb\\xcd\"") ); } /* AF_BRIDGE: IFLA_BRIDGE_FLAGS */ static const struct strval16 bridge_flags[] = { { ARG_STR(0) }, { ARG_STR(BRIDGE_FLAGS_MASTER) }, { ARG_STR(BRIDGE_FLAGS_SELF) }, { ARG_STR(BRIDGE_FLAGS_MASTER|BRIDGE_FLAGS_SELF) }, { ARG_STR(0x4) " /* BRIDGE_FLAGS_??? */" }, { 0xcafe, "BRIDGE_FLAGS_SELF|0xcafc" }, { ARG_STR(0x7eac) " /* BRIDGE_FLAGS_??? */" }, }; for (size_t i = 0; i < ARRAY_SIZE(bridge_flags); i++) { TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_ifinfomsg, print_ifinfomsg, IFLA_BRIDGE_FLAGS, "IFLA_BRIDGE_FLAGS", pattern, bridge_flags[i].val, print_quoted_hex, 1, printf("%s", bridge_flags[i].str) ); } /* AF_BRIDGE: IFLA_BRIDGE_MODE */ static const struct strval16 bridge_modes[] = { { ARG_STR(BRIDGE_MODE_VEB) }, { ARG_STR(BRIDGE_MODE_VEPA) }, { ARG_STR(0x2) " /* BRIDGE_MODE_??? */" }, { ARG_STR(0x3) " /* BRIDGE_MODE_??? */" }, { ARG_STR(0xcafe) " /* BRIDGE_MODE_??? */" }, { ARG_STR(0xfffe) " /* BRIDGE_MODE_??? */" }, { ARG_STR(BRIDGE_MODE_UNDEF) }, }; for (size_t i = 0; i < ARRAY_SIZE(bridge_flags); i++) { TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_ifinfomsg, print_ifinfomsg, IFLA_BRIDGE_MODE, "IFLA_BRIDGE_MODE", pattern, bridge_modes[i].val, print_quoted_hex, 1, printf("%s", bridge_modes[i].str) ); } /* AF_BRIDGE: IFLA_BRIDGE_VLAN_INFO */ static const struct { struct bridge_vlan_info val; const char *str; } bridge_vis[] = { { { 0, 0 }, "{flags=0, vid=0}" }, { { 1, 1 }, "{flags=BRIDGE_VLAN_INFO_MASTER, vid=1}" }, { { 0x69, 0xface }, "{flags=BRIDGE_VLAN_INFO_MASTER|BRIDGE_VLAN_INFO_RANGE_BEGIN" "|BRIDGE_VLAN_INFO_BRENTRY|BRIDGE_VLAN_INFO_ONLY_OPTS" ", vid=64206}" }, { {0xef80, 0xfeed }, "{flags=0xef80 /* BRIDGE_VLAN_INFO_??? */, vid=65261}" }, { {0xcafe, 0xdead }, "{flags=BRIDGE_VLAN_INFO_PVID|BRIDGE_VLAN_INFO_UNTAGGED" "|BRIDGE_VLAN_INFO_RANGE_BEGIN|BRIDGE_VLAN_INFO_RANGE_END" "|BRIDGE_VLAN_INFO_BRENTRY|BRIDGE_VLAN_INFO_ONLY_OPTS|0xca80" ", vid=57005}" }, }; char bvi_buf[12]; fill_memory_ex(bvi_buf, sizeof(bvi_buf), 'z', 0x80); for (size_t i = 0; i < ARRAY_SIZE(bridge_vis); i++) { TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_ifinfomsg, print_ifinfomsg, IFLA_BRIDGE_VLAN_INFO, "IFLA_BRIDGE_VLAN_INFO", pattern, bridge_vis[i].val, print_quoted_hex, 1, printf("%s", bridge_vis[i].str)); memcpy(bvi_buf, &bridge_vis[i].val, sizeof(bridge_vis[i].val)); TEST_NLATTR_(fd, nlh0 - NLA_HDRLEN, hdrlen + NLA_HDRLEN, init_ifinfomsg, print_ifinfomsg, IFLA_BRIDGE_VLAN_INFO, "IFLA_BRIDGE_VLAN_INFO", sizeof(bvi_buf), bvi_buf, sizeof(bvi_buf), printf("%s, \"\\x7e\\x7f\\x80\\x81\\x82" "\\x83\\x84\\x85\"]", bridge_vis[i].str)); } /* AF_BRIDGE: IFLA_BRIDGE_TUNNEL_INFO: unknown, undecoded */ static const struct strval16 unk_bti_attrs[] = { { ENUM_KNOWN(0, IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC) }, { ARG_XLAT_UNKNOWN(0x4, "IFLA_BRIDGE_VLAN_TUNNEL_???") }, { ARG_XLAT_UNKNOWN(0xbad, "IFLA_BRIDGE_VLAN_TUNNEL_???") }, }; for (size_t i = 0; i < ARRAY_SIZE(unk_bti_attrs); i++) { TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, print_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, unk_bti_attrs[i].val, unk_bti_attrs[i].str, pattern, unknown_msg, print_quoted_hex, 2, printf("\"\\xab\\xac\\xdb\\xcd\"") ); } /* AF_BRIDGE: IFLA_BRIDGE_TUNNEL_INFO: u32 attrs */ static const struct strval16 u32_bti_attrs[] = { { ENUM_KNOWN(0x1, IFLA_BRIDGE_VLAN_TUNNEL_ID) }, }; void *nlh_u32 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN + sizeof(uint32_t)); for (size_t i = 0; i < ARRAY_SIZE(u32_bti_attrs); i++) { check_u32_nlattr(fd, nlh_u32, hdrlen, init_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, print_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, u32_bti_attrs[i].val, u32_bti_attrs[i].str, pattern, 2); } /* AF_BRIDGE: IFLA_BRIDGE_TUNNEL_INFO: u16 attrs */ static const struct strval16 u16_bti_attrs[] = { { ENUM_KNOWN(0x1, IFLA_BRIDGE_VLAN_TUNNEL_VID) }, }; void *nlh_u16 = midtail_alloc(NLMSG_SPACE(hdrlen), NLA_HDRLEN + sizeof(uint16_t)); for (size_t i = 0; i < ARRAY_SIZE(u16_bti_attrs); i++) { check_u16_nlattr(fd, nlh_u16, hdrlen, init_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, print_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, u16_bti_attrs[i].val, u16_bti_attrs[i].str, pattern, 2); } /* AF_BRIDGE: IFLA_BRIDGE_TUNNEL_INFO: IFLA_BRIDGE_VLAN_TUNNEL_FLAGS */ static const struct strval16 bti_flags[] = { { ARG_STR(0) }, { ARG_STR(BRIDGE_VLAN_INFO_MASTER) }, { ARG_STR(BRIDGE_VLAN_INFO_PVID) }, { ARG_STR(BRIDGE_VLAN_INFO_MASTER|BRIDGE_VLAN_INFO_PVID) }, { ARG_STR(0xef80) " /* BRIDGE_VLAN_INFO_??? */" }, { 0xcafe, "BRIDGE_VLAN_INFO_PVID|BRIDGE_VLAN_INFO_UNTAGGED" "|BRIDGE_VLAN_INFO_RANGE_BEGIN" "|BRIDGE_VLAN_INFO_RANGE_END|BRIDGE_VLAN_INFO_BRENTRY" "|BRIDGE_VLAN_INFO_ONLY_OPTS|0xca80" }, }; for (size_t i = 0; i < ARRAY_SIZE(bti_flags); i++) { TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, print_IFLA_BRIDGE_VLAN_TUNNEL_INFO_msg, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, "IFLA_BRIDGE_VLAN_TUNNEL_FLAGS", pattern, bti_flags[i].val, print_quoted_hex, 2, printf("%s", bti_flags[i].str) ); } /* AF_INET6 */ msg_af = AF_UNIX; strcpy(msg_af_str, "AF_UNIX"); check_ifla_af_inet6(fd, nlh0, hdrlen, init_AF_INET6_msg, print_AF_INET6_msg, pattern, 2); /* AF_MCTP */ TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_AF_MCTP_msg, print_AF_MCTP_msg, 0, "IFLA_MCTP_UNSPEC", pattern, unknown_msg, print_quoted_hex, 2, printf("\"\\xab\\xac\\xdb\\xcd\"")); TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen, init_AF_MCTP_msg, print_AF_MCTP_msg, 2, "0x2 /* IFLA_MCTP_??? */", pattern, unknown_msg, print_quoted_hex, 2, printf("\"\\xab\\xac\\xdb\\xcd\"")); /* AF_MCTP: IFLA_MCTP_NET */ check_u32_nlattr(fd, nlh0, hdrlen, init_AF_MCTP_msg, print_AF_MCTP_msg, 1, "IFLA_MCTP_NET", pattern, 2); puts("+++ exited with 0 +++"); return 0; }