Skip to content

Commit 51183d2

Browse files
dsaherndavem330
authored andcommitted
net/neighbor: Update neigh_dump_info for strict data checking
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 <[email protected]> Acked-by: Christian Brauner <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e8ba330 commit 51183d2

File tree

1 file changed

+67
-15
lines changed

1 file changed

+67
-15
lines changed

net/core/neighbour.c

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2426,11 +2426,73 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
24262426

24272427
}
24282428

2429+
static int neigh_valid_dump_req(const struct nlmsghdr *nlh,
2430+
bool strict_check,
2431+
struct neigh_dump_filter *filter,
2432+
struct netlink_ext_ack *extack)
2433+
{
2434+
struct nlattr *tb[NDA_MAX + 1];
2435+
int err, i;
2436+
2437+
if (strict_check) {
2438+
struct ndmsg *ndm;
2439+
2440+
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2441+
NL_SET_ERR_MSG(extack, "Invalid header for neighbor dump request");
2442+
return -EINVAL;
2443+
}
2444+
2445+
ndm = nlmsg_data(nlh);
2446+
if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_ifindex ||
2447+
ndm->ndm_state || ndm->ndm_flags || ndm->ndm_type) {
2448+
NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor dump request");
2449+
return -EINVAL;
2450+
}
2451+
2452+
err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
2453+
NULL, extack);
2454+
} else {
2455+
err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
2456+
NULL, extack);
2457+
}
2458+
if (err < 0)
2459+
return err;
2460+
2461+
for (i = 0; i <= NDA_MAX; ++i) {
2462+
if (!tb[i])
2463+
continue;
2464+
2465+
/* all new attributes should require strict_check */
2466+
switch (i) {
2467+
case NDA_IFINDEX:
2468+
if (nla_len(tb[i]) != sizeof(u32)) {
2469+
NL_SET_ERR_MSG(extack, "Invalid IFINDEX attribute in neighbor dump request");
2470+
return -EINVAL;
2471+
}
2472+
filter->dev_idx = nla_get_u32(tb[i]);
2473+
break;
2474+
case NDA_MASTER:
2475+
if (nla_len(tb[i]) != sizeof(u32)) {
2476+
NL_SET_ERR_MSG(extack, "Invalid MASTER attribute in neighbor dump request");
2477+
return -EINVAL;
2478+
}
2479+
filter->master_idx = nla_get_u32(tb[i]);
2480+
break;
2481+
default:
2482+
if (strict_check) {
2483+
NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor dump request");
2484+
return -EINVAL;
2485+
}
2486+
}
2487+
}
2488+
2489+
return 0;
2490+
}
2491+
24292492
static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
24302493
{
24312494
const struct nlmsghdr *nlh = cb->nlh;
24322495
struct neigh_dump_filter filter = {};
2433-
struct nlattr *tb[NDA_MAX + 1];
24342496
struct neigh_table *tbl;
24352497
int t, family, s_t;
24362498
int proxy = 0;
@@ -2445,20 +2507,10 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
24452507
((struct ndmsg *)nlmsg_data(nlh))->ndm_flags == NTF_PROXY)
24462508
proxy = 1;
24472509

2448-
err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL,
2449-
cb->extack);
2450-
if (!err) {
2451-
if (tb[NDA_IFINDEX]) {
2452-
if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32))
2453-
return -EINVAL;
2454-
filter.dev_idx = nla_get_u32(tb[NDA_IFINDEX]);
2455-
}
2456-
if (tb[NDA_MASTER]) {
2457-
if (nla_len(tb[NDA_MASTER]) != sizeof(u32))
2458-
return -EINVAL;
2459-
filter.master_idx = nla_get_u32(tb[NDA_MASTER]);
2460-
}
2461-
}
2510+
err = neigh_valid_dump_req(nlh, cb->strict_check, &filter, cb->extack);
2511+
if (err < 0 && cb->strict_check)
2512+
return err;
2513+
24622514
s_t = cb->args[0];
24632515

24642516
for (t = 0; t < NEIGH_NR_TABLES; t++) {

0 commit comments

Comments
 (0)