]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: check for buffer boundary
authorJakub Urbańczyk <xthaid@gmail.com>
Wed, 10 Jun 2020 09:44:31 +0000 (11:44 +0200)
committerJakub Urbańczyk <xthaid@gmail.com>
Sat, 13 Jun 2020 20:56:25 +0000 (22:56 +0200)
 * Move code encoding Netlink messages to separate functions
 * Add buffer bounds checking while creating Nelink messages

Signed-off-by: Jakub Urbańczyk <xthaid@gmail.com>
zebra/dplane_fpm_nl.c
zebra/rt_netlink.c
zebra/rt_netlink.h
zebra/rule_netlink.c
zebra/zebra_mpls_netlink.c

index 88d5ab5cecab21e40720f43bafa41b7cfa16fc9f..ef208bdc8361a26c8606c2057f09f7ecd37ded70 100644 (file)
@@ -709,12 +709,13 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
        switch (op) {
        case DPLANE_OP_ROUTE_UPDATE:
        case DPLANE_OP_ROUTE_DELETE:
-               rv = netlink_route_multipath(RTM_DELROUTE, ctx, nl_buf,
-                                            sizeof(nl_buf), true,
-                                            fnc->use_nhg);
+               rv = netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx,
+                                                       nl_buf, sizeof(nl_buf),
+                                                       true, fnc->use_nhg);
                if (rv <= 0) {
-                       zlog_err("%s: netlink_route_multipath failed",
-                                __func__);
+                       zlog_err(
+                               "%s: netlink_route_multipath_msg_encode failed",
+                               __func__);
                        return 0;
                }
 
@@ -726,12 +727,13 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
 
                /* FALL THROUGH */
        case DPLANE_OP_ROUTE_INSTALL:
-               rv = netlink_route_multipath(
+               rv = netlink_route_multipath_msg_encode(
                        RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len],
                        sizeof(nl_buf) - nl_buf_len, true, fnc->use_nhg);
                if (rv <= 0) {
-                       zlog_err("%s: netlink_route_multipath failed",
-                                __func__);
+                       zlog_err(
+                               "%s: netlink_route_multipath_msg_encode failed",
+                               __func__);
                        return 0;
                }
 
@@ -751,10 +753,11 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
                break;
 
        case DPLANE_OP_NH_DELETE:
-               rv = netlink_nexthop_encode(RTM_DELNEXTHOP, ctx, nl_buf,
-                                           sizeof(nl_buf));
+               rv = netlink_nexthop_msg_encode(RTM_DELNEXTHOP, ctx, nl_buf,
+                                               sizeof(nl_buf));
                if (rv <= 0) {
-                       zlog_err("%s: netlink_nexthop_encode failed", __func__);
+                       zlog_err("%s: netlink_nexthop_msg_encode failed",
+                                __func__);
                        return 0;
                }
 
@@ -762,10 +765,11 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
                break;
        case DPLANE_OP_NH_INSTALL:
        case DPLANE_OP_NH_UPDATE:
-               rv = netlink_nexthop_encode(RTM_NEWNEXTHOP, ctx, nl_buf,
-                                           sizeof(nl_buf));
+               rv = netlink_nexthop_msg_encode(RTM_NEWNEXTHOP, ctx, nl_buf,
+                                               sizeof(nl_buf));
                if (rv <= 0) {
-                       zlog_err("%s: netlink_nexthop_encode failed", __func__);
+                       zlog_err("%s: netlink_nexthop_msg_encode failed",
+                                __func__);
                        return 0;
                }
 
index 238eea6d3513380ad4d779749377c518b8d4d887..9261d1b97586315a30fdb78c729580eb88d36b40 100644 (file)
@@ -1029,7 +1029,11 @@ int netlink_route_read(struct zebra_ns *zns)
        return 0;
 }
 
-static void _netlink_route_add_gateway_info(uint8_t route_family,
+/*
+ * The function returns true if the gateway info could be added
+ * to the message, otherwise false is returned.
+ */
+static bool _netlink_route_add_gateway_info(uint8_t route_family,
                                            uint8_t gw_family,
                                            struct nlmsghdr *nlmsg,
                                            size_t req_size, int bytelen,
@@ -1043,16 +1047,22 @@ static void _netlink_route_add_gateway_info(uint8_t route_family,
                        memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen);
                else
                        memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen);
-               nl_attr_put(nlmsg, req_size, RTA_VIA, &gw_fam.family,
-                           bytelen + 2);
+               if (!nl_attr_put(nlmsg, req_size, RTA_VIA, &gw_fam.family,
+                                bytelen + 2))
+                       return false;
        } else {
-               if (gw_family == AF_INET)
-                       nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
-                                   &nexthop->gate.ipv4, bytelen);
-               else
-                       nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
-                                   &nexthop->gate.ipv6, bytelen);
+               if (gw_family == AF_INET) {
+                       if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
+                                        &nexthop->gate.ipv4, bytelen))
+                               return false;
+               } else {
+                       if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
+                                        &nexthop->gate.ipv6, bytelen))
+                               return false;
+               }
        }
+
+       return true;
 }
 
 static int build_label_stack(struct mpls_label_stack *nh_label,
@@ -1095,8 +1105,11 @@ static int build_label_stack(struct mpls_label_stack *nh_label,
  * @param nexthop: Nexthop information
  * @param nlmsg: nlmsghdr structure to fill in.
  * @param req_size: The size allocated for the message.
+ *
+ * The function returns true if the nexthop could be added
+ * to the message, otherwise false is returned.
  */
-static void _netlink_route_build_singlepath(const struct prefix *p,
+static bool _netlink_route_build_singlepath(const struct prefix *p,
                                            const char *routedesc, int bytelen,
                                            const struct nexthop *nexthop,
                                            struct nlmsghdr *nlmsg,
@@ -1129,18 +1142,26 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
                /* Set the BoS bit */
                out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
 
-               if (rtmsg->rtm_family == AF_MPLS)
-                       nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
-                                   num_labels * sizeof(mpls_lse_t));
-               else {
+               if (rtmsg->rtm_family == AF_MPLS) {
+                       if (!nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
+                                        num_labels * sizeof(mpls_lse_t)))
+                               return false;
+               } else {
                        struct rtattr *nest;
                        uint16_t encap = LWTUNNEL_ENCAP_MPLS;
 
-                       nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE, &encap,
-                                   sizeof(uint16_t));
+                       if (!nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE,
+                                        &encap, sizeof(uint16_t)))
+                               return false;
+
                        nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
-                       nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
-                                   &out_lse, num_labels * sizeof(mpls_lse_t));
+                       if (!nest)
+                               return false;
+
+                       if (!nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
+                                        &out_lse,
+                                        num_labels * sizeof(mpls_lse_t)))
+                               return false;
                        nl_attr_nest_end(nlmsg, nest);
                }
        }
@@ -1150,41 +1171,52 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
 
        if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
                rtmsg->rtm_flags |= RTNH_F_ONLINK;
-               nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4);
-               nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
+               if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4))
+                       return false;
+               if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
+                       return false;
 
                if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY
-                   && (cmd == RTM_NEWROUTE))
-                       nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                   &nexthop->rmap_src.ipv4, bytelen);
-               else if (nexthop->src.ipv4.s_addr != INADDR_ANY
-                        && (cmd == RTM_NEWROUTE))
-                       nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                   &nexthop->src.ipv4, bytelen);
+                   && (cmd == RTM_NEWROUTE)) {
+                       if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                        &nexthop->rmap_src.ipv4, bytelen))
+                               return false;
+               } else if (nexthop->src.ipv4.s_addr != INADDR_ANY
+                          && (cmd == RTM_NEWROUTE)) {
+                       if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                        &nexthop->src.ipv4, bytelen))
+                               return false;
+               }
 
                if (IS_ZEBRA_DEBUG_KERNEL)
                        zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
                                   __func__, routedesc, p, ipv4_ll_buf,
                                   label_buf, nexthop->ifindex,
                                   VRF_LOGNAME(vrf), nexthop->vrf_id);
-               return;
+               return true;
        }
 
        if (nexthop->type == NEXTHOP_TYPE_IPV4
            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
                /* Send deletes to the kernel without specifying the next-hop */
-               if (cmd != RTM_DELROUTE)
-                       _netlink_route_add_gateway_info(
-                               rtmsg->rtm_family, AF_INET, nlmsg, req_size,
-                               bytelen, nexthop);
+               if (cmd != RTM_DELROUTE) {
+                       if (!_netlink_route_add_gateway_info(
+                                   rtmsg->rtm_family, AF_INET, nlmsg, req_size,
+                                   bytelen, nexthop))
+                               return false;
+               }
 
                if (cmd == RTM_NEWROUTE) {
-                       if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
-                               nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                           &nexthop->rmap_src.ipv4, bytelen);
-                       else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
-                               nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                           &nexthop->src.ipv4, bytelen);
+                       if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
+                               if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                                &nexthop->rmap_src.ipv4,
+                                                bytelen))
+                                       return false;
+                       } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
+                               if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                                &nexthop->src.ipv4, bytelen))
+                                       return false;
+                       }
                }
 
                if (IS_ZEBRA_DEBUG_KERNEL) {
@@ -1199,17 +1231,23 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
 
        if (nexthop->type == NEXTHOP_TYPE_IPV6
            || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
-               _netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET6,
-                                               nlmsg, req_size, bytelen,
-                                               nexthop);
+               if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
+                                                    AF_INET6, nlmsg, req_size,
+                                                    bytelen, nexthop))
+                       return false;
 
                if (cmd == RTM_NEWROUTE) {
-                       if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
-                               nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                           &nexthop->rmap_src.ipv6, bytelen);
-                       else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
-                               nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                           &nexthop->src.ipv6, bytelen);
+                       if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) {
+                               if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                                &nexthop->rmap_src.ipv6,
+                                                bytelen))
+                                       return false;
+                       } else if (!IN6_IS_ADDR_UNSPECIFIED(
+                                          &nexthop->src.ipv6)) {
+                               if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                                &nexthop->src.ipv6, bytelen))
+                                       return false;
+                       }
                }
 
                if (IS_ZEBRA_DEBUG_KERNEL) {
@@ -1227,17 +1265,23 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
         * This is especially useful if we are doing route
         * leaking.
         */
-       if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
-               nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex);
+       if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
+               if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
+                       return false;
+       }
 
        if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
                if (cmd == RTM_NEWROUTE) {
-                       if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
-                               nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                           &nexthop->rmap_src.ipv4, bytelen);
-                       else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
-                               nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
-                                           &nexthop->src.ipv4, bytelen);
+                       if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
+                               if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                                &nexthop->rmap_src.ipv4,
+                                                bytelen))
+                                       return false;
+                       } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
+                               if (!nl_attr_put(nlmsg, req_size, RTA_PREFSRC,
+                                                &nexthop->src.ipv4, bytelen))
+                                       return false;
+                       }
                }
 
                if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1245,6 +1289,8 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
                                   __func__, routedesc, p, nexthop->ifindex,
                                   VRF_LOGNAME(vrf), nexthop->vrf_id);
        }
+
+       return true;
 }
 
 /* This function takes a nexthop as argument and
@@ -1261,8 +1307,11 @@ static void _netlink_route_build_singlepath(const struct prefix *p,
  * @param req_size: The size allocated for the message.
  * @param src: pointer pointing to a location where
  *             the prefsrc should be stored.
+ *
+ * The function returns true if the nexthop could be added
+ * to the message, otherwise false is returned.
  */
-static void _netlink_route_build_multipath(const struct prefix *p,
+static bool _netlink_route_build_multipath(const struct prefix *p,
                                           const char *routedesc, int bytelen,
                                           const struct nexthop *nexthop,
                                           struct nlmsghdr *nlmsg,
@@ -1276,6 +1325,8 @@ static void _netlink_route_build_multipath(const struct prefix *p,
        struct rtnexthop *rtnh;
 
        rtnh = nl_attr_rtnh(nlmsg, req_size);
+       if (rtnh == NULL)
+               return false;
 
        assert(nexthop);
 
@@ -1297,17 +1348,25 @@ static void _netlink_route_build_multipath(const struct prefix *p,
                out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
 
                if (rtmsg->rtm_family == AF_MPLS) {
-                       nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
-                                   num_labels * sizeof(mpls_lse_t));
+                       if (!nl_attr_put(nlmsg, req_size, RTA_NEWDST, &out_lse,
+                                        num_labels * sizeof(mpls_lse_t)))
+                               return false;
                } else {
                        struct rtattr *nest;
                        uint16_t encap = LWTUNNEL_ENCAP_MPLS;
 
-                       nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE, &encap,
-                                   sizeof(uint16_t));
+                       if (!nl_attr_put(nlmsg, req_size, RTA_ENCAP_TYPE,
+                                        &encap, sizeof(uint16_t)))
+                               return false;
+
                        nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
-                       nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
-                                   &out_lse, num_labels * sizeof(mpls_lse_t));
+                       if (nest == NULL)
+                               return false;
+
+                       if (!nl_attr_put(nlmsg, req_size, MPLS_IPTUNNEL_DST,
+                                        &out_lse,
+                                        num_labels * sizeof(mpls_lse_t)))
+                               return false;
                        nl_attr_nest_end(nlmsg, nest);
                }
        }
@@ -1318,7 +1377,9 @@ static void _netlink_route_build_multipath(const struct prefix *p,
        if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
                bytelen = 4;
                rtnh->rtnh_flags |= RTNH_F_ONLINK;
-               nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, bytelen);
+               if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll,
+                                bytelen))
+                       return false;
                rtnh->rtnh_ifindex = nexthop->ifindex;
                if (nexthop->weight)
                        rtnh->rtnh_hops = nexthop->weight - 1;
@@ -1335,14 +1396,16 @@ static void _netlink_route_build_multipath(const struct prefix *p,
                                nexthop->ifindex, VRF_LOGNAME(vrf),
                                nexthop->vrf_id);
                nl_attr_rtnh_end(nlmsg, rtnh);
-               return;
+               return true;
        }
 
        if (nexthop->type == NEXTHOP_TYPE_IPV4
            || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
-               _netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET,
-                                               nlmsg, req_size, bytelen,
-                                               nexthop);
+               if (!_netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET,
+                                                    nlmsg, req_size, bytelen,
+                                                    nexthop))
+                       return false;
+
                if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
                        *src = &nexthop->rmap_src;
                else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
@@ -1356,9 +1419,10 @@ static void _netlink_route_build_multipath(const struct prefix *p,
        }
        if (nexthop->type == NEXTHOP_TYPE_IPV6
            || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
-               _netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET6,
-                                               nlmsg, req_size, bytelen,
-                                               nexthop);
+               if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
+                                                    AF_INET6, nlmsg, req_size,
+                                                    bytelen, nexthop))
+                       return false;
 
                if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
                        *src = &nexthop->rmap_src;
@@ -1395,10 +1459,12 @@ static void _netlink_route_build_multipath(const struct prefix *p,
 
        if (nexthop->weight)
                rtnh->rtnh_hops = nexthop->weight - 1;
+
        nl_attr_rtnh_end(nlmsg, rtnh);
+       return true;
 }
 
-static inline void _netlink_mpls_build_singlepath(const struct prefix *p,
+static inline bool _netlink_mpls_build_singlepath(const struct prefix *p,
                                                  const char *routedesc,
                                                  const zebra_nhlfe_t *nhlfe,
                                                  struct nlmsghdr *nlmsg,
@@ -1410,12 +1476,13 @@ static inline void _netlink_mpls_build_singlepath(const struct prefix *p,
 
        family = NHLFE_FAMILY(nhlfe);
        bytelen = (family == AF_INET ? 4 : 16);
-       _netlink_route_build_singlepath(p, routedesc, bytelen, nhlfe->nexthop,
-                                       nlmsg, rtmsg, req_size, cmd);
+       return _netlink_route_build_singlepath(p, routedesc, bytelen,
+                                              nhlfe->nexthop, nlmsg, rtmsg,
+                                              req_size, cmd);
 }
 
 
-static inline void
+static inline bool
 _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc,
                              const zebra_nhlfe_t *nhlfe,
                              struct nlmsghdr *nlmsg, size_t req_size,
@@ -1426,15 +1493,16 @@ _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc,
 
        family = NHLFE_FAMILY(nhlfe);
        bytelen = (family == AF_INET ? 4 : 16);
-       _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop,
-                                      nlmsg, req_size, rtmsg, src);
+       return _netlink_route_build_multipath(p, routedesc, bytelen,
+                                             nhlfe->nexthop, nlmsg, req_size,
+                                             rtmsg, src);
 }
 
 static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
 {
        if (IS_ZEBRA_DEBUG_KERNEL)
-               zlog_debug("netlink_mpls_multipath() (%s): %s %u/20", routedesc,
-                          nl_msg_type_to_str(cmd), label);
+               zlog_debug("netlink_mpls_multipath_msg_encode() (%s): %s %u/20",
+                          routedesc, nl_msg_type_to_str(cmd), label);
 }
 
 static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla,
@@ -1494,29 +1562,45 @@ static bool nexthop_set_src(const struct nexthop *nexthop, int family,
        return false;
 }
 
-static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
-                                       struct nexthop *nh)
+/*
+ * The function returns true if the attribute could be added
+ * to the message, otherwise false is returned.
+ */
+static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
+                                      struct nexthop *nh)
 {
        struct rtattr *nest;
 
        switch (nh->nh_encap_type) {
        case NET_VXLAN:
-               nl_attr_put(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type,
-                           sizeof(uint16_t));
+               if (!nl_attr_put(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type,
+                                sizeof(uint16_t)))
+                       return false;
 
                nest = nl_attr_nest(n, nlen, RTA_ENCAP);
-               nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni);
+               if (!nest)
+                       return false;
+
+               if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */,
+                                  nh->nh_encap.vni))
+                       return false;
                nl_attr_nest_end(n, nest);
                break;
        }
+
+       return true;
 }
 
 /*
  * Routing table change via netlink interface, using a dataplane context object
+ *
+ * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
+ * otherwise the number of bytes written to buf.
  */
-ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
-                               uint8_t *data, size_t datalen, bool fpm,
-                               bool force_nhg)
+ssize_t netlink_route_multipath_msg_encode(int cmd,
+                                          struct zebra_dplane_ctx *ctx,
+                                          uint8_t *data, size_t datalen,
+                                          bool fpm, bool force_nhg)
 {
        int bytelen;
        struct nexthop *nexthop = NULL;
@@ -1536,6 +1620,9 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
        p = dplane_ctx_get_dest(ctx);
        src_p = dplane_ctx_get_src(ctx);
 
+       if (datalen < sizeof(*req))
+               return 0;
+
        memset(req, 0, sizeof(*req));
 
        bytelen = (p->family == AF_INET ? 4 : 16);
@@ -1572,10 +1659,13 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
        if (cmd != RTM_DELROUTE)
                req->r.rtm_type = RTN_UNICAST;
 
-       nl_attr_put(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen);
-       if (src_p)
-               nl_attr_put(&req->n, datalen, RTA_SRC, &src_p->u.prefix,
-                           bytelen);
+       if (!nl_attr_put(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen))
+               return 0;
+       if (src_p) {
+               if (!nl_attr_put(&req->n, datalen, RTA_SRC, &src_p->u.prefix,
+                                bytelen))
+                       return 0;
+       }
 
        /* Metric. */
        /* Hardcode the metric for all routes coming from zebra. Metric isn't
@@ -1584,7 +1674,9 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
         * path(s)
         * by the routing protocol and for communicating with protocol peers.
         */
-       nl_attr_put32(&req->n, datalen, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
+       if (!nl_attr_put32(&req->n, datalen, RTA_PRIORITY,
+                          NL_DEFAULT_ROUTE_METRIC))
+               return 0;
 
 #if defined(SUPPORT_REALMS)
        {
@@ -1595,8 +1687,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                else
                        tag = dplane_ctx_get_tag(ctx);
 
-               if (tag > 0 && tag <= 255)
-                       nl_attr_put32(&req->n, datalen, RTA_FLOW, tag);
+               if (tag > 0 && tag <= 255) {
+                       if (!nl_attr_put32(&req->n, datalen, RTA_FLOW, tag))
+                               return 0;
+               }
        }
 #endif
        /* Table corresponding to this route. */
@@ -1605,7 +1699,8 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                req->r.rtm_table = table_id;
        else {
                req->r.rtm_table = RT_TABLE_UNSPEC;
-               nl_attr_put32(&req->n, datalen, RTA_TABLE, table_id);
+               if (!nl_attr_put32(&req->n, datalen, RTA_TABLE, table_id))
+                       return 0;
        }
 
        if (IS_ZEBRA_DEBUG_KERNEL)
@@ -1621,7 +1716,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
         * it.
         */
        if (cmd == RTM_DELROUTE)
-               return req->n.nlmsg_len;
+               return NLMSG_ALIGN(req->n.nlmsg_len);
 
        if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) {
                struct rtattr *nest;
@@ -1632,19 +1727,23 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                        mtu = nexthop_mtu;
 
                nest = nl_attr_nest(&req->n, datalen, RTA_METRICS);
-               nl_attr_put(&req->n, datalen, RTAX_MTU, &mtu, sizeof(mtu));
+               if (nest == NULL)
+                       return 0;
+
+               if (!nl_attr_put(&req->n, datalen, RTAX_MTU, &mtu, sizeof(mtu)))
+                       return 0;
                nl_attr_nest_end(&req->n, nest);
        }
 
        if (kernel_nexthops_supported() || force_nhg) {
                /* Kernel supports nexthop objects */
                if (IS_ZEBRA_DEBUG_KERNEL)
-                       zlog_debug(
-                               "netlink_route_multipath(): %pFX nhg_id is %u",
-                               p, dplane_ctx_get_nhe_id(ctx));
+                       zlog_debug("%s: %pFX nhg_id is %u", __func__, p,
+                                  dplane_ctx_get_nhe_id(ctx));
 
-               nl_attr_put32(&req->n, datalen, RTA_NH_ID,
-                             dplane_ctx_get_nhe_id(ctx));
+               if (!nl_attr_put32(&req->n, datalen, RTA_NH_ID,
+                                  dplane_ctx_get_nhe_id(ctx)))
+                       return 0;
 
                /* Have to determine src still */
                for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
@@ -1655,15 +1754,18 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                }
 
                if (setsrc) {
-                       if (p->family == AF_INET)
-                               nl_attr_put(&req->n, datalen, RTA_PREFSRC,
-                                           &src.ipv4, bytelen);
-                       else if (p->family == AF_INET6)
-                               nl_attr_put(&req->n, datalen, RTA_PREFSRC,
-                                           &src.ipv6, bytelen);
+                       if (p->family == AF_INET) {
+                               if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+                                                &src.ipv4, bytelen))
+                                       return 0;
+                       } else if (p->family == AF_INET6) {
+                               if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+                                                &src.ipv6, bytelen))
+                                       return 0;
+                       }
                }
 
-               return req->n.nlmsg_len;
+               return NLMSG_ALIGN(req->n.nlmsg_len);
        }
 
        /* Count overall nexthops so we can decide whether to use singlepath
@@ -1702,7 +1804,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                                        req->r.rtm_type = RTN_BLACKHOLE;
                                        break;
                                }
-                               return req->n.nlmsg_len;
+                               return NLMSG_ALIGN(req->n.nlmsg_len);
                        }
                        if (CHECK_FLAG(nexthop->flags,
                                       NEXTHOP_FLAG_RECURSIVE)) {
@@ -1720,9 +1822,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                                                    ? "recursive, single-path"
                                                    : "single-path";
 
-                               _netlink_route_build_singlepath(
-                                       p, routedesc, bytelen, nexthop, &req->n,
-                                       &req->r, datalen, cmd);
+                               if (!_netlink_route_build_singlepath(
+                                           p, routedesc, bytelen, nexthop,
+                                           &req->n, &req->r, datalen, cmd))
+                                       return 0;
                                nexthop_num++;
                                break;
                        }
@@ -1731,24 +1834,31 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                         * Add encapsulation information when installing via
                         * FPM.
                         */
-                       if (fpm)
-                               netlink_route_nexthop_encap(&req->n, datalen,
-                                                           nexthop);
+                       if (fpm) {
+                               if (!netlink_route_nexthop_encap(
+                                           &req->n, datalen, nexthop))
+                                       return 0;
+                       }
                }
 
                if (setsrc) {
-                       if (p->family == AF_INET)
-                               nl_attr_put(&req->n, datalen, RTA_PREFSRC,
-                                           &src.ipv4, bytelen);
-                       else if (p->family == AF_INET6)
-                               nl_attr_put(&req->n, datalen, RTA_PREFSRC,
-                                           &src.ipv6, bytelen);
+                       if (p->family == AF_INET) {
+                               if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+                                                &src.ipv4, bytelen))
+                                       return 0;
+                       } else if (p->family == AF_INET6) {
+                               if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+                                                &src.ipv6, bytelen))
+                                       return 0;
+                       }
                }
        } else {    /* Multipath case */
                struct rtattr *nest;
                const union g_addr *src1 = NULL;
 
                nest = nl_attr_nest(&req->n, datalen, RTA_MULTIPATH);
+               if (nest == NULL)
+                       return 0;
 
                nexthop_num = 0;
                for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
@@ -1769,9 +1879,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                                                    : "multipath";
                                nexthop_num++;
 
-                               _netlink_route_build_multipath(
-                                       p, routedesc, bytelen, nexthop, &req->n,
-                                       datalen, &req->r, &src1);
+                               if (!_netlink_route_build_multipath(
+                                           p, routedesc, bytelen, nexthop,
+                                           &req->n, datalen, &req->r, &src1))
+                                       return 0;
 
                                if (!setsrc && src1) {
                                        if (p->family == AF_INET)
@@ -1783,6 +1894,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                                }
                        }
                }
+
                nl_attr_nest_end(&req->n, nest);
 
                /*
@@ -1795,20 +1907,23 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
                                if (CHECK_FLAG(nexthop->flags,
                                               NEXTHOP_FLAG_RECURSIVE))
                                        continue;
-
-                               netlink_route_nexthop_encap(&req->n, datalen,
-                                                           nexthop);
+                               if (!netlink_route_nexthop_encap(
+                                           &req->n, datalen, nexthop))
+                                       return 0;
                        }
                }
 
 
                if (setsrc) {
-                       if (p->family == AF_INET)
-                               nl_attr_put(&req->n, datalen, RTA_PREFSRC,
-                                           &src.ipv4, bytelen);
-                       else if (p->family == AF_INET6)
-                               nl_attr_put(&req->n, datalen, RTA_PREFSRC,
-                                           &src.ipv6, bytelen);
+                       if (p->family == AF_INET) {
+                               if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+                                                &src.ipv4, bytelen))
+                                       return 0;
+                       } else if (p->family == AF_INET6) {
+                               if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
+                                                &src.ipv6, bytelen))
+                                       return 0;
+                       }
                        if (IS_ZEBRA_DEBUG_KERNEL)
                                zlog_debug("Setting source");
                }
@@ -1879,7 +1994,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
 /* Char length to debug ID with */
 #define ID_LENGTH 10
 
-static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
+static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
                                         uint32_t id,
                                         const struct nh_grp *z_grp,
                                         const uint8_t count)
@@ -1909,11 +2024,15 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
                                }
                        }
                }
-               nl_attr_put(n, req_size, NHA_GROUP, grp, count * sizeof(*grp));
+               if (!nl_attr_put(n, req_size, NHA_GROUP, grp,
+                                count * sizeof(*grp)))
+                       return false;
        }
 
        if (IS_ZEBRA_DEBUG_KERNEL)
                zlog_debug("%s: ID (%u): %s", __func__, id, buf);
+
+       return true;
 }
 
 /**
@@ -1924,10 +2043,12 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
  * \param[out] buf buffer to hold the packet.
  * \param[in] buflen amount of buffer bytes.
  *
- * \returns -1 on failure or the number of bytes written to buf.
+ * \returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
+ * otherwise the number of bytes written to buf.
  */
-ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
-                              void *buf, size_t buflen)
+ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
+                                  const struct zebra_dplane_ctx *ctx,
+                                  void *buf, size_t buflen)
 {
        struct {
                struct nlmsghdr n;
@@ -1941,7 +2062,10 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
 
        label_buf[0] = '\0';
 
-       memset(req, 0, buflen);
+       if (buflen < sizeof(*req))
+               return 0;
+
+       memset(req, 0, sizeof(*req));
 
        req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
        req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
@@ -1964,7 +2088,8 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
                return -1;
        }
 
-       nl_attr_put32(&req->n, buflen, NHA_ID, id);
+       if (!nl_attr_put32(&req->n, buflen, NHA_ID, id))
+               return 0;
 
        if (cmd == RTM_NEWNEXTHOP) {
                /*
@@ -1973,12 +2098,13 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
                 * group is installed as an id that just refers to a list of
                 * other ids.
                 */
-               if (dplane_ctx_get_nhe_nh_grp_count(ctx))
-                       _netlink_nexthop_build_group(
-                               &req->n, buflen, id,
-                               dplane_ctx_get_nhe_nh_grp(ctx),
-                               dplane_ctx_get_nhe_nh_grp_count(ctx));
-               else {
+               if (dplane_ctx_get_nhe_nh_grp_count(ctx)) {
+                       if (_netlink_nexthop_build_group(
+                                   &req->n, buflen, id,
+                                   dplane_ctx_get_nhe_nh_grp(ctx),
+                                   dplane_ctx_get_nhe_nh_grp_count(ctx)))
+                               return 0;
+               } else {
                        const struct nexthop *nh =
                                dplane_ctx_get_nhe_ng(ctx)->nexthop;
                        afi_t afi = dplane_ctx_get_nhe_afi(ctx);
@@ -1991,17 +2117,22 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
                        switch (nh->type) {
                        case NEXTHOP_TYPE_IPV4:
                        case NEXTHOP_TYPE_IPV4_IFINDEX:
-                               nl_attr_put(&req->n, buflen, NHA_GATEWAY,
-                                           &nh->gate.ipv4, IPV4_MAX_BYTELEN);
+                               if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
+                                                &nh->gate.ipv4,
+                                                IPV4_MAX_BYTELEN))
+                                       return 0;
                                break;
                        case NEXTHOP_TYPE_IPV6:
                        case NEXTHOP_TYPE_IPV6_IFINDEX:
-                               nl_attr_put(&req->n, buflen, NHA_GATEWAY,
-                                           &nh->gate.ipv6, IPV6_MAX_BYTELEN);
+                               if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
+                                                &nh->gate.ipv6,
+                                                IPV6_MAX_BYTELEN))
+                                       return 0;
                                break;
                        case NEXTHOP_TYPE_BLACKHOLE:
-                               nl_attr_put(&req->n, buflen, NHA_BLACKHOLE,
-                                           NULL, 0);
+                               if (!nl_attr_put(&req->n, buflen, NHA_BLACKHOLE,
+                                                NULL, 0))
+                                       return 0;
                                /* Blackhole shouldn't have anymore attributes
                                 */
                                goto nexthop_done;
@@ -2017,7 +2148,9 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
                                return -1;
                        }
 
-                       nl_attr_put32(&req->n, buflen, NHA_OIF, nh->ifindex);
+                       if (!nl_attr_put32(&req->n, buflen, NHA_OIF,
+                                          nh->ifindex))
+                               return 0;
 
                        if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
                                req->nhm.nh_flags |= RTNH_F_ONLINK;
@@ -2037,25 +2170,31 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
                                if (req->nhm.nh_family == AF_MPLS)
                                        goto nexthop_done;
 #if 0
-                                       nl_attr_put(&req->n, buflen, NHA_NEWDST,
+                                       if (!nl_attr_put(&req->n, buflen, NHA_NEWDST,
                                                  &out_lse,
                                                  num_labels
-                                                         * sizeof(mpls_lse_t));
+                                                         * sizeof(mpls_lse_t)))
+                                               return 0;
 #endif
                                else {
                                        struct rtattr *nest;
                                        uint16_t encap = LWTUNNEL_ENCAP_MPLS;
 
-                                       nl_attr_put(&req->n, buflen,
-                                                   NHA_ENCAP_TYPE, &encap,
-                                                   sizeof(uint16_t));
+                                       if (!nl_attr_put(&req->n, buflen,
+                                                        NHA_ENCAP_TYPE, &encap,
+                                                        sizeof(uint16_t)))
+                                               return 0;
                                        nest = nl_attr_nest(&req->n, buflen,
                                                            NHA_ENCAP);
-                                       nl_attr_put(
-                                               &req->n, buflen,
-                                               MPLS_IPTUNNEL_DST, &out_lse,
-                                               num_labels
-                                                       * sizeof(mpls_lse_t));
+                                       if (!nest)
+                                               return 0;
+                                       if (!nl_attr_put(
+                                                   &req->n, buflen,
+                                                   MPLS_IPTUNNEL_DST, &out_lse,
+                                                   num_labels
+                                                           * sizeof(
+                                                                   mpls_lse_t)))
+                                               return 0;
                                        nl_attr_nest_end(&req->n, nest);
                                }
                        }
@@ -2067,7 +2206,7 @@ nexthop_done:
                                           __func__, id, nh, nh->ifindex,
                                           vrf_id_to_name(nh->vrf_id),
                                           nh->vrf_id, label_buf);
-               }
+}
 
                req->nhm.nh_protocol =
                        zebra2proto(dplane_ctx_get_nhe_type(ctx));
@@ -2117,7 +2256,7 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
        if (!kernel_nexthops_supported())
                return ZEBRA_DPLANE_REQUEST_SUCCESS;
 
-       if (netlink_nexthop_encode(cmd, ctx, buf, sizeof(buf)) > 0)
+       if (netlink_nexthop_msg_encode(cmd, ctx, buf, sizeof(buf)) > 0)
                ret = netlink_talk_info(netlink_talk_filter, (void *)&buf,
                                        dplane_ctx_get_ns(ctx), 0);
        else
@@ -2158,12 +2297,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
                         */
                        if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) &&
                            !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
-                               netlink_route_multipath(RTM_DELROUTE, ctx,
-                                                       nl_pkt, sizeof(nl_pkt),
-                                                       false, false);
-                               netlink_talk_info(netlink_talk_filter,
-                                                 (struct nlmsghdr *)nl_pkt,
-                                                 dplane_ctx_get_ns(ctx), 0);
+                               if (netlink_route_multipath_msg_encode(
+                                           RTM_DELROUTE, ctx, nl_pkt,
+                                           sizeof(nl_pkt), false, false)
+                                   > 0)
+                                       netlink_talk_info(
+                                               netlink_talk_filter,
+                                               (struct nlmsghdr *)nl_pkt,
+                                               dplane_ctx_get_ns(ctx), 0);
                        }
                } else {
                        /*
@@ -2179,12 +2320,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
                         * screwed.
                         */
                        if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
-                               netlink_route_multipath(RTM_DELROUTE, ctx,
-                                                       nl_pkt, sizeof(nl_pkt),
-                                                       false, false);
-                               netlink_talk_info(netlink_talk_filter,
-                                                 (struct nlmsghdr *)nl_pkt,
-                                                 dplane_ctx_get_ns(ctx), 0);
+                               if (netlink_route_multipath_msg_encode(
+                                           RTM_DELROUTE, ctx, nl_pkt,
+                                           sizeof(nl_pkt), false, false)
+                                   > 0)
+                                       netlink_talk_info(
+                                               netlink_talk_filter,
+                                               (struct nlmsghdr *)nl_pkt,
+                                               dplane_ctx_get_ns(ctx), 0);
                        }
                        cmd = RTM_NEWROUTE;
                }
@@ -2194,11 +2337,15 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
        }
 
        if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) {
-               netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt), false,
-                                       false);
-               ret = netlink_talk_info(netlink_talk_filter,
-                                       (struct nlmsghdr *)nl_pkt,
-                                       dplane_ctx_get_ns(ctx), 0);
+               if (netlink_route_multipath_msg_encode(
+                           cmd, ctx, nl_pkt, sizeof(nl_pkt), false, false)
+                   > 0)
+                       ret = netlink_talk_info(netlink_talk_filter,
+                                               (struct nlmsghdr *)nl_pkt,
+                                               dplane_ctx_get_ns(ctx), 0);
+               else
+                       ret = -1;
+
        } else
                ret = 0;
        if ((cmd == RTM_NEWROUTE) && (ret == 0)) {
@@ -2522,8 +2669,8 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
 }
 
 /**
- * netlink_update_neigh_ctx_internal() - Common helper api for evpn
- * neighbor updates using dataplane context object.
+ * netlink_neigh_update_msg_encode() - Common helper api for encoding
+ * evpn neighbor update as netlink messages using dataplane context object.
  * Here, a neighbor refers to a bridge forwarding database entry for
  * either unicast forwarding or head-end replication or an IP neighbor
  * entry.
@@ -2542,14 +2689,13 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
  * @data:              data buffer pointer
  * @datalen:           total amount of data buffer space
  *
- * Return:             Result status
+ * Return:             0 when the msg doesn't fit entirely in the buffer
+ *                             otherwise the number of bytes written to buf.
  */
-static ssize_t
-netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx,
-                                 int cmd, const struct ethaddr *mac,
-                                 const struct ipaddr *ip, bool replace_obj,
-                                 uint8_t family, uint8_t type, uint8_t flags,
-                                 uint16_t state, void *data, size_t datalen)
+static ssize_t netlink_neigh_update_msg_encode(
+       const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac,
+       const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type,
+       uint8_t flags, uint16_t state, void *data, size_t datalen)
 {
        uint8_t protocol = RTPROT_ZEBRA;
        struct {
@@ -2560,6 +2706,8 @@ netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx,
        int ipa_len;
        enum dplane_op_e op;
 
+       if (datalen < sizeof(*req))
+               return 0;
        memset(req, 0, datalen);
 
        op = dplane_ctx_get_op(ctx);
@@ -2577,22 +2725,30 @@ netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx,
        req->ndm.ndm_flags = flags;
        req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
 
-       nl_attr_put(&req->n, sizeof(req), NDA_PROTOCOL, &protocol,
-                   sizeof(protocol));
-       if (mac)
-               nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6);
+       if (!nl_attr_put(&req->n, sizeof(req), NDA_PROTOCOL, &protocol,
+                        sizeof(protocol)))
+               return 0;
+
+       if (mac) {
+               if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6))
+                       return 0;
+       }
 
        ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
-       nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len);
+       if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len))
+               return 0;
 
        if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
                vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
 
-               if (vid > 0)
-                       nl_attr_put16(&req->n, datalen, NDA_VLAN, vid);
+               if (vid > 0) {
+                       if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid))
+                               return 0;
+               }
 
-               nl_attr_put32(&req->n, datalen, NDA_MASTER,
-                             dplane_ctx_mac_get_br_ifindex(ctx));
+               if (!nl_attr_put32(&req->n, datalen, NDA_MASTER,
+                                  dplane_ctx_mac_get_br_ifindex(ctx)))
+                       return 0;
        }
 
        return NLMSG_ALIGN(req->n.nlmsg_len);
@@ -2608,10 +2764,12 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx,
        struct ethaddr dst_mac = {.octet = {0}};
        uint8_t nl_pkt[NL_PKT_BUF_SIZE];
 
-        netlink_update_neigh_ctx_internal(
-               ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
-               PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), nl_pkt,
-               sizeof(nl_pkt));
+       if (netlink_neigh_update_msg_encode(
+                   ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false,
+                   PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), nl_pkt,
+                   sizeof(nl_pkt))
+           <= 0)
+               return -1;
 
        return netlink_talk_info(netlink_talk_filter,
                                 (struct nlmsghdr *)nl_pkt,
@@ -2989,9 +3147,9 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
                           ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf)));
        }
 
-       total = netlink_update_neigh_ctx_internal(
-                       ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip,
-                       true, AF_BRIDGE, 0, flags, state, data, datalen);
+       total = netlink_neigh_update_msg_encode(
+               ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true,
+               AF_BRIDGE, 0, flags, state, data, datalen);
 
        return total;
 }
@@ -3407,9 +3565,11 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
                        flags, state);
        }
 
-       netlink_update_neigh_ctx_internal(
-                       ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags,
-                       state, nl_pkt, sizeof(nl_pkt));
+       if (netlink_neigh_update_msg_encode(ctx, cmd, mac, ip, true, family,
+                                           RTN_UNICAST, flags, state, nl_pkt,
+                                           sizeof(nl_pkt))
+           <= 0)
+               return -1;
 
        return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
                                 dplane_ctx_get_ns(ctx), 0);
@@ -3464,7 +3624,8 @@ enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx)
  * MPLS label forwarding table change via netlink interface, using dataplane
  * context information.
  */
-int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
+ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
+                                         void *buf, size_t buflen)
 {
        mpls_lse_t lse;
        const struct nhlfe_list_head *head;
@@ -3478,10 +3639,13 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
        struct {
                struct nlmsghdr n;
                struct rtmsg r;
-               char buf[NL_PKT_BUF_SIZE];
-       } req;
+               char buf[0];
+       } *req = buf;
+
+       if (buflen < sizeof(*req))
+               return 0;
 
-       memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE);
+       memset(req, 0, sizeof(*req));
 
        /*
         * Count # nexthops so we can decide whether to use singlepath
@@ -3510,30 +3674,31 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
            (!dplane_ctx_get_best_nhlfe(ctx) && (cmd != RTM_DELROUTE)))
                return 0;
 
-       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
-       req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
-       req.n.nlmsg_type = cmd;
-       req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
+       req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+       req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+       req->n.nlmsg_type = cmd;
+       req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
 
-       req.r.rtm_family = AF_MPLS;
-       req.r.rtm_table = RT_TABLE_MAIN;
-       req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
-       req.r.rtm_scope = RT_SCOPE_UNIVERSE;
-       req.r.rtm_type = RTN_UNICAST;
+       req->r.rtm_family = AF_MPLS;
+       req->r.rtm_table = RT_TABLE_MAIN;
+       req->r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
+       req->r.rtm_scope = RT_SCOPE_UNIVERSE;
+       req->r.rtm_type = RTN_UNICAST;
 
        if (cmd == RTM_NEWROUTE) {
                /* We do a replace to handle update. */
-               req.n.nlmsg_flags |= NLM_F_REPLACE;
+               req->n.nlmsg_flags |= NLM_F_REPLACE;
 
                /* set the protocol value if installing */
                route_type = re_type_from_lsp_type(
                        dplane_ctx_get_best_nhlfe(ctx)->type);
-               req.r.rtm_protocol = zebra2proto(route_type);
+               req->r.rtm_protocol = zebra2proto(route_type);
        }
 
        /* Fill destination */
        lse = mpls_lse_encode(dplane_ctx_get_in_label(ctx), 0, 0, 1);
-       nl_attr_put(&req.n, sizeof(req), RTA_DST, &lse, sizeof(mpls_lse_t));
+       if (!nl_attr_put(&req->n, buflen, RTA_DST, &lse, sizeof(mpls_lse_t)))
+               return 0;
 
        /* Fill nexthops (paths) based on single-path or multipath. The paths
         * chosen depend on the operation.
@@ -3559,9 +3724,10 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
                                    && CHECK_FLAG(nexthop->flags,
                                                  NEXTHOP_FLAG_FIB)))) {
                                /* Add the gateway */
-                               _netlink_mpls_build_singlepath(
-                                       &p, routedesc, nhlfe, &req.n, &req.r,
-                                       sizeof(req), cmd);
+                               if (!_netlink_mpls_build_singlepath(
+                                           &p, routedesc, nhlfe, &req->n,
+                                           &req->r, buflen, cmd))
+                                       return false;
 
                                nexthop_num++;
                                break;
@@ -3571,7 +3737,9 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
                struct rtattr *nest;
                const union g_addr *src1 = NULL;
 
-               nest = nl_attr_nest(&req.n, sizeof(req), RTA_MULTIPATH);
+               nest = nl_attr_nest(&req->n, buflen, RTA_MULTIPATH);
+               if (!nest)
+                       return 0;
 
                routedesc = "multipath";
                _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
@@ -3595,18 +3763,17 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx)
                                nexthop_num++;
 
                                /* Build the multipath */
-                               _netlink_mpls_build_multipath(
-                                       &p, routedesc, nhlfe, &req.n,
-                                       sizeof(req), &req.r, &src1);
+                               if (!_netlink_mpls_build_multipath(
+                                           &p, routedesc, nhlfe, &req->n,
+                                           buflen, &req->r, &src1))
+                                       return 0;
                        }
                }
 
                /* Add the multipath */
-               nl_attr_nest_end(&req.n, nest);
+               nl_attr_nest_end(&req->n, nest);
        }
 
-       /* Talk to netlink socket. */
-       return netlink_talk_info(netlink_talk_filter, &req.n,
-                                dplane_ctx_get_ns(ctx), 0);
+       return NLMSG_ALIGN(req->n.nlmsg_len);
 }
 #endif /* HAVE_NETLINK */
index c09609f47cfc1215f10d116953d971045f6f69ee..429ff0bf8521081515d13b61f5484422049ec780 100644 (file)
@@ -64,11 +64,14 @@ extern "C" {
 void rt_netlink_init(void);
 
 /* MPLS label forwarding table change, using dataplane context information. */
-extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx);
+extern ssize_t netlink_mpls_multipath_msg_encode(int cmd,
+                                                struct zebra_dplane_ctx *ctx,
+                                                void *buf, size_t buflen);
 
-extern ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
-                                      uint8_t *data, size_t datalen, bool fpm,
-                                      bool force_nhg);
+extern ssize_t netlink_route_multipath_msg_encode(int cmd,
+                                                 struct zebra_dplane_ctx *ctx,
+                                                 uint8_t *data, size_t datalen,
+                                                 bool fpm, bool force_nhg);
 extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx,
                                         uint8_t *data, size_t datalen);
 
@@ -78,9 +81,9 @@ extern int netlink_route_read(struct zebra_ns *zns);
 extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id,
                                  int startup);
 extern int netlink_nexthop_read(struct zebra_ns *zns);
-extern ssize_t netlink_nexthop_encode(uint16_t cmd,
-                                     const struct zebra_dplane_ctx *ctx,
-                                     void *buf, size_t buflen);
+extern ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
+                                         const struct zebra_dplane_ctx *ctx,
+                                         void *buf, size_t buflen);
 
 extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id);
 extern int netlink_macfdb_read(struct zebra_ns *zns);
index 8dbdc84589cab8d984c595562303da914d62d423..b7be3985069fcb51e59289b5ce6f4b5bab5b8319 100644 (file)
@@ -87,38 +87,48 @@ static ssize_t netlink_rule_msg_encode(
        req->frh.family = family;
        req->frh.action = FR_ACT_TO_TBL;
 
-       nl_attr_put(&req->n, buflen, FRA_PROTOCOL, &protocol, sizeof(protocol));
+       if (!nl_attr_put(&req->n, buflen, FRA_PROTOCOL, &protocol,
+                        sizeof(protocol)))
+               return 0;
 
        /* rule's pref # */
-       nl_attr_put32(&req->n, buflen, FRA_PRIORITY, priority);
+       if (!nl_attr_put32(&req->n, buflen, FRA_PRIORITY, priority))
+               return 0;
 
        /* interface on which applied */
-       nl_attr_put(&req->n, buflen, FRA_IFNAME, ifname, strlen(ifname) + 1);
+       if (!nl_attr_put(&req->n, buflen, FRA_IFNAME, ifname,
+                        strlen(ifname) + 1))
+               return 0;
 
        /* source IP, if specified */
        if (filter_bm & PBR_FILTER_SRC_IP) {
                req->frh.src_len = src_ip->prefixlen;
-               nl_attr_put(&req->n, buflen, FRA_SRC, &src_ip->u.prefix,
-                           bytelen);
+               if (!nl_attr_put(&req->n, buflen, FRA_SRC, &src_ip->u.prefix,
+                                bytelen))
+                       return 0;
        }
 
        /* destination IP, if specified */
        if (filter_bm & PBR_FILTER_DST_IP) {
                req->frh.dst_len = dst_ip->prefixlen;
-               nl_attr_put(&req->n, buflen, FRA_DST, &dst_ip->u.prefix,
-                           bytelen);
+               if (!nl_attr_put(&req->n, buflen, FRA_DST, &dst_ip->u.prefix,
+                                bytelen))
+                       return 0;
        }
 
        /* fwmark, if specified */
-       if (filter_bm & PBR_FILTER_FWMARK)
-               nl_attr_put32(&req->n, buflen, FRA_FWMARK, fwmark);
+       if (filter_bm & PBR_FILTER_FWMARK) {
+               if (!nl_attr_put32(&req->n, buflen, FRA_FWMARK, fwmark))
+                       return 0;
+       }
 
        /* Route table to use to forward, if filter criteria matches. */
        if (table < 256)
                req->frh.table = table;
        else {
                req->frh.table = RT_TABLE_UNSPEC;
-               nl_attr_put32(&req->n, buflen, FRA_TABLE, table);
+               if (!nl_attr_put32(&req->n, buflen, FRA_TABLE, table))
+                       return 0;
        }
 
        if (IS_ZEBRA_DEBUG_KERNEL)
index a9233530dc9c16968bffa25f07f6fda3381d4cc4..c95a0216399cc703efd7a9b26f9af550966a757e 100644 (file)
 #include "zebra/rt.h"
 #include "zebra/rt_netlink.h"
 #include "zebra/zebra_mpls.h"
+#include "zebra/kernel_netlink.h"
 
 /*
  * LSP forwarding update using dataplane context information.
  */
 enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
 {
-       int cmd, ret = -1;
+       uint8_t nl_pkt[NL_PKT_BUF_SIZE];
+       ssize_t ret = -1;
+       int cmd;
 
        /* Call to netlink layer based on type of update */
        if (dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_DELETE) {
@@ -53,7 +56,13 @@ enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx)
                /* Invalid op? */
                goto done;
 
-       ret = netlink_mpls_multipath(cmd, ctx);
+       ret = netlink_mpls_multipath_msg_encode(cmd, ctx, nl_pkt,
+                                               sizeof(nl_pkt));
+       if (ret <= 0)
+               return ZEBRA_DPLANE_REQUEST_FAILURE;
+
+       ret = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt,
+                               dplane_ctx_get_ns(ctx), 0);
 
 done: