Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/xfrm/compat: Copy xfrm_spdattr_type_t atributes

The attribute-translator has to take in mind maxtype, that is
xfrm_link::nla_max. When it is set, attributes are not of xfrm_attr_type_t.
Currently, they can be only XFRMA_SPD_MAX (message XFRM_MSG_NEWSPDINFO),
their UABI is the same for 64/32-bit, so just copy them.

Thanks to YueHaibing for reporting this:
In xfrm_user_rcv_msg_compat() if maxtype is not zero and less than
XFRMA_MAX, nlmsg_parse_deprecated() do not initialize attrs array fully.
xfrm_xlate32() will access uninit 'attrs[i]' while iterating all attrs
array.

KASAN: probably user-memory-access in range [0x0000000041b58ab0-0x0000000041b58ab7]
CPU: 0 PID: 15799 Comm: syz-executor.2 Tainted: G W 5.14.0-rc1-syzkaller #0
RIP: 0010:nla_type include/net/netlink.h:1130 [inline]
RIP: 0010:xfrm_xlate32_attr net/xfrm/xfrm_compat.c:410 [inline]
RIP: 0010:xfrm_xlate32 net/xfrm/xfrm_compat.c:532 [inline]
RIP: 0010:xfrm_user_rcv_msg_compat+0x5e5/0x1070 net/xfrm/xfrm_compat.c:577
[...]
Call Trace:
xfrm_user_rcv_msg+0x556/0x8b0 net/xfrm/xfrm_user.c:2774
netlink_rcv_skb+0x153/0x420 net/netlink/af_netlink.c:2504
xfrm_netlink_rcv+0x6b/0x90 net/xfrm/xfrm_user.c:2824
netlink_unicast_kernel net/netlink/af_netlink.c:1314 [inline]
netlink_unicast+0x533/0x7d0 net/netlink/af_netlink.c:1340
netlink_sendmsg+0x86d/0xdb0 net/netlink/af_netlink.c:1929
sock_sendmsg_nosec net/socket.c:702 [inline]

Fixes: 5106f4a8acff ("xfrm/compat: Add 32=>64-bit messages translator")
Cc: <stable@kernel.org>
Reported-by: YueHaibing <yuehaibing@huawei.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>

authored by

Dmitry Safonov and committed by
Steffen Klassert
4e950506 2580d3f4

+44 -5
+44 -5
net/xfrm/xfrm_compat.c
··· 298 298 len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]); 299 299 300 300 nla_for_each_attr(nla, attrs, len, remaining) { 301 - int err = xfrm_xlate64_attr(dst, nla); 301 + int err; 302 302 303 + switch (type) { 304 + case XFRM_MSG_NEWSPDINFO: 305 + err = xfrm_nla_cpy(dst, nla, nla_len(nla)); 306 + break; 307 + default: 308 + err = xfrm_xlate64_attr(dst, nla); 309 + break; 310 + } 303 311 if (err) 304 312 return err; 305 313 } ··· 349 341 350 342 /* Calculates len of translated 64-bit message. */ 351 343 static size_t xfrm_user_rcv_calculate_len64(const struct nlmsghdr *src, 352 - struct nlattr *attrs[XFRMA_MAX+1]) 344 + struct nlattr *attrs[XFRMA_MAX + 1], 345 + int maxtype) 353 346 { 354 347 size_t len = nlmsg_len(src); 355 348 ··· 367 358 case XFRM_MSG_POLEXPIRE: 368 359 len += 8; 369 360 break; 361 + case XFRM_MSG_NEWSPDINFO: 362 + /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */ 363 + return len; 370 364 default: 371 365 break; 372 366 } 367 + 368 + /* Unexpected for anything, but XFRM_MSG_NEWSPDINFO, please 369 + * correct both 64=>32-bit and 32=>64-bit translators to copy 370 + * new attributes. 371 + */ 372 + if (WARN_ON_ONCE(maxtype)) 373 + return len; 373 374 374 375 if (attrs[XFRMA_SA]) 375 376 len += 4; ··· 459 440 460 441 static int xfrm_xlate32(struct nlmsghdr *dst, const struct nlmsghdr *src, 461 442 struct nlattr *attrs[XFRMA_MAX+1], 462 - size_t size, u8 type, struct netlink_ext_ack *extack) 443 + size_t size, u8 type, int maxtype, 444 + struct netlink_ext_ack *extack) 463 445 { 464 446 size_t pos; 465 447 int i; ··· 540 520 } 541 521 pos = dst->nlmsg_len; 542 522 523 + if (maxtype) { 524 + /* attirbutes are xfrm_spdattr_type_t, not xfrm_attr_type_t */ 525 + WARN_ON_ONCE(src->nlmsg_type != XFRM_MSG_NEWSPDINFO); 526 + 527 + for (i = 1; i <= maxtype; i++) { 528 + int err; 529 + 530 + if (!attrs[i]) 531 + continue; 532 + 533 + /* just copy - no need for translation */ 534 + err = xfrm_attr_cpy32(dst, &pos, attrs[i], size, 535 + nla_len(attrs[i]), nla_len(attrs[i])); 536 + if (err) 537 + return err; 538 + } 539 + return 0; 540 + } 541 + 543 542 for (i = 1; i < XFRMA_MAX + 1; i++) { 544 543 int err; 545 544 ··· 603 564 if (err < 0) 604 565 return ERR_PTR(err); 605 566 606 - len = xfrm_user_rcv_calculate_len64(h32, attrs); 567 + len = xfrm_user_rcv_calculate_len64(h32, attrs, maxtype); 607 568 /* The message doesn't need translation */ 608 569 if (len == nlmsg_len(h32)) 609 570 return NULL; ··· 613 574 if (!h64) 614 575 return ERR_PTR(-ENOMEM); 615 576 616 - err = xfrm_xlate32(h64, h32, attrs, len, type, extack); 577 + err = xfrm_xlate32(h64, h32, attrs, len, type, maxtype, extack); 617 578 if (err < 0) { 618 579 kvfree(h64); 619 580 return ERR_PTR(err);