| .. | .. |
|---|
| 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 | |
|---|