diff options
-rw-r--r-- | include/net/netlink.h | 15 | ||||
-rw-r--r-- | net/netlink/attr.c | 49 |
2 files changed, 50 insertions, 14 deletions
diff --git a/include/net/netlink.h b/include/net/netlink.h index bcb27e3a312e..11dc2e7f679a 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h | |||
@@ -167,6 +167,7 @@ enum { | |||
167 | NLA_FLAG, | 167 | NLA_FLAG, |
168 | NLA_MSECS, | 168 | NLA_MSECS, |
169 | NLA_NESTED, | 169 | NLA_NESTED, |
170 | NLA_NUL_STRING, | ||
170 | __NLA_TYPE_MAX, | 171 | __NLA_TYPE_MAX, |
171 | }; | 172 | }; |
172 | 173 | ||
@@ -175,21 +176,27 @@ enum { | |||
175 | /** | 176 | /** |
176 | * struct nla_policy - attribute validation policy | 177 | * struct nla_policy - attribute validation policy |
177 | * @type: Type of attribute or NLA_UNSPEC | 178 | * @type: Type of attribute or NLA_UNSPEC |
178 | * @minlen: Minimal length of payload required to be available | 179 | * @len: Type specific length of payload |
179 | * | 180 | * |
180 | * Policies are defined as arrays of this struct, the array must be | 181 | * Policies are defined as arrays of this struct, the array must be |
181 | * accessible by attribute type up to the highest identifier to be expected. | 182 | * accessible by attribute type up to the highest identifier to be expected. |
182 | * | 183 | * |
184 | * Meaning of `len' field: | ||
185 | * NLA_STRING Maximum length of string | ||
186 | * NLA_NUL_STRING Maximum length of string (excluding NUL) | ||
187 | * NLA_FLAG Unused | ||
188 | * All other Exact length of attribute payload | ||
189 | * | ||
183 | * Example: | 190 | * Example: |
184 | * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = { | 191 | * static struct nla_policy my_policy[ATTR_MAX+1] __read_mostly = { |
185 | * [ATTR_FOO] = { .type = NLA_U16 }, | 192 | * [ATTR_FOO] = { .type = NLA_U16 }, |
186 | * [ATTR_BAR] = { .type = NLA_STRING }, | 193 | * [ATTR_BAR] = { .type = NLA_STRING, len = BARSIZ }, |
187 | * [ATTR_BAZ] = { .minlen = sizeof(struct mystruct) }, | 194 | * [ATTR_BAZ] = { .len = sizeof(struct mystruct) }, |
188 | * }; | 195 | * }; |
189 | */ | 196 | */ |
190 | struct nla_policy { | 197 | struct nla_policy { |
191 | u16 type; | 198 | u16 type; |
192 | u16 minlen; | 199 | u16 len; |
193 | }; | 200 | }; |
194 | 201 | ||
195 | /** | 202 | /** |
diff --git a/net/netlink/attr.c b/net/netlink/attr.c index 136e529e5780..004139557e09 100644 --- a/net/netlink/attr.c +++ b/net/netlink/attr.c | |||
@@ -20,7 +20,6 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { | |||
20 | [NLA_U16] = sizeof(u16), | 20 | [NLA_U16] = sizeof(u16), |
21 | [NLA_U32] = sizeof(u32), | 21 | [NLA_U32] = sizeof(u32), |
22 | [NLA_U64] = sizeof(u64), | 22 | [NLA_U64] = sizeof(u64), |
23 | [NLA_STRING] = 1, | ||
24 | [NLA_NESTED] = NLA_HDRLEN, | 23 | [NLA_NESTED] = NLA_HDRLEN, |
25 | }; | 24 | }; |
26 | 25 | ||
@@ -28,7 +27,7 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
28 | struct nla_policy *policy) | 27 | struct nla_policy *policy) |
29 | { | 28 | { |
30 | struct nla_policy *pt; | 29 | struct nla_policy *pt; |
31 | int minlen = 0; | 30 | int minlen = 0, attrlen = nla_len(nla); |
32 | 31 | ||
33 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) | 32 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) |
34 | return 0; | 33 | return 0; |
@@ -37,16 +36,46 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
37 | 36 | ||
38 | BUG_ON(pt->type > NLA_TYPE_MAX); | 37 | BUG_ON(pt->type > NLA_TYPE_MAX); |
39 | 38 | ||
40 | if (pt->minlen) | 39 | switch (pt->type) { |
41 | minlen = pt->minlen; | 40 | case NLA_FLAG: |
42 | else if (pt->type != NLA_UNSPEC) | 41 | if (attrlen > 0) |
43 | minlen = nla_attr_minlen[pt->type]; | 42 | return -ERANGE; |
43 | break; | ||
44 | 44 | ||
45 | if (pt->type == NLA_FLAG && nla_len(nla) > 0) | 45 | case NLA_NUL_STRING: |
46 | return -ERANGE; | 46 | if (pt->len) |
47 | minlen = min_t(int, attrlen, pt->len + 1); | ||
48 | else | ||
49 | minlen = attrlen; | ||
47 | 50 | ||
48 | if (nla_len(nla) < minlen) | 51 | if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) |
49 | return -ERANGE; | 52 | return -EINVAL; |
53 | /* fall through */ | ||
54 | |||
55 | case NLA_STRING: | ||
56 | if (attrlen < 1) | ||
57 | return -ERANGE; | ||
58 | |||
59 | if (pt->len) { | ||
60 | char *buf = nla_data(nla); | ||
61 | |||
62 | if (buf[attrlen - 1] == '\0') | ||
63 | attrlen--; | ||
64 | |||
65 | if (attrlen > pt->len) | ||
66 | return -ERANGE; | ||
67 | } | ||
68 | break; | ||
69 | |||
70 | default: | ||
71 | if (pt->len) | ||
72 | minlen = pt->len; | ||
73 | else if (pt->type != NLA_UNSPEC) | ||
74 | minlen = nla_attr_minlen[pt->type]; | ||
75 | |||
76 | if (attrlen < minlen) | ||
77 | return -ERANGE; | ||
78 | } | ||
50 | 79 | ||
51 | return 0; | 80 | return 0; |
52 | } | 81 | } |