From: Johannes Berg <johannes.berg@intel.com>
Date: Wed, 26 Sep 2018 11:15:32 +0200
Subject: [PATCH] netlink: move extack setting into validate_nla()
Patch-mainline: v4.20-rc1
Git-commit: c29f1845b2b22974411278bad3a2ac0b7815dfb4
References: bsc#1152107 CVE-2019-16746
This unifies the code between nla_parse() which sets the bad
attribute pointer and an error message, and nla_validate()
which only sets the bad attribute pointer.
It also cleans up the code for NLA_REJECT and paves the way
for nested policy validation, as it will allow us to easily
skip setting the "generic" message without any extra args
like the **error_msg now, just passing the extack through is
now enough.
While at it, remove the unnecessary label in nla_parse().
Suggested-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Cho, Yu-Chen <acho@suse.com>
---
lib/nlattr.c | 66 +++++++++++++++++++++++++++++++----------------------------
1 file changed, 35 insertions(+), 31 deletions(-)
--- a/lib/nlattr.c
+++ b/lib/nlattr.c
@@ -53,10 +53,11 @@ static int validate_nla_bitfield32(const
static int validate_nla(const struct nlattr *nla, int maxtype,
const struct nla_policy *policy,
- const char **error_msg)
+ struct netlink_ext_ack *extack)
{
const struct nla_policy *pt;
int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla);
+ int err = -ERANGE;
if (type <= 0 || type > maxtype)
return 0;
@@ -67,20 +68,27 @@ static int validate_nla(const struct nla
switch (pt->type) {
case NLA_REJECT:
- if (pt->validation_data && error_msg)
- *error_msg = pt->validation_data;
- return -EINVAL;
+ if (extack && pt->validation_data) {
+ NL_SET_BAD_ATTR(extack, nla);
+ extack->_msg = pt->validation_data;
+ return -EINVAL;
+ }
+ err = -EINVAL;
+ goto out_err;
case NLA_FLAG:
if (attrlen > 0)
- return -ERANGE;
+ goto out_err;
break;
case NLA_BITFIELD32:
if (attrlen != sizeof(struct nla_bitfield32))
- return -ERANGE;
+ goto out_err;
- return validate_nla_bitfield32(nla, pt->validation_data);
+ err = validate_nla_bitfield32(nla, pt->validation_data);
+ if (err)
+ goto out_err;
+ break;
case NLA_NUL_STRING:
if (pt->len)
@@ -88,13 +96,15 @@ static int validate_nla(const struct nla
else
minlen = attrlen;
- if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
- return -EINVAL;
+ if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) {
+ err = -EINVAL;
+ goto out_err;
+ }
/* fall through */
case NLA_STRING:
if (attrlen < 1)
- return -ERANGE;
+ goto out_err;
if (pt->len) {
char *buf = nla_data(nla);
@@ -103,13 +113,13 @@ static int validate_nla(const struct nla
attrlen--;
if (attrlen > pt->len)
- return -ERANGE;
+ goto out_err;
}
break;
case NLA_BINARY:
if (pt->len && attrlen > pt->len)
- return -ERANGE;
+ goto out_err;
break;
case NLA_NESTED_COMPAT:
@@ -136,10 +146,13 @@ static int validate_nla(const struct nla
minlen = nla_attr_minlen[pt->type];
if (attrlen < minlen)
- return -ERANGE;
+ goto out_err;
}
return 0;
+out_err:
+ NL_SET_ERR_MSG_ATTR(extack, nla, "Attribute failed policy validation");
+ return err;
}
/**
@@ -164,12 +177,10 @@ int nla_validate(const struct nlattr *he
int rem;
nla_for_each_attr(nla, head, len, rem) {
- int err = validate_nla(nla, maxtype, policy, NULL);
+ int err = validate_nla(nla, maxtype, policy, extack);
- if (err < 0) {
- NL_SET_BAD_ATTR(extack, nla);
+ if (err < 0)
return err;
- }
}
return 0;
@@ -223,7 +234,7 @@ int nla_parse(struct nlattr **tb, int ma
struct netlink_ext_ack *extack)
{
const struct nlattr *nla;
- int rem, err;
+ int rem;
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
@@ -231,17 +242,12 @@ int nla_parse(struct nlattr **tb, int ma
u16 type = nla_type(nla);
if (type > 0 && type <= maxtype) {
- static const char _msg[] = "Attribute failed policy validation";
- const char *msg = _msg;
-
if (policy) {
- err = validate_nla(nla, maxtype, policy, &msg);
- if (err < 0) {
- NL_SET_BAD_ATTR(extack, nla);
- if (extack)
- extack->_msg = msg;
- goto errout;
- }
+ int err = validate_nla(nla, maxtype, policy,
+ extack);
+
+ if (err < 0)
+ return err;
}
tb[type] = (struct nlattr *)nla;
@@ -252,9 +258,7 @@ int nla_parse(struct nlattr **tb, int ma
pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n",
rem, current->comm);
- err = 0;
-errout:
- return err;
+ return 0;
}
EXPORT_SYMBOL(nla_parse);