mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-09 03:47:47 +00:00
zebra: Fix extended ack error message parsing
Fix the macros for reading NLA attribute info from an extended error ack. We were processing the data using route attributes (rtattr) which is identical in size to nlattr but probably should not be used. Further, we were incorrectly calculating the length of the inner netlink message that cause the error. We have to read passed that in order to access all the nlattr's. Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
This commit is contained in:
parent
dfff60ed31
commit
4cebb2b6f6
@ -606,50 +606,56 @@ const char *nl_rttype_to_str(uint8_t rttype)
|
|||||||
return lookup_msg(rttype_str, rttype, "");
|
return lookup_msg(rttype_str, rttype, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NL_OK(nla, len) \
|
#define NLA_OK(nla, len) \
|
||||||
((len) >= (int)sizeof(struct nlattr) \
|
((len) >= (int)sizeof(struct nlattr) \
|
||||||
&& (nla)->nla_len >= sizeof(struct nlattr) \
|
&& (nla)->nla_len >= sizeof(struct nlattr) \
|
||||||
&& (nla)->nla_len <= (len))
|
&& (nla)->nla_len <= (len))
|
||||||
#define NL_NEXT(nla, attrlen) \
|
#define NLA_NEXT(nla, attrlen) \
|
||||||
((attrlen) -= RTA_ALIGN((nla)->nla_len), \
|
((attrlen) -= NLA_ALIGN((nla)->nla_len), \
|
||||||
(struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
|
(struct nlattr *)(((char *)(nla)) + NLA_ALIGN((nla)->nla_len)))
|
||||||
#define NL_RTA(r) \
|
#define NLA_LENGTH(len) (NLA_ALIGN(sizeof(struct nlattr)) + (len))
|
||||||
((struct nlattr *)(((char *)(r)) \
|
#define NLA_DATA(nla) ((struct nlattr *)(((char *)(nla)) + NLA_LENGTH(0)))
|
||||||
+ NLMSG_ALIGN(sizeof(struct nlmsgerr))))
|
|
||||||
|
#define ERR_NLA(err, inner_len) \
|
||||||
|
((struct nlattr *)(((char *)(err)) \
|
||||||
|
+ NLMSG_ALIGN(sizeof(struct nlmsgerr)) \
|
||||||
|
+ NLMSG_ALIGN((inner_len))))
|
||||||
|
|
||||||
static void netlink_parse_nlattr(struct nlattr **tb, int max,
|
static void netlink_parse_nlattr(struct nlattr **tb, int max,
|
||||||
struct nlattr *nla, int len)
|
struct nlattr *nla, int len)
|
||||||
{
|
{
|
||||||
while (NL_OK(nla, len)) {
|
while (NLA_OK(nla, len)) {
|
||||||
if (nla->nla_type <= max)
|
if (nla->nla_type <= max)
|
||||||
tb[nla->nla_type] = nla;
|
tb[nla->nla_type] = nla;
|
||||||
nla = NL_NEXT(nla, len);
|
nla = NLA_NEXT(nla, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netlink_parse_extended_ack(struct nlmsghdr *h)
|
static void netlink_parse_extended_ack(struct nlmsghdr *h)
|
||||||
{
|
{
|
||||||
struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
|
struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
|
||||||
const struct nlmsgerr *err =
|
const struct nlmsgerr *err = (const struct nlmsgerr *)NLMSG_DATA(h);
|
||||||
(const struct nlmsgerr *)((uint8_t *)h
|
|
||||||
+ NLMSG_ALIGN(
|
|
||||||
sizeof(struct nlmsghdr)));
|
|
||||||
const struct nlmsghdr *err_nlh = NULL;
|
const struct nlmsghdr *err_nlh = NULL;
|
||||||
uint32_t hlen = sizeof(*err);
|
/* Length not including nlmsghdr */
|
||||||
|
uint32_t len = 0;
|
||||||
|
/* Inner error netlink message length */
|
||||||
|
uint32_t inner_len = 0;
|
||||||
const char *msg = NULL;
|
const char *msg = NULL;
|
||||||
uint32_t off = 0;
|
uint32_t off = 0;
|
||||||
|
|
||||||
if (!(h->nlmsg_flags & NLM_F_CAPPED))
|
if (!(h->nlmsg_flags & NLM_F_CAPPED))
|
||||||
hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
|
inner_len = (uint32_t)NLMSG_PAYLOAD(&err->msg, 0);
|
||||||
|
|
||||||
memset(tb, 0, sizeof(tb));
|
len = (uint32_t)(NLMSG_PAYLOAD(h, sizeof(struct nlmsgerr)) - inner_len);
|
||||||
netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
|
|
||||||
|
netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, ERR_NLA(err, inner_len),
|
||||||
|
len);
|
||||||
|
|
||||||
if (tb[NLMSGERR_ATTR_MSG])
|
if (tb[NLMSGERR_ATTR_MSG])
|
||||||
msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
|
msg = (const char *)NLA_DATA(tb[NLMSGERR_ATTR_MSG]);
|
||||||
|
|
||||||
if (tb[NLMSGERR_ATTR_OFFS]) {
|
if (tb[NLMSGERR_ATTR_OFFS]) {
|
||||||
off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
|
off = *(uint32_t *)NLA_DATA(tb[NLMSGERR_ATTR_OFFS]);
|
||||||
|
|
||||||
if (off > h->nlmsg_len) {
|
if (off > h->nlmsg_len) {
|
||||||
zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS");
|
zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS");
|
||||||
|
Loading…
Reference in New Issue
Block a user