.. | .. |
---|
5 | 5 | * Based on code and translator idea by: Florian Westphal <fw@strlen.de> |
---|
6 | 6 | */ |
---|
7 | 7 | #include <linux/compat.h> |
---|
| 8 | +#include <linux/nospec.h> |
---|
8 | 9 | #include <linux/xfrm.h> |
---|
9 | 10 | #include <net/xfrm.h> |
---|
10 | 11 | |
---|
.. | .. |
---|
107 | 108 | [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, |
---|
108 | 109 | [XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) }, |
---|
109 | 110 | [XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) }, |
---|
110 | | - [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) }, |
---|
| 111 | + [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_user_sec_ctx) }, |
---|
111 | 112 | [XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) }, |
---|
112 | 113 | [XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) }, |
---|
113 | 114 | [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 }, |
---|
.. | .. |
---|
216 | 217 | case XFRM_MSG_GETSADINFO: |
---|
217 | 218 | case XFRM_MSG_GETSPDINFO: |
---|
218 | 219 | default: |
---|
219 | | - WARN_ONCE(1, "unsupported nlmsg_type %d", nlh_src->nlmsg_type); |
---|
| 220 | + pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type); |
---|
220 | 221 | return ERR_PTR(-EOPNOTSUPP); |
---|
221 | 222 | } |
---|
222 | 223 | |
---|
.. | .. |
---|
234 | 235 | case XFRMA_PAD: |
---|
235 | 236 | /* Ignore */ |
---|
236 | 237 | return 0; |
---|
| 238 | + case XFRMA_UNSPEC: |
---|
237 | 239 | case XFRMA_ALG_AUTH: |
---|
238 | 240 | case XFRMA_ALG_CRYPT: |
---|
239 | 241 | case XFRMA_ALG_COMP: |
---|
.. | .. |
---|
276 | 278 | return xfrm_nla_cpy(dst, src, nla_len(src)); |
---|
277 | 279 | default: |
---|
278 | 280 | BUILD_BUG_ON(XFRMA_MAX != XFRMA_IF_ID); |
---|
279 | | - WARN_ONCE(1, "unsupported nla_type %d", src->nla_type); |
---|
| 281 | + pr_warn_once("unsupported nla_type %d\n", src->nla_type); |
---|
280 | 282 | return -EOPNOTSUPP; |
---|
281 | 283 | } |
---|
282 | 284 | } |
---|
.. | .. |
---|
297 | 299 | len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]); |
---|
298 | 300 | |
---|
299 | 301 | nla_for_each_attr(nla, attrs, len, remaining) { |
---|
300 | | - int err = xfrm_xlate64_attr(dst, nla); |
---|
| 302 | + int err; |
---|
301 | 303 | |
---|
| 304 | + switch (nlh_src->nlmsg_type) { |
---|
| 305 | + case XFRM_MSG_NEWSPDINFO: |
---|
| 306 | + err = xfrm_nla_cpy(dst, nla, nla_len(nla)); |
---|
| 307 | + break; |
---|
| 308 | + default: |
---|
| 309 | + err = xfrm_xlate64_attr(dst, nla); |
---|
| 310 | + break; |
---|
| 311 | + } |
---|
302 | 312 | if (err) |
---|
303 | 313 | return err; |
---|
304 | 314 | } |
---|
.. | .. |
---|
314 | 324 | struct sk_buff *new = NULL; |
---|
315 | 325 | int err; |
---|
316 | 326 | |
---|
317 | | - if (WARN_ON_ONCE(type >= ARRAY_SIZE(xfrm_msg_min))) |
---|
| 327 | + if (type >= ARRAY_SIZE(xfrm_msg_min)) { |
---|
| 328 | + pr_warn_once("unsupported nlmsg_type %d\n", nlh_src->nlmsg_type); |
---|
318 | 329 | return -EOPNOTSUPP; |
---|
| 330 | + } |
---|
319 | 331 | |
---|
320 | 332 | if (skb_shinfo(skb)->frag_list == NULL) { |
---|
321 | 333 | new = alloc_skb(skb->len + skb_tailroom(skb), GFP_ATOMIC); |
---|
.. | .. |
---|
338 | 350 | |
---|
339 | 351 | /* Calculates len of translated 64-bit message. */ |
---|
340 | 352 | static size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr *src, |
---|
341 | | - struct nlattr *attrs[XFRMA_MAX+1]) |
---|
| 353 | + struct nlattr *attrs[XFRMA_MAX + 1], |
---|
| 354 | + int maxtype) |
---|
342 | 355 | { |
---|
343 | 356 | size_t len = nlmsg_len(src); |
---|
344 | 357 | |
---|
.. | .. |
---|
355 | 368 | case XFRM_MSG_POLEXPIRE: |
---|
356 | 369 | len += 8; |
---|
357 | 370 | break; |
---|
| 371 | + case XFRM_MSG_NEWSPDINFO: |
---|
| 372 | + /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */ |
---|
| 373 | + return len; |
---|
358 | 374 | default: |
---|
359 | 375 | break; |
---|
360 | 376 | } |
---|
| 377 | + |
---|
| 378 | + /* Unexpected for anything, but XFRM_MSG_NEWSPDINFO, please |
---|
| 379 | + * correct both 64=>32-bit and 32=>64-bit translators to copy |
---|
| 380 | + * new attributes. |
---|
| 381 | + */ |
---|
| 382 | + if (WARN_ON_ONCE(maxtype)) |
---|
| 383 | + return len; |
---|
361 | 384 | |
---|
362 | 385 | if (attrs[XFRMA_SA]) |
---|
363 | 386 | len += 4; |
---|
.. | .. |
---|
377 | 400 | struct nlmsghdr *nlmsg = dst; |
---|
378 | 401 | struct nlattr *nla; |
---|
379 | 402 | |
---|
| 403 | + /* xfrm_user_rcv_msg_compat() relies on fact that 32-bit messages |
---|
| 404 | + * have the same len or shorted than 64-bit ones. |
---|
| 405 | + * 32-bit translation that is bigger than 64-bit original is unexpected. |
---|
| 406 | + */ |
---|
380 | 407 | if (WARN_ON_ONCE(copy_len > payload)) |
---|
381 | 408 | copy_len = payload; |
---|
382 | 409 | |
---|
.. | .. |
---|
387 | 414 | |
---|
388 | 415 | memcpy(nla, src, nla_attr_size(copy_len)); |
---|
389 | 416 | nla->nla_len = nla_attr_size(payload); |
---|
390 | | - *pos += nla_attr_size(payload); |
---|
| 417 | + *pos += nla_attr_size(copy_len); |
---|
391 | 418 | nlmsg->nlmsg_len += nla->nla_len; |
---|
392 | 419 | |
---|
393 | 420 | memset(dst + *pos, 0, payload - copy_len); |
---|
.. | .. |
---|
409 | 436 | NL_SET_ERR_MSG(extack, "Bad attribute"); |
---|
410 | 437 | return -EOPNOTSUPP; |
---|
411 | 438 | } |
---|
| 439 | + type = array_index_nospec(type, XFRMA_MAX + 1); |
---|
412 | 440 | if (nla_len(nla) < compat_policy[type].len) { |
---|
413 | 441 | NL_SET_ERR_MSG(extack, "Attribute bad length"); |
---|
414 | 442 | return -EOPNOTSUPP; |
---|
.. | .. |
---|
433 | 461 | |
---|
434 | 462 | static int xfrm_xlate32(struct nlmsghdr *dst, const struct nlmsghdr *src, |
---|
435 | 463 | struct nlattr *attrs[XFRMA_MAX+1], |
---|
436 | | - size_t size, u8 type, struct netlink_ext_ack *extack) |
---|
| 464 | + size_t size, u8 type, int maxtype, |
---|
| 465 | + struct netlink_ext_ack *extack) |
---|
437 | 466 | { |
---|
438 | 467 | size_t pos; |
---|
439 | 468 | int i; |
---|
.. | .. |
---|
513 | 542 | } |
---|
514 | 543 | pos = dst->nlmsg_len; |
---|
515 | 544 | |
---|
| 545 | + if (maxtype) { |
---|
| 546 | + /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */ |
---|
| 547 | + WARN_ON_ONCE(src->nlmsg_type != XFRM_MSG_NEWSPDINFO); |
---|
| 548 | + |
---|
| 549 | + for (i = 1; i <= maxtype; i++) { |
---|
| 550 | + int err; |
---|
| 551 | + |
---|
| 552 | + if (!attrs[i]) |
---|
| 553 | + continue; |
---|
| 554 | + |
---|
| 555 | + /* just copy - no need for translation */ |
---|
| 556 | + err = xfrm_attr_cpy32(dst, &pos, attrs[i], size, |
---|
| 557 | + nla_len(attrs[i]), nla_len(attrs[i])); |
---|
| 558 | + if (err) |
---|
| 559 | + return err; |
---|
| 560 | + } |
---|
| 561 | + return 0; |
---|
| 562 | + } |
---|
| 563 | + |
---|
516 | 564 | for (i = 1; i < XFRMA_MAX + 1; i++) { |
---|
517 | 565 | int err; |
---|
518 | 566 | |
---|
.. | .. |
---|
552 | 600 | (h32->nlmsg_flags & NLM_F_DUMP)) |
---|
553 | 601 | return NULL; |
---|
554 | 602 | |
---|
555 | | - err = nlmsg_parse(h32, compat_msg_min[type], attrs, |
---|
| 603 | + err = nlmsg_parse_deprecated(h32, compat_msg_min[type], attrs, |
---|
556 | 604 | maxtype ? : XFRMA_MAX, policy ? : compat_policy, extack); |
---|
557 | 605 | if (err < 0) |
---|
558 | 606 | return ERR_PTR(err); |
---|
559 | 607 | |
---|
560 | | - len = xfrm_user_rcv_calculate_len64(h32, attrs); |
---|
| 608 | + len = xfrm_user_rcv_calculate_len64(h32, attrs, maxtype); |
---|
561 | 609 | /* The message doesn't need translation */ |
---|
562 | 610 | if (len == nlmsg_len(h32)) |
---|
563 | 611 | return NULL; |
---|
564 | 612 | |
---|
565 | 613 | len += NLMSG_HDRLEN; |
---|
566 | | - h64 = kvmalloc(len, GFP_KERNEL | __GFP_ZERO); |
---|
| 614 | + h64 = kvmalloc(len, GFP_KERNEL); |
---|
567 | 615 | if (!h64) |
---|
568 | 616 | return ERR_PTR(-ENOMEM); |
---|
569 | 617 | |
---|
570 | | - err = xfrm_xlate32(h64, h32, attrs, len, type, extack); |
---|
| 618 | + err = xfrm_xlate32(h64, h32, attrs, len, type, maxtype, extack); |
---|
571 | 619 | if (err < 0) { |
---|
572 | 620 | kvfree(h64); |
---|
573 | 621 | return ERR_PTR(err); |
---|
.. | .. |
---|
585 | 633 | if (optlen < sizeof(*p)) |
---|
586 | 634 | return -EINVAL; |
---|
587 | 635 | |
---|
588 | | - data64 = kmalloc(optlen + 4, GFP_USER | __GFP_NOWARN); |
---|
| 636 | + data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN); |
---|
589 | 637 | if (!data64) |
---|
590 | 638 | return -ENOMEM; |
---|
591 | 639 | |
---|