diff options
Diffstat (limited to 'net/netlink/attr.c')
| -rw-r--r-- | net/netlink/attr.c | 125 |
1 files changed, 114 insertions, 11 deletions
diff --git a/net/netlink/attr.c b/net/netlink/attr.c index fffef4ab276f..004139557e09 100644 --- a/net/netlink/attr.c +++ b/net/netlink/attr.c | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | 5 | * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/config.h> | ||
| 9 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 10 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
| 11 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
| @@ -21,7 +20,6 @@ static u16 nla_attr_minlen[NLA_TYPE_MAX+1] __read_mostly = { | |||
| 21 | [NLA_U16] = sizeof(u16), | 20 | [NLA_U16] = sizeof(u16), |
| 22 | [NLA_U32] = sizeof(u32), | 21 | [NLA_U32] = sizeof(u32), |
| 23 | [NLA_U64] = sizeof(u64), | 22 | [NLA_U64] = sizeof(u64), |
| 24 | [NLA_STRING] = 1, | ||
| 25 | [NLA_NESTED] = NLA_HDRLEN, | 23 | [NLA_NESTED] = NLA_HDRLEN, |
| 26 | }; | 24 | }; |
| 27 | 25 | ||
| @@ -29,7 +27,7 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
| 29 | struct nla_policy *policy) | 27 | struct nla_policy *policy) |
| 30 | { | 28 | { |
| 31 | struct nla_policy *pt; | 29 | struct nla_policy *pt; |
| 32 | int minlen = 0; | 30 | int minlen = 0, attrlen = nla_len(nla); |
| 33 | 31 | ||
| 34 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) | 32 | if (nla->nla_type <= 0 || nla->nla_type > maxtype) |
| 35 | return 0; | 33 | return 0; |
| @@ -38,16 +36,46 @@ static int validate_nla(struct nlattr *nla, int maxtype, | |||
| 38 | 36 | ||
| 39 | BUG_ON(pt->type > NLA_TYPE_MAX); | 37 | BUG_ON(pt->type > NLA_TYPE_MAX); |
| 40 | 38 | ||
| 41 | if (pt->minlen) | 39 | switch (pt->type) { |
| 42 | minlen = pt->minlen; | 40 | case NLA_FLAG: |
| 43 | else if (pt->type != NLA_UNSPEC) | 41 | if (attrlen > 0) |
| 44 | minlen = nla_attr_minlen[pt->type]; | 42 | return -ERANGE; |
| 43 | break; | ||
| 45 | 44 | ||
| 46 | if (pt->type == NLA_FLAG && nla_len(nla) > 0) | 45 | case NLA_NUL_STRING: |
| 47 | return -ERANGE; | 46 | if (pt->len) |
| 47 | minlen = min_t(int, attrlen, pt->len + 1); | ||
| 48 | else | ||
| 49 | minlen = attrlen; | ||
| 48 | 50 | ||
| 49 | if (nla_len(nla) < minlen) | 51 | if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) |
| 50 | 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 | } | ||
| 51 | 79 | ||
| 52 | return 0; | 80 | return 0; |
| 53 | } | 81 | } |
| @@ -256,6 +284,26 @@ struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
| 256 | } | 284 | } |
| 257 | 285 | ||
| 258 | /** | 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 | /** | ||
| 259 | * nla_reserve - reserve room for attribute on the skb | 307 | * nla_reserve - reserve room for attribute on the skb |
| 260 | * @skb: socket buffer to reserve room on | 308 | * @skb: socket buffer to reserve room on |
| 261 | * @attrtype: attribute type | 309 | * @attrtype: attribute type |
| @@ -276,6 +324,24 @@ struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) | |||
| 276 | } | 324 | } |
| 277 | 325 | ||
| 278 | /** | 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 | /** | ||
| 279 | * __nla_put - Add a netlink attribute to a socket buffer | 345 | * __nla_put - Add a netlink attribute to a socket buffer |
| 280 | * @skb: socket buffer to add attribute to | 346 | * @skb: socket buffer to add attribute to |
| 281 | * @attrtype: attribute type | 347 | * @attrtype: attribute type |
| @@ -294,6 +360,22 @@ void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, | |||
| 294 | memcpy(nla_data(nla), data, attrlen); | 360 | memcpy(nla_data(nla), data, attrlen); |
| 295 | } | 361 | } |
| 296 | 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 | } | ||
| 297 | 379 | ||
| 298 | /** | 380 | /** |
| 299 | * nla_put - Add a netlink attribute to a socket buffer | 381 | * nla_put - Add a netlink attribute to a socket buffer |
| @@ -314,15 +396,36 @@ int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) | |||
| 314 | return 0; | 396 | return 0; |
| 315 | } | 397 | } |
| 316 | 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 | } | ||
| 317 | 416 | ||
| 318 | EXPORT_SYMBOL(nla_validate); | 417 | EXPORT_SYMBOL(nla_validate); |
| 319 | EXPORT_SYMBOL(nla_parse); | 418 | EXPORT_SYMBOL(nla_parse); |
| 320 | EXPORT_SYMBOL(nla_find); | 419 | EXPORT_SYMBOL(nla_find); |
| 321 | EXPORT_SYMBOL(nla_strlcpy); | 420 | EXPORT_SYMBOL(nla_strlcpy); |
| 322 | EXPORT_SYMBOL(__nla_reserve); | 421 | EXPORT_SYMBOL(__nla_reserve); |
| 422 | EXPORT_SYMBOL(__nla_reserve_nohdr); | ||
| 323 | EXPORT_SYMBOL(nla_reserve); | 423 | EXPORT_SYMBOL(nla_reserve); |
| 424 | EXPORT_SYMBOL(nla_reserve_nohdr); | ||
| 324 | EXPORT_SYMBOL(__nla_put); | 425 | EXPORT_SYMBOL(__nla_put); |
| 426 | EXPORT_SYMBOL(__nla_put_nohdr); | ||
| 325 | EXPORT_SYMBOL(nla_put); | 427 | EXPORT_SYMBOL(nla_put); |
| 428 | EXPORT_SYMBOL(nla_put_nohdr); | ||
| 326 | EXPORT_SYMBOL(nla_memcpy); | 429 | EXPORT_SYMBOL(nla_memcpy); |
| 327 | EXPORT_SYMBOL(nla_memcmp); | 430 | EXPORT_SYMBOL(nla_memcmp); |
| 328 | EXPORT_SYMBOL(nla_strcmp); | 431 | EXPORT_SYMBOL(nla_strcmp); |
