diff options
author | Eugene Syromyatnikov <evgsyr@gmail.com> | 2021-09-29 16:47:27 +0200 |
---|---|---|
committer | Eugene Syromyatnikov <evgsyr@gmail.com> | 2021-10-09 12:30:24 +0200 |
commit | 0c73fcccd6266db94c7ac1e53c29ce18a8d34506 (patch) | |
tree | 0f841499712975fe2b04b2dfa2ef925b38bdf07e | |
parent | b27a057e8748d41a4f7b87779add6ffcb9b20ea3 (diff) | |
download | strace-0c73fcccd6266db94c7ac1e53c29ce18a8d34506.tar.gz |
rtnl_route: handle multiple next hop entries inside RTA_MULTIPATH
* configure.ac (AC_CHECK_FUNCS): Add mempcpy.
* src/rtnl_route.c (decode_rta_multipath): Navigate through attribute
payload and print it as an array if there are more data in the payload
than the first struct rtnexthop.rtnh_len indicates.
* tests/nlattr_rtmsg.c [!HAVE_MEMPCPY] (mempcpy): Re-define
to strace_mempcpy.
[!HAVE_MEMPCPY] (mempcpy): New function.
(DEF_NLATTR_RTMSG_FUNCS): New macro for defining init/print functions.
(init_rtmsg_inet, print_rtmsg_inet): New functions, defined using
DEF_NLATTR_RTMSG_FUNCS macro.
(main): Update expected output, add a check for multiple
struct rtnexthop inside RTA_MULTIPATH.
Resolves: https://github.com/strace/strace/issues/195
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/rtnl_route.c | 43 | ||||
-rw-r--r-- | tests/nlattr_rtmsg.c | 156 |
3 files changed, 158 insertions, 42 deletions
diff --git a/configure.ac b/configure.ac index 2771c0f82..e662c12f4 100644 --- a/configure.ac +++ b/configure.ac @@ -352,6 +352,7 @@ AC_CHECK_FUNCS(m4_normalize([ futimens iconv_open if_indextoname + mempcpy open64 open_memstream preadv diff --git a/src/rtnl_route.c b/src/rtnl_route.c index fd6be7361..e3d6d52ad 100644 --- a/src/rtnl_route.c +++ b/src/rtnl_route.c @@ -236,17 +236,42 @@ static const nla_decoder_t rtmsg_nla_decoders[] = { [RTA_DPORT] = decode_nla_u16 }; +/* + * RTA_MULTIPATH payload is a list of struct rtnexthop-headed RTA_* netlink + * attributes: + * + * {RTA_MULTIPATH nlattr hdr} [ [{struct rtnexthop}, {RTA_* nlattr}], + * [{struct rtnexthop}, {RTA_* nlattr}], ... ] + */ static bool decode_rta_multipath(struct tcb *const tcp, const kernel_ulong_t addr, const unsigned int len, const void *const opaque_data) { + bool is_array = false; struct rtnexthop nh; + kernel_ulong_t cur = addr; + kernel_ulong_t left = len; if (len < sizeof(nh)) return false; - else if (!umove_or_printaddr(tcp, addr, &nh)) { + + while (!umove_or_printaddr(tcp, cur, &nh)) { + static const size_t offset = RTNH_ALIGN(sizeof(nh)); + const unsigned int rtnh_len = MIN(left, nh.rtnh_len); + + if (cur == addr && nh.rtnh_len < len) { + tprint_array_begin(); + is_array = true; + } + + if (cur > addr) + tprint_array_next(); + + if (rtnh_len > offset) + tprint_array_begin(); + /* print the whole structure regardless of its rtnh_len */ tprint_struct_begin(); PRINT_FIELD_U(nh, rtnh_len); @@ -259,18 +284,28 @@ decode_rta_multipath(struct tcb *const tcp, PRINT_FIELD_IFINDEX(nh, rtnh_ifindex); tprint_struct_end(); - const unsigned short rtnh_len = MIN(len, nh.rtnh_len); - const size_t offset = RTNH_ALIGN(sizeof(nh)); if (rtnh_len > offset) { tprint_array_next(); - decode_nlattr(tcp, addr + offset, rtnh_len - offset, + decode_nlattr(tcp, cur + offset, rtnh_len - offset, rtnl_route_attrs, "RTA_???", rtmsg_nla_decoders, ARRAY_SIZE(rtmsg_nla_decoders), opaque_data); } + + if (rtnh_len > offset) + tprint_array_end(); + + if (RTNH_ALIGN(rtnh_len) >= left) + break; + + cur += RTNH_ALIGN(rtnh_len); + left -= RTNH_ALIGN(rtnh_len); } + if (is_array) + tprint_array_end(); + return true; } diff --git a/tests/nlattr_rtmsg.c b/tests/nlattr_rtmsg.c index bddc13faf..cd477dd1d 100644 --- a/tests/nlattr_rtmsg.c +++ b/tests/nlattr_rtmsg.c @@ -15,43 +15,61 @@ #include <linux/ip.h> #include <linux/rtnetlink.h> -#define LWTUNNEL_ENCAP_NONE 0 - -static void -init_rtmsg(struct nlmsghdr *const nlh, const unsigned int msg_len) +#if !defined HAVE_MEMPCPY +# undef mempcpy +# define mempcpy strace_mempcpy +static void * +mempcpy(void *dest, const void *src, size_t n) { - SET_STRUCT(struct nlmsghdr, nlh, - .nlmsg_len = msg_len, - .nlmsg_type = RTM_GETROUTE, - .nlmsg_flags = NLM_F_DUMP - ); - - struct rtmsg *const msg = NLMSG_DATA(nlh); - SET_STRUCT(struct rtmsg, msg, - .rtm_family = AF_UNIX, - .rtm_tos = IPTOS_LOWDELAY, - .rtm_table = RT_TABLE_DEFAULT, - .rtm_protocol = RTPROT_KERNEL, - .rtm_scope = RT_SCOPE_UNIVERSE, - .rtm_type = RTN_LOCAL, - .rtm_flags = RTM_F_NOTIFY - ); -} + memcpy(dest, src, n); -static void -print_rtmsg(const unsigned int msg_len) -{ - printf("{nlmsg_len=%u, nlmsg_type=RTM_GETROUTE, nlmsg_flags=NLM_F_DUMP" - ", nlmsg_seq=0, nlmsg_pid=0}, {rtm_family=AF_UNIX" - ", rtm_dst_len=0, rtm_src_len=0" - ", rtm_tos=IPTOS_LOWDELAY" - ", rtm_table=RT_TABLE_DEFAULT" - ", rtm_protocol=RTPROT_KERNEL" - ", rtm_scope=RT_SCOPE_UNIVERSE" - ", rtm_type=RTN_LOCAL" - ", rtm_flags=RTM_F_NOTIFY}", - msg_len); + return dest + n; } +#endif + +#define LWTUNNEL_ENCAP_NONE 0 + +#define DEF_NLATTR_RTMSG_FUNCS(sfx_, af_) \ + static void \ + init_##sfx_(struct nlmsghdr *const nlh, const unsigned int msg_len) \ + { \ + SET_STRUCT(struct nlmsghdr, nlh, \ + .nlmsg_len = msg_len, \ + .nlmsg_type = RTM_GETROUTE, \ + .nlmsg_flags = NLM_F_DUMP \ + ); \ + \ + struct rtmsg *const msg = NLMSG_DATA(nlh); \ + SET_STRUCT(struct rtmsg, msg, \ + .rtm_family = (af_), \ + .rtm_tos = IPTOS_LOWDELAY, \ + .rtm_table = RT_TABLE_DEFAULT, \ + .rtm_protocol = RTPROT_KERNEL, \ + .rtm_scope = RT_SCOPE_UNIVERSE, \ + .rtm_type = RTN_LOCAL, \ + .rtm_flags = RTM_F_NOTIFY \ + ); \ + } \ + \ + static void \ + print_##sfx_(const unsigned int msg_len) \ + { \ + printf("{nlmsg_len=%u, nlmsg_type=RTM_GETROUTE" \ + ", nlmsg_flags=NLM_F_DUMP" \ + ", nlmsg_seq=0, nlmsg_pid=0}, {rtm_family=" #af_ \ + ", rtm_dst_len=0, rtm_src_len=0" \ + ", rtm_tos=IPTOS_LOWDELAY" \ + ", rtm_table=RT_TABLE_DEFAULT" \ + ", rtm_protocol=RTPROT_KERNEL" \ + ", rtm_scope=RT_SCOPE_UNIVERSE" \ + ", rtm_type=RTN_LOCAL" \ + ", rtm_flags=RTM_F_NOTIFY}", \ + msg_len); \ + } \ + /* End of DEF_NLATTR_RTMSG_FUNCS */ + +DEF_NLATTR_RTMSG_FUNCS(rtmsg, AF_UNIX) +DEF_NLATTR_RTMSG_FUNCS(rtmsg_inet, AF_INET) int main(void) @@ -110,9 +128,9 @@ main(void) TEST_NLATTR_OBJECT(fd, nlh0, hdrlen, init_rtmsg, print_rtmsg, RTA_MULTIPATH, pattern, nh, - printf("{rtnh_len=%u, rtnh_flags=RTNH_F_DEAD" + printf("[{rtnh_len=%u, rtnh_flags=RTNH_F_DEAD" ", rtnh_hops=%u" - ", rtnh_ifindex=" IFINDEX_LO_STR "}", + ", rtnh_ifindex=" IFINDEX_LO_STR "}]", nh.rtnh_len, nh.rtnh_hops)); char buf[RTNH_ALIGN(sizeof(nh)) + sizeof(nla)]; @@ -123,11 +141,73 @@ main(void) TEST_NLATTR(fd, nlh0, hdrlen, init_rtmsg, print_rtmsg, RTA_MULTIPATH, sizeof(buf), buf, sizeof(buf), - printf("{rtnh_len=%u, rtnh_flags=RTNH_F_DEAD" + printf("[{rtnh_len=%u, rtnh_flags=RTNH_F_DEAD" ", rtnh_hops=%u, rtnh_ifindex=" IFINDEX_LO_STR "}" - ", {nla_len=%u, nla_type=RTA_DST}", + ", {nla_len=%u, nla_type=RTA_DST}]", nh.rtnh_len, nh.rtnh_hops, nla.nla_len)); + static const struct in_addr gw_inet_addr = { .s_addr = BE32(0xdeadbeef) }; + static const uint8_t via_inet6_addr[16] = { + 0xde, 0xad, 0xfa, 0xce, 0xbe, 0xef, 0xca, 0xfe, + 0xfe, 0xed, 0xba, 0x5e, 0x00, 0x00, 0xfa, 0xde }; + static const struct rtvia rtvia = { .rtvia_family = AF_INET6 }; + char buf2[2 * (RTNH_ALIGN(sizeof(nh)) + NLMSG_ALIGN(sizeof(nla))) + + + NLMSG_ALIGN(sizeof(gw_inet_addr)) + + NLMSG_ALIGN(offsetof(struct rtvia, rtvia_addr) + + sizeof(via_inet6_addr))]; + char *pos = buf2; + + nh.rtnh_len = RTNH_ALIGN(sizeof(nh)) + NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(sizeof(gw_inet_addr)); + nh.rtnh_flags = 0xc0; + nla.nla_type = RTA_GATEWAY; + nla.nla_len = NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(sizeof(gw_inet_addr)); + pos = mempcpy(pos, &nh, sizeof(nh)); + pos = mempcpy(pos, &nla, sizeof(nla)); + pos = mempcpy(pos, &gw_inet_addr, sizeof(gw_inet_addr)); + + nh.rtnh_len = RTNH_ALIGN(sizeof(nh)) + NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(offsetof(struct rtvia, rtvia_addr) + + sizeof(via_inet6_addr)); + nla.nla_type = RTA_VIA; + nla.nla_len = NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(offsetof(struct rtvia, rtvia_addr) + + sizeof(via_inet6_addr)); + pos = mempcpy(pos, &nh, sizeof(nh)); + pos = mempcpy(pos, &nla, sizeof(nla)); + pos = mempcpy(pos, &rtvia, sizeof(rtvia)); + pos = mempcpy(pos, &via_inet6_addr, sizeof(via_inet6_addr)); + TEST_NLATTR(fd, nlh0, hdrlen, + init_rtmsg_inet, print_rtmsg_inet, + RTA_MULTIPATH, sizeof(buf2), buf2, sizeof(buf2), + printf("[[{rtnh_len=%u, rtnh_flags=RTNH_F_TRAP|0x80" + ", rtnh_hops=%u, rtnh_ifindex=" IFINDEX_LO_STR "}" + ", [{nla_len=%u, nla_type=RTA_GATEWAY}" + ", inet_addr(\"222.173.190.239\")]]" + ", [{rtnh_len=%u, rtnh_flags=RTNH_F_TRAP|0x80" + ", rtnh_hops=%u, rtnh_ifindex=" IFINDEX_LO_STR "}" + ", [{nla_len=%u, nla_type=RTA_VIA}" + ", {rtvia_family=AF_INET6" + ", inet_pton(AF_INET6" + ", \"dead:face:beef:cafe:feed:ba5e:0:fade\"" + ", &rtvia_addr)}]]]", + (uint32_t) (RTNH_ALIGN(sizeof(nh)) + + NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(sizeof(gw_inet_addr))), + nh.rtnh_hops, + (uint32_t) (NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(sizeof(gw_inet_addr))), + (uint32_t) (RTNH_ALIGN(sizeof(nh)) + + NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(offsetof(struct rtvia, rtvia_addr) + + sizeof(via_inet6_addr))), + nh.rtnh_hops, + (uint32_t) (NLMSG_ALIGN(sizeof(nla)) + + NLMSG_ALIGN(offsetof(struct rtvia, rtvia_addr) + + sizeof(via_inet6_addr))) + )); + static const struct rta_cacheinfo ci = { .rta_clntref = 0xabcdefab, .rta_lastuse = 0xbdadaedc, |