summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Urbańczyk <xthaid@gmail.com>2020-06-10 11:44:31 +0200
committerJakub Urbańczyk <xthaid@gmail.com>2020-06-13 22:56:25 +0200
commit0be6e7d75dbbbfae33c3b51ae7c160d35b228915 (patch)
treebce89dc6c75a01809334c591f21ac9c5ab455465
parent312a6beed67017e53679673a763c7693514cdd7e (diff)
zebra: check for buffer boundary
* 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>
-rw-r--r--zebra/dplane_fpm_nl.c32
-rw-r--r--zebra/rt_netlink.c641
-rw-r--r--zebra/rt_netlink.h17
-rw-r--r--zebra/rule_netlink.c30
-rw-r--r--zebra/zebra_mpls_netlink.c13
5 files changed, 463 insertions, 270 deletions
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 88d5ab5cec..ef208bdc83 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -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;
}
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 238eea6d35..9261d1b975 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -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 */
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index c09609f47c..429ff0bf85 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -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);
diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c
index 8dbdc84589..b7be398506 100644
--- a/zebra/rule_netlink.c
+++ b/zebra/rule_netlink.c
@@ -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)
diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c
index a9233530dc..c95a021639 100644
--- a/zebra/zebra_mpls_netlink.c
+++ b/zebra/zebra_mpls_netlink.c
@@ -26,13 +26,16 @@
#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: