diff options
Diffstat (limited to 'net/netlink/attr.c')
-rw-r--r-- | net/netlink/attr.c | 124 |
1 files changed, 114 insertions, 10 deletions
diff --git a/net/netlink/attr.c b/net/netlink/attr.c index dddbd15135a8..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 | } |
@@ -255,6 +284,26 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
255 | } | 284 | } |
256 | 285 | ||
257 | /** | 286 | /** |
287 | * __nla_reserve_nohdr - reserve room for attribute without header | ||
288 | * @skb: socket buffer to reserve room on | ||
289 | * @attrlen: length of attribute payload | ||
290 | * | ||
291 | * Reserves room for attribute payload without a header. | ||
292 | * | ||
293 | * The caller is responsible to ensure that the skb provides enough | ||
294 | * tailroom for the payload. | ||
295 | */ | ||
296 | void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen) | ||
297 | { | ||
298 | void *start; | ||
299 | |||
300 | start = skb_put(skb, NLA_ALIGN(attrlen)); | ||
301 | memset(start, 0, NLA_ALIGN(attrlen)); | ||
302 | |||
303 | return start; | ||
304 | } | ||
305 | |||
306 | /** | ||
258 | * nla_reserve - reserve room for attribute on the skb | 307 | * nla_reserve - reserve room for attribute on the skb |
259 | * @skb: socket buffer to reserve room on | 308 | * @skb: socket buffer to reserve room on |
260 | * @attrtype: attribute type | 309 | * @attrtype: attribute type |
@@ -275,6 +324,24 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
275 | } | 324 | } |
276 | 325 | ||
277 | /** | 326 | /** |
327 | * nla_reserve - reserve room for attribute without header | ||
328 | * @skb: socket buffer to reserve room on | ||
329 | * @len: length of attribute payload | ||
330 | * | ||
331 | * Reserves room for attribute payload without a header. | ||
332 | * | ||
333 | * Returns NULL if the tailroom of the skb is insufficient to store | ||
334 | * the attribute payload. | ||
335 | */ | ||
336 | void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen) | ||
337 | { | ||
338 | if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) | ||
339 | return NULL; | ||
340 | |||
341 | return __nla_reserve_nohdr(skb, attrlen); | ||
342 | } | ||
343 | |||
344 | /** | ||
278 | * __nla_put - Add a netlink attribute to a socket buffer | 345 | * __nla_put - Add a netlink attribute to a socket buffer |
279 | * @skb: socket buffer to add attribute to | 346 | * @skb: socket buffer to add attribute to |
280 | * @attrtype: attribute type | 347 | * @attrtype: attribute type |
@@ -293,6 +360,22 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, | |||
293 | memcpy(nla_data(nla), data, attrlen); | 360 | memcpy(nla_data(nla), data, attrlen); |
294 | } | 361 | } |
295 | 362 | ||
363 | /** | ||
364 | * __nla_put_nohdr - Add a netlink attribute without header | ||
365 | * @skb: socket buffer to add attribute to | ||
366 | * @attrlen: length of attribute payload | ||
367 | * @data: head of attribute payload | ||
368 | * | ||
369 | * The caller is responsible to ensure that the skb provides enough | ||
370 | * tailroom for the attribute payload. | ||
371 | */ | ||
372 | void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) | ||
373 | { | ||
374 | void *start; | ||
375 | |||
376 | start = __nla_reserve_nohdr(skb, attrlen); | ||
377 | memcpy(start, data, attrlen); | ||
378 | } | ||
296 | 379 | ||
297 | /** | 380 | /** |
298 | * nla_put - Add a netlink attribute to a socket buffer | 381 | * nla_put - Add a netlink attribute to a socket buffer |
@@ -313,15 +396,36 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | |||
313 | return 0; | 396 | return 0; |
314 | } | 397 | } |
315 | 398 | ||
399 | /** | ||
400 | * nla_put_nohdr - Add a netlink attribute without header | ||
401 | * @skb: socket buffer to add attribute to | ||
402 | * @attrlen: length of attribute payload | ||
403 | * @data: head of attribute payload | ||
404 | * | ||
405 | * Returns -1 if the tailroom of the skb is insufficient to store | ||
406 | * the attribute payload. | ||
407 | */ | ||
408 | int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) | ||
409 | { | ||
410 | if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) | ||
411 | return -1; | ||
412 | |||
413 | __nla_put_nohdr(skb, attrlen, data); | ||
414 | return 0; | ||
415 | } | ||
316 | 416 | ||
317 | EXPORT_SYMBOL(nla_validate); | 417 | EXPORT_SYMBOL(nla_validate); |
318 | EXPORT_SYMBOL(nla_parse); | 418 | EXPORT_SYMBOL(nla_parse); |
319 | EXPORT_SYMBOL(nla_find); | 419 | EXPORT_SYMBOL(nla_find); |
320 | EXPORT_SYMBOL(nla_strlcpy); | 420 | EXPORT_SYMBOL(nla_strlcpy); |
321 | EXPORT_SYMBOL(__nla_reserve); | 421 | EXPORT_SYMBOL(__nla_reserve); |
422 | EXPORT_SYMBOL(__nla_reserve_nohdr); | ||
322 | EXPORT_SYMBOL(nla_reserve); | 423 | EXPORT_SYMBOL(nla_reserve); |
424 | EXPORT_SYMBOL(nla_reserve_nohdr); | ||
323 | EXPORT_SYMBOL(__nla_put); | 425 | EXPORT_SYMBOL(__nla_put); |
426 | EXPORT_SYMBOL(__nla_put_nohdr); | ||
324 | EXPORT_SYMBOL(nla_put); | 427 | EXPORT_SYMBOL(nla_put); |
428 | EXPORT_SYMBOL(nla_put_nohdr); | ||
325 | EXPORT_SYMBOL(nla_memcpy); | 429 | EXPORT_SYMBOL(nla_memcpy); |
326 | EXPORT_SYMBOL(nla_memcmp); | 430 | EXPORT_SYMBOL(nla_memcmp); |
327 | EXPORT_SYMBOL(nla_strcmp); | 431 | EXPORT_SYMBOL(nla_strcmp); |