Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5531a5d authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller
Browse files

[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: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e3b4eadb
Loading
Loading
Loading
Loading
+11 −4
Original line number Diff line number Diff line
@@ -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;
};

/**
+39 −10
Original line number Diff line number Diff line
@@ -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;

	case NLA_NUL_STRING:
		if (pt->len)
			minlen = min_t(int, attrlen, pt->len + 1);
		else
			minlen = attrlen;

		if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL)
			return -EINVAL;
		/* fall through */

	case NLA_STRING:
		if (attrlen < 1)
			return -ERANGE;

	if (pt->type == NLA_FLAG && nla_len(nla) > 0)
		if (pt->len) {
			char *buf = nla_data(nla);

			if (buf[attrlen - 1] == '\0')
				attrlen--;

			if (attrlen > pt->len)
				return -ERANGE;
		}
		break;

	if (nla_len(nla) < minlen)
	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;
}