[NETLINK]: Improve string attribute validation
Introduces a new attribute type NLA_NUL_STRING to support NUL terminated strings. Attributes of this kind require to carry a terminating NUL within the maximum specified in the policy. The `old' NLA_STRING which is not required to be NUL terminated is extended to provide means to specify a maximum length of the string. Aims at easing the pain with using nla_strlcpy() on temporary buffers. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
e3b4eadbea
commit
a5531a5d85
@ -167,6 +167,7 @@ enum {
|
||||
NLA_FLAG,
|
||||
NLA_MSECS,
|
||||
NLA_NESTED,
|
||||
NLA_NUL_STRING,
|
||||
__NLA_TYPE_MAX,
|
||||
};
|
||||
|
||||
@ -175,21 +176,27 @@ enum {
|
||||
/**
|
||||
* struct nla_policy - attribute validation policy
|
||||
* @type: Type of attribute or NLA_UNSPEC
|
||||
* @minlen: Minimal length of payload required to be available
|
||||
* @len: Type specific length of payload
|
||||
*
|
||||
* Policies are defined as arrays of this struct, the array must be
|
||||
* accessible by attribute type up to the highest identifier to be expected.
|
||||
*
|
||||
* Meaning of `len' field:
|
||||
* NLA_STRING Maximum length of string
|
||||
* NLA_NUL_STRING Maximum length of string (excluding NUL)
|
||||
* NLA_FLAG Unused
|
||||
* All other Exact length of attribute payload
|
||||
*
|
||||
* Example:
|
||||
* static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = {
|
||||
* [ATTR_FOO] = { .type = NLA_U16 },
|
||||
* [ATTR_BAR] = { .type = NLA_STRING },
|
||||
* [ATTR_BAZ] = { .minlen = sizeof(struct mystruct) },
|
||||
* [ATTR_BAR] = { .type = NLA_STRING, len = BARSIZ },
|
||||
* [ATTR_BAZ] = { .len = sizeof(struct mystruct) },
|
||||
* };
|
||||
*/
|
||||
struct nla_policy {
|
||||
u16 type;
|
||||
u16 minlen;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,6 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = {
|
||||
[NLA_U16] = sizeof(u16),
|
||||
[NLA_U32] = sizeof(u32),
|
||||
[NLA_U64] = sizeof(u64),
|
||||
[NLA_STRING] = 1,
|
||||
[NLA_NESTED] = NLA_HDRLEN,
|
||||
};
|
||||
|
||||
@ -28,7 +27,7 @@ static int validate_nla(struct nlattr *nla, int maxtype,
|
||||
struct nla_policy *policy)
|
||||
{
|
||||
struct nla_policy *pt;
|
||||
int minlen = 0;
|
||||
int minlen = 0, attrlen = nla_len(nla);
|
||||
|
||||
if (nla->nla_type <= 0 || nla->nla_type > maxtype)
|
||||
return 0;
|
||||
@ -37,16 +36,46 @@ static int validate_nla(struct nlattr *nla, int maxtype,
|
||||
|
||||
BUG_ON(pt->type > NLA_TYPE_MAX);
|
||||
|
||||
if (pt->minlen)
|
||||
minlen = pt->minlen;
|
||||
else if (pt->type != NLA_UNSPEC)
|
||||
minlen = nla_attr_minlen[pt->type];
|
||||
switch (pt->type) {
|
||||
case NLA_FLAG:
|
||||
if (attrlen > 0)
|
||||
return -ERANGE;
|
||||
break;
|
||||
|
||||
if (pt->type == NLA_FLAG && nla_len(nla) > 0)
|
||||
return -ERANGE;
|
||||
case NLA_NUL_STRING:
|
||||
if (pt->len)
|
||||
minlen = min_t(int, attrlen, pt->len + 1);
|
||||
else
|
||||
minlen = attrlen;
|
||||
|
||||
if (nla_len(nla) < minlen)
|
||||
return -ERANGE;
|
||||
if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
|
||||
return -EINVAL;
|
||||
/* fall through */
|
||||
|
||||
case NLA_STRING:
|
||||
if (attrlen < 1)
|
||||
return -ERANGE;
|
||||
|
||||
if (pt->len) {
|
||||
char *buf = nla_data(nla);
|
||||
|
||||
if (buf[attrlen - 1] == '\0')
|
||||
attrlen--;
|
||||
|
||||
if (attrlen > pt->len)
|
||||
return -ERANGE;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (pt->len)
|
||||
minlen = pt->len;
|
||||
else if (pt->type != NLA_UNSPEC)
|
||||
minlen = nla_attr_minlen[pt->type];
|
||||
|
||||
if (attrlen < minlen)
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user