Skip to content

Commit 7690aa1

Browse files
jmberg-inteldavem330
authored andcommitted
netlink: limit recursion depth in policy validation
Now that we have nested policies, we can theoretically recurse forever parsing attributes if a (sub-)policy refers back to a higher level one. This is a situation that has happened in nl80211, and we've avoided it there by not linking it. Add some code to netlink parsing to limit recursion depth. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 47a1494 commit 7690aa1

File tree

1 file changed

+34
-12
lines changed

1 file changed

+34
-12
lines changed

Diff for: lib/nlattr.c

+34-12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ static const u8 nla_attr_minlen[NLA_TYPE_MAX+1] = {
4444
[NLA_S64] = sizeof(s64),
4545
};
4646

47+
/*
48+
* Nested policies might refer back to the original
49+
* policy in some cases, and userspace could try to
50+
* abuse that and recurse by nesting in the right
51+
* ways. Limit recursion to avoid this problem.
52+
*/
53+
#define MAX_POLICY_RECURSION_DEPTH 10
54+
55+
static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
56+
const struct nla_policy *policy,
57+
unsigned int validate,
58+
struct netlink_ext_ack *extack,
59+
struct nlattr **tb, unsigned int depth);
60+
4761
static int validate_nla_bitfield32(const struct nlattr *nla,
4862
const u32 valid_flags_mask)
4963
{
@@ -70,7 +84,7 @@ static int validate_nla_bitfield32(const struct nlattr *nla,
7084
static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
7185
const struct nla_policy *policy,
7286
struct netlink_ext_ack *extack,
73-
unsigned int validate)
87+
unsigned int validate, unsigned int depth)
7488
{
7589
const struct nlattr *entry;
7690
int rem;
@@ -87,8 +101,9 @@ static int nla_validate_array(const struct nlattr *head, int len, int maxtype,
87101
return -ERANGE;
88102
}
89103

90-
ret = __nla_validate(nla_data(entry), nla_len(entry),
91-
maxtype, policy, validate, extack);
104+
ret = __nla_validate_parse(nla_data(entry), nla_len(entry),
105+
maxtype, policy, validate, extack,
106+
NULL, depth + 1);
92107
if (ret < 0)
93108
return ret;
94109
}
@@ -156,7 +171,7 @@ static int nla_validate_int_range(const struct nla_policy *pt,
156171

157172
static int validate_nla(const struct nlattr *nla, int maxtype,
158173
const struct nla_policy *policy, unsigned int validate,
159-
struct netlink_ext_ack *extack)
174+
struct netlink_ext_ack *extack, unsigned int depth)
160175
{
161176
u16 strict_start_type = policy[0].strict_start_type;
162177
const struct nla_policy *pt;
@@ -269,9 +284,10 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
269284
if (attrlen < NLA_HDRLEN)
270285
goto out_err;
271286
if (pt->nested_policy) {
272-
err = __nla_validate(nla_data(nla), nla_len(nla), pt->len,
273-
pt->nested_policy, validate,
274-
extack);
287+
err = __nla_validate_parse(nla_data(nla), nla_len(nla),
288+
pt->len, pt->nested_policy,
289+
validate, extack, NULL,
290+
depth + 1);
275291
if (err < 0) {
276292
/*
277293
* return directly to preserve the inner
@@ -294,7 +310,7 @@ static int validate_nla(const struct nlattr *nla, int maxtype,
294310

295311
err = nla_validate_array(nla_data(nla), nla_len(nla),
296312
pt->len, pt->nested_policy,
297-
extack, validate);
313+
extack, validate, depth);
298314
if (err < 0) {
299315
/*
300316
* return directly to preserve the inner
@@ -358,11 +374,17 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
358374
const struct nla_policy *policy,
359375
unsigned int validate,
360376
struct netlink_ext_ack *extack,
361-
struct nlattr **tb)
377+
struct nlattr **tb, unsigned int depth)
362378
{
363379
const struct nlattr *nla;
364380
int rem;
365381

382+
if (depth >= MAX_POLICY_RECURSION_DEPTH) {
383+
NL_SET_ERR_MSG(extack,
384+
"allowed policy recursion depth exceeded");
385+
return -EINVAL;
386+
}
387+
366388
if (tb)
367389
memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1));
368390

@@ -379,7 +401,7 @@ static int __nla_validate_parse(const struct nlattr *head, int len, int maxtype,
379401
}
380402
if (policy) {
381403
int err = validate_nla(nla, maxtype, policy,
382-
validate, extack);
404+
validate, extack, depth);
383405

384406
if (err < 0)
385407
return err;
@@ -421,7 +443,7 @@ int __nla_validate(const struct nlattr *head, int len, int maxtype,
421443
struct netlink_ext_ack *extack)
422444
{
423445
return __nla_validate_parse(head, len, maxtype, policy, validate,
424-
extack, NULL);
446+
extack, NULL, 0);
425447
}
426448
EXPORT_SYMBOL(__nla_validate);
427449

@@ -476,7 +498,7 @@ int __nla_parse(struct nlattr **tb, int maxtype,
476498
struct netlink_ext_ack *extack)
477499
{
478500
return __nla_validate_parse(head, len, maxtype, policy, validate,
479-
extack, tb);
501+
extack, tb, 0);
480502
}
481503
EXPORT_SYMBOL(__nla_parse);
482504

0 commit comments

Comments
 (0)