netlink: Add strict version of nlmsg_parse and nla_parse
nla_parse is currently lenient on message parsing, allowing type to be 0 or greater than max expected and only logging a message "netlink: %d bytes leftover after parsing attributes in process `%s'." if the netlink message has unknown data at the end after parsing. What this could mean is that the header at the front of the attributes is actually wrong and the parsing is shifted from what is expected. Add a new strict version that actually fails with EINVAL if there are any bytes remaining after the parsing loop completes, if the atttrbitue type is 0 or greater than max expected. Signed-off-by: David Ahern <dsahern@gmail.com> Acked-by: Christian Brauner <christian@brauner.io> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committad av
David S. Miller

förälder
dac9c9790e
incheckning
a5f6cba291
50
lib/nlattr.c
50
lib/nlattr.c
@@ -391,9 +391,10 @@ EXPORT_SYMBOL(nla_policy_len);
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
|
||||
int len, const struct nla_policy *policy,
|
||||
struct netlink_ext_ack *extack)
|
||||
static int __nla_parse(struct nlattr **tb, int maxtype,
|
||||
const struct nlattr *head, int len,
|
||||
bool strict, const struct nla_policy *policy,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const struct nlattr *nla;
|
||||
int rem;
|
||||
@@ -403,27 +404,50 @@ int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
|
||||
nla_for_each_attr(nla, head, len, rem) {
|
||||
u16 type = nla_type(nla);
|
||||
|
||||
if (type > 0 && type <= maxtype) {
|
||||
if (policy) {
|
||||
int err = validate_nla(nla, maxtype, policy,
|
||||
extack);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (type == 0 || type > maxtype) {
|
||||
if (strict) {
|
||||
NL_SET_ERR_MSG(extack, "Unknown attribute type");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tb[type] = (struct nlattr *)nla;
|
||||
continue;
|
||||
}
|
||||
if (policy) {
|
||||
int err = validate_nla(nla, maxtype, policy, extack);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
tb[type] = (struct nlattr *)nla;
|
||||
}
|
||||
|
||||
if (unlikely(rem > 0))
|
||||
if (unlikely(rem > 0)) {
|
||||
pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n",
|
||||
rem, current->comm);
|
||||
NL_SET_ERR_MSG(extack, "bytes leftover after parsing attributes");
|
||||
if (strict)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head,
|
||||
int len, const struct nla_policy *policy,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return __nla_parse(tb, maxtype, head, len, false, policy, extack);
|
||||
}
|
||||
EXPORT_SYMBOL(nla_parse);
|
||||
|
||||
int nla_parse_strict(struct nlattr **tb, int maxtype, const struct nlattr *head,
|
||||
int len, const struct nla_policy *policy,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
return __nla_parse(tb, maxtype, head, len, true, policy, extack);
|
||||
}
|
||||
EXPORT_SYMBOL(nla_parse_strict);
|
||||
|
||||
/**
|
||||
* nla_find - Find a specific attribute in a stream of attributes
|
||||
* @head: head of attribute stream
|
||||
|
Referens i nytt ärende
Block a user