summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Syromyatnikov <evgsyr@gmail.com>2021-09-29 16:47:27 +0200
committerEugene Syromyatnikov <evgsyr@gmail.com>2021-10-09 12:30:24 +0200
commit0c73fcccd6266db94c7ac1e53c29ce18a8d34506 (patch)
tree0f841499712975fe2b04b2dfa2ef925b38bdf07e
parentb27a057e8748d41a4f7b87779add6ffcb9b20ea3 (diff)
downloadstrace-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.ac1
-rw-r--r--src/rtnl_route.c43
-rw-r--r--tests/nlattr_rtmsg.c156
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,