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

Merge tag 'ipsec-2023-02-08' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec

Steffen Klassert says:

====================
ipsec 2023-02-08

1) Fix policy checks for nested IPsec tunnels when using
xfrm interfaces. From Benedict Wong.

2) Fix netlink message expression on 32=>64-bit
messages translators. From Anastasia Belova.

3) Prevent potential spectre v1 gadget in xfrm_xlate32_attr.
From Eric Dumazet.

4) Always consistently use time64_t in xfrm_timer_handler.
From Eric Dumazet.

5) Fix KCSAN reported bug: Multiple cpus can update use_time
at the same time. From Eric Dumazet.

6) Fix SCP copy from IPv4 to IPv6 on interfamily tunnel.
From Christian Hopps.

* tag 'ipsec-2023-02-08' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec:
xfrm: fix bug with DSCP copy to v6 from v4 tunnel
xfrm: annotate data-race around use_time
xfrm: consistently use time64_t in xfrm_timer_handler()
xfrm/compat: prevent potential spectre v1 gadget in xfrm_xlate32_attr()
xfrm: compat: change expression for switch in xfrm_xlate64
Fix XFRM-I support for nested ESP tunnels
====================

Link: https://lore.kernel.org/r/20230208114322.266510-1-steffen.klassert@secunet.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+73 -20
+3 -1
net/xfrm/xfrm_compat.c
··· 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 ··· 303 302 nla_for_each_attr(nla, attrs, len, remaining) { 304 303 int err; 305 304 306 - switch (type) { 305 + switch (nlh_src->nlmsg_type) { 307 306 case XFRM_MSG_NEWSPDINFO: 308 307 err = xfrm_nla_cpy(dst, nla, nla_len(nla)); 309 308 break; ··· 438 437 NL_SET_ERR_MSG(extack, "Bad attribute"); 439 438 return -EOPNOTSUPP; 440 439 } 440 + type = array_index_nospec(type, XFRMA_MAX + 1); 441 441 if (nla_len(nla) < compat_policy[type].len) { 442 442 NL_SET_ERR_MSG(extack, "Attribute bad length"); 443 443 return -EOPNOTSUPP;
+1 -2
net/xfrm/xfrm_input.c
··· 279 279 goto out; 280 280 281 281 if (x->props.flags & XFRM_STATE_DECAP_DSCP) 282 - ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)), 283 - ipipv6_hdr(skb)); 282 + ipv6_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipipv6_hdr(skb)); 284 283 if (!(x->props.flags & XFRM_STATE_NOECN)) 285 284 ipip6_ecn_decapsulate(skb); 286 285
+50 -4
net/xfrm/xfrm_interface_core.c
··· 310 310 skb->mark = 0; 311 311 } 312 312 313 + static int xfrmi_input(struct sk_buff *skb, int nexthdr, __be32 spi, 314 + int encap_type, unsigned short family) 315 + { 316 + struct sec_path *sp; 317 + 318 + sp = skb_sec_path(skb); 319 + if (sp && (sp->len || sp->olen) && 320 + !xfrm_policy_check(NULL, XFRM_POLICY_IN, skb, family)) 321 + goto discard; 322 + 323 + XFRM_SPI_SKB_CB(skb)->family = family; 324 + if (family == AF_INET) { 325 + XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); 326 + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; 327 + } else { 328 + XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); 329 + XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 330 + } 331 + 332 + return xfrm_input(skb, nexthdr, spi, encap_type); 333 + discard: 334 + kfree_skb(skb); 335 + return 0; 336 + } 337 + 338 + static int xfrmi4_rcv(struct sk_buff *skb) 339 + { 340 + return xfrmi_input(skb, ip_hdr(skb)->protocol, 0, 0, AF_INET); 341 + } 342 + 343 + static int xfrmi6_rcv(struct sk_buff *skb) 344 + { 345 + return xfrmi_input(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], 346 + 0, 0, AF_INET6); 347 + } 348 + 349 + static int xfrmi4_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) 350 + { 351 + return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET); 352 + } 353 + 354 + static int xfrmi6_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) 355 + { 356 + return xfrmi_input(skb, nexthdr, spi, encap_type, AF_INET6); 357 + } 358 + 313 359 static int xfrmi_rcv_cb(struct sk_buff *skb, int err) 314 360 { 315 361 const struct xfrm_mode *inner_mode; ··· 991 945 }; 992 946 993 947 static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = { 994 - .handler = xfrm6_rcv, 995 - .input_handler = xfrm_input, 948 + .handler = xfrmi6_rcv, 949 + .input_handler = xfrmi6_input, 996 950 .cb_handler = xfrmi_rcv_cb, 997 951 .err_handler = xfrmi6_err, 998 952 .priority = 10, ··· 1042 996 #endif 1043 997 1044 998 static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = { 1045 - .handler = xfrm4_rcv, 1046 - .input_handler = xfrm_input, 999 + .handler = xfrmi4_rcv, 1000 + .input_handler = xfrmi4_input, 1047 1001 .cb_handler = xfrmi_rcv_cb, 1048 1002 .err_handler = xfrmi4_err, 1049 1003 .priority = 10,
+10 -4
net/xfrm/xfrm_policy.c
··· 336 336 } 337 337 if (xp->lft.hard_use_expires_seconds) { 338 338 time64_t tmo = xp->lft.hard_use_expires_seconds + 339 - (xp->curlft.use_time ? : xp->curlft.add_time) - now; 339 + (READ_ONCE(xp->curlft.use_time) ? : xp->curlft.add_time) - now; 340 340 if (tmo <= 0) 341 341 goto expired; 342 342 if (tmo < next) ··· 354 354 } 355 355 if (xp->lft.soft_use_expires_seconds) { 356 356 time64_t tmo = xp->lft.soft_use_expires_seconds + 357 - (xp->curlft.use_time ? : xp->curlft.add_time) - now; 357 + (READ_ONCE(xp->curlft.use_time) ? : xp->curlft.add_time) - now; 358 358 if (tmo <= 0) { 359 359 warn = 1; 360 360 tmo = XFRM_KM_TIMEOUT; ··· 3661 3661 return 1; 3662 3662 } 3663 3663 3664 - pol->curlft.use_time = ktime_get_real_seconds(); 3664 + /* This lockless write can happen from different cpus. */ 3665 + WRITE_ONCE(pol->curlft.use_time, ktime_get_real_seconds()); 3665 3666 3666 3667 pols[0] = pol; 3667 3668 npols++; ··· 3677 3676 xfrm_pol_put(pols[0]); 3678 3677 return 0; 3679 3678 } 3680 - pols[1]->curlft.use_time = ktime_get_real_seconds(); 3679 + /* This write can happen from different cpus. */ 3680 + WRITE_ONCE(pols[1]->curlft.use_time, 3681 + ktime_get_real_seconds()); 3681 3682 npols++; 3682 3683 } 3683 3684 } ··· 3744 3741 XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH); 3745 3742 goto reject; 3746 3743 } 3744 + 3745 + if (if_id) 3746 + secpath_reset(skb); 3747 3747 3748 3748 xfrm_pols_put(pols, npols); 3749 3749 return 1;
+9 -9
net/xfrm/xfrm_state.c
··· 577 577 if (x->km.state == XFRM_STATE_EXPIRED) 578 578 goto expired; 579 579 if (x->lft.hard_add_expires_seconds) { 580 - long tmo = x->lft.hard_add_expires_seconds + 580 + time64_t tmo = x->lft.hard_add_expires_seconds + 581 581 x->curlft.add_time - now; 582 582 if (tmo <= 0) { 583 583 if (x->xflags & XFRM_SOFT_EXPIRE) { ··· 594 594 next = tmo; 595 595 } 596 596 if (x->lft.hard_use_expires_seconds) { 597 - long tmo = x->lft.hard_use_expires_seconds + 598 - (x->curlft.use_time ? : now) - now; 597 + time64_t tmo = x->lft.hard_use_expires_seconds + 598 + (READ_ONCE(x->curlft.use_time) ? : now) - now; 599 599 if (tmo <= 0) 600 600 goto expired; 601 601 if (tmo < next) ··· 604 604 if (x->km.dying) 605 605 goto resched; 606 606 if (x->lft.soft_add_expires_seconds) { 607 - long tmo = x->lft.soft_add_expires_seconds + 607 + time64_t tmo = x->lft.soft_add_expires_seconds + 608 608 x->curlft.add_time - now; 609 609 if (tmo <= 0) { 610 610 warn = 1; ··· 616 616 } 617 617 } 618 618 if (x->lft.soft_use_expires_seconds) { 619 - long tmo = x->lft.soft_use_expires_seconds + 620 - (x->curlft.use_time ? : now) - now; 619 + time64_t tmo = x->lft.soft_use_expires_seconds + 620 + (READ_ONCE(x->curlft.use_time) ? : now) - now; 621 621 if (tmo <= 0) 622 622 warn = 1; 623 623 else if (tmo < next) ··· 1906 1906 1907 1907 hrtimer_start(&x1->mtimer, ktime_set(1, 0), 1908 1908 HRTIMER_MODE_REL_SOFT); 1909 - if (x1->curlft.use_time) 1909 + if (READ_ONCE(x1->curlft.use_time)) 1910 1910 xfrm_state_check_expire(x1); 1911 1911 1912 1912 if (x->props.smark.m || x->props.smark.v || x->if_id) { ··· 1940 1940 { 1941 1941 xfrm_dev_state_update_curlft(x); 1942 1942 1943 - if (!x->curlft.use_time) 1944 - x->curlft.use_time = ktime_get_real_seconds(); 1943 + if (!READ_ONCE(x->curlft.use_time)) 1944 + WRITE_ONCE(x->curlft.use_time, ktime_get_real_seconds()); 1945 1945 1946 1946 if (x->curlft.bytes >= x->lft.hard_byte_limit || 1947 1947 x->curlft.packets >= x->lft.hard_packet_limit) {