]> git.proxmox.com Git - mirror_frr.git/commitdiff
zebra: Fix extended ack error message parsing
authorStephen Worley <sworley@cumulusnetworks.com>
Tue, 26 Mar 2019 05:03:06 +0000 (01:03 -0400)
committerStephen Worley <sworley@cumulusnetworks.com>
Tue, 26 Mar 2019 05:20:29 +0000 (01:20 -0400)
Fix the macros for reading NLA attribute info
from an extended error ack. We were processing the data
using route attributes (rtattr) which is identical in size
to nlattr but probably should not be used.

Further, we were incorrectly calculating the length of the
inner netlink message that cause the error. We have to read
passed that in order to access all the nlattr's.

Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
zebra/kernel_netlink.c

index c5fbfd44814aad9a8f53b4220a8e11110ab93b0d..fe37a333581ed12244f62acce217dba9adddbe7c 100644 (file)
@@ -606,50 +606,56 @@ const char *nl_rttype_to_str(uint8_t rttype)
        return lookup_msg(rttype_str, rttype, "");
 }
 
-#define NL_OK(nla, len)                                                        \
+#define NLA_OK(nla, len)                                                       \
        ((len) >= (int)sizeof(struct nlattr)                                   \
         && (nla)->nla_len >= sizeof(struct nlattr)                            \
         && (nla)->nla_len <= (len))
-#define NL_NEXT(nla, attrlen)                                                  \
-       ((attrlen) -= RTA_ALIGN((nla)->nla_len),                               \
-        (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
-#define NL_RTA(r)                                                              \
-       ((struct nlattr *)(((char *)(r))                                       \
-                          + NLMSG_ALIGN(sizeof(struct nlmsgerr))))
+#define NLA_NEXT(nla, attrlen)                                                 \
+       ((attrlen) -= NLA_ALIGN((nla)->nla_len),                               \
+        (struct nlattr *)(((char *)(nla)) + NLA_ALIGN((nla)->nla_len)))
+#define NLA_LENGTH(len) (NLA_ALIGN(sizeof(struct nlattr)) + (len))
+#define NLA_DATA(nla) ((struct nlattr *)(((char *)(nla)) + NLA_LENGTH(0)))
+
+#define ERR_NLA(err, inner_len)                                                \
+       ((struct nlattr *)(((char *)(err))                                     \
+                          + NLMSG_ALIGN(sizeof(struct nlmsgerr))              \
+                          + NLMSG_ALIGN((inner_len))))
 
 static void netlink_parse_nlattr(struct nlattr **tb, int max,
                                 struct nlattr *nla, int len)
 {
-       while (NL_OK(nla, len)) {
+       while (NLA_OK(nla, len)) {
                if (nla->nla_type <= max)
                        tb[nla->nla_type] = nla;
-               nla = NL_NEXT(nla, len);
+               nla = NLA_NEXT(nla, len);
        }
 }
 
 static void netlink_parse_extended_ack(struct nlmsghdr *h)
 {
-       struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
-       const struct nlmsgerr *err =
-               (const struct nlmsgerr *)((uint8_t *)h
-                                         + NLMSG_ALIGN(
-                                                   sizeof(struct nlmsghdr)));
+       struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+       const struct nlmsgerr *err = (const struct nlmsgerr *)NLMSG_DATA(h);
        const struct nlmsghdr *err_nlh = NULL;
-       uint32_t hlen = sizeof(*err);
+       /* Length not including nlmsghdr */
+       uint32_t len = 0;
+       /* Inner error netlink message length */
+       uint32_t inner_len = 0;
        const char *msg = NULL;
        uint32_t off = 0;
 
        if (!(h->nlmsg_flags & NLM_F_CAPPED))
-               hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+               inner_len = (uint32_t)NLMSG_PAYLOAD(&err->msg, 0);
+
+       len = (uint32_t)(NLMSG_PAYLOAD(h, sizeof(struct nlmsgerr)) - inner_len);
 
-       memset(tb, 0, sizeof(tb));
-       netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
+       netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, ERR_NLA(err, inner_len),
+                            len);
 
        if (tb[NLMSGERR_ATTR_MSG])
-               msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
+               msg = (const char *)NLA_DATA(tb[NLMSGERR_ATTR_MSG]);
 
        if (tb[NLMSGERR_ATTR_OFFS]) {
-               off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
+               off = *(uint32_t *)NLA_DATA(tb[NLMSGERR_ATTR_OFFS]);
 
                if (off > h->nlmsg_len) {
                        zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS");