Skip to content

Commit

Permalink
net/neighbor: Update neigh_dump_info for strict data checking
Browse files Browse the repository at this point in the history
Update neigh_dump_info for strict data checking. If the flag is set,
the dump request is expected to have an ndmsg struct as the header
potentially followed by one or more attributes. Any data passed in the
header or as an attribute is taken as a request to influence the data
returned. Only values supported by the dump handler are allowed to be
non-0 or set in the request. At the moment only the NDA_IFINDEX and
NDA_MASTER attributes are supported.

Existing code does not fail the dump if nlmsg_parse fails. That behavior
is kept for non-strict checking.

Signed-off-by: David Ahern <dsahern@gmail.com>
Acked-by: Christian Brauner <christian@brauner.io>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and David S. Miller committed Oct 8, 2018
1 parent e8ba330 commit 51183d2
Showing 1 changed file with 67 additions and 15 deletions.
82 changes: 67 additions & 15 deletions net/core/neighbour.c
Original file line number Diff line number Diff line change
Expand Up @@ -2426,11 +2426,73 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,

}

static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
bool strict_check,
struct neigh_dump_filter *filter,
struct netlink_ext_ack *extack)
{
struct nlattr *tb[NDA_MAX + 1];
int err, i;

if (strict_check) {
struct ndmsg *ndm;

if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
return -EINVAL;
}

ndm = nlmsg_data(nlh);
if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex ||
ndm->ndm_state || ndm->ndm_flags || ndm->ndm_type) {
NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
return -EINVAL;
}

err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
NULL, extack);
} else {
err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
NULL, extack);
}
if (err < 0)
return err;

for (i = 0; i <= NDA_MAX; ++i) {
if (!tb[i])
continue;

/* all new attributes should require strict_check */
switch (i) {
case NDA_IFINDEX:
if (nla_len(tb[i]) != sizeof(u32)) {
NL_SET_ERR_MSG(extack, "Invalid IFINDEX attribute in neighbor dump request");
return -EINVAL;
}
filter->dev_idx = nla_get_u32(tb[i]);
break;
case NDA_MASTER:
if (nla_len(tb[i]) != sizeof(u32)) {
NL_SET_ERR_MSG(extack, "Invalid MASTER attribute in neighbor dump request");
return -EINVAL;
}
filter->master_idx = nla_get_u32(tb[i]);
break;
default:
if (strict_check) {
NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
return -EINVAL;
}
}
}

return 0;
}

static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
{
const struct nlmsghdr *nlh = cb->nlh;
struct neigh_dump_filter filter = {};
struct nlattr *tb[NDA_MAX + 1];
struct neigh_table *tbl;
int t, family, s_t;
int proxy = 0;
Expand All @@ -2445,20 +2507,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
proxy = 1;

err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL,
cb->extack);
if (!err) {
if (tb[NDA_IFINDEX]) {
if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32))
return -EINVAL;
filter.dev_idx = nla_get_u32(tb[NDA_IFINDEX]);
}
if (tb[NDA_MASTER]) {
if (nla_len(tb[NDA_MASTER]) != sizeof(u32))
return -EINVAL;
filter.master_idx = nla_get_u32(tb[NDA_MASTER]);
}
}
err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
if (err < 0 && cb->strict_check)
return err;

s_t = cb->args[0];

for (t = 0; t < NEIGH_NR_TABLES; t++) {
Expand Down

0 comments on commit 51183d2

Please sign in to comment.