Skip to content

Commit 646be03

Browse files
committed
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/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 363d7c2 + 6028da3 commit 646be03

File tree

5 files changed

+73
-20
lines changed

5 files changed

+73
-20
lines changed

net/xfrm/xfrm_compat.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* Based on code and translator idea by: Florian Westphal <[email protected]>
66
*/
77
#include <linux/compat.h>
8+
#include <linux/nospec.h>
89
#include <linux/xfrm.h>
910
#include <net/xfrm.h>
1011

@@ -302,7 +303,7 @@ static int xfrm_xlate64(struct sk_buff *dst, const struct nlmsghdr *nlh_src)
302303
nla_for_each_attr(nla, attrs, len, remaining) {
303304
int err;
304305

305-
switch (type) {
306+
switch (nlh_src->nlmsg_type) {
306307
case XFRM_MSG_NEWSPDINFO:
307308
err = xfrm_nla_cpy(dst, nla, nla_len(nla));
308309
break;
@@ -437,6 +438,7 @@ static int xfrm_xlate32_attr(void *dst, const struct nlattr *nla,
437438
NL_SET_ERR_MSG(extack, "Bad attribute");
438439
return -EOPNOTSUPP;
439440
}
441+
type = array_index_nospec(type, XFRMA_MAX + 1);
440442
if (nla_len(nla) < compat_policy[type].len) {
441443
NL_SET_ERR_MSG(extack, "Attribute bad length");
442444
return -EOPNOTSUPP;

net/xfrm/xfrm_input.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,7 @@ static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
279279
goto out;
280280

281281
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));
284283
if (!(x->props.flags & XFRM_STATE_NOECN))
285284
ipip6_ecn_decapsulate(skb);
286285

net/xfrm/xfrm_interface_core.c

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,52 @@ static void xfrmi_scrub_packet(struct sk_buff *skb, bool xnet)
310310
skb->mark = 0;
311311
}
312312

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+
313359
static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
314360
{
315361
const struct xfrm_mode *inner_mode;
@@ -945,8 +991,8 @@ static struct pernet_operations xfrmi_net_ops = {
945991
};
946992

947993
static struct xfrm6_protocol xfrmi_esp6_protocol __read_mostly = {
948-
.handler = xfrm6_rcv,
949-
.input_handler = xfrm_input,
994+
.handler = xfrmi6_rcv,
995+
.input_handler = xfrmi6_input,
950996
.cb_handler = xfrmi_rcv_cb,
951997
.err_handler = xfrmi6_err,
952998
.priority = 10,
@@ -996,8 +1042,8 @@ static struct xfrm6_tunnel xfrmi_ip6ip_handler __read_mostly = {
9961042
#endif
9971043

9981044
static struct xfrm4_protocol xfrmi_esp4_protocol __read_mostly = {
999-
.handler = xfrm4_rcv,
1000-
.input_handler = xfrm_input,
1045+
.handler = xfrmi4_rcv,
1046+
.input_handler = xfrmi4_input,
10011047
.cb_handler = xfrmi_rcv_cb,
10021048
.err_handler = xfrmi4_err,
10031049
.priority = 10,

net/xfrm/xfrm_policy.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ static void xfrm_policy_timer(struct timer_list *t)
336336
}
337337
if (xp->lft.hard_use_expires_seconds) {
338338
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;
340340
if (tmo <= 0)
341341
goto expired;
342342
if (tmo < next)
@@ -354,7 +354,7 @@ static void xfrm_policy_timer(struct timer_list *t)
354354
}
355355
if (xp->lft.soft_use_expires_seconds) {
356356
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;
358358
if (tmo <= 0) {
359359
warn = 1;
360360
tmo = XFRM_KM_TIMEOUT;
@@ -3661,7 +3661,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
36613661
return 1;
36623662
}
36633663

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());
36653666

36663667
pols[0] = pol;
36673668
npols++;
@@ -3676,7 +3677,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
36763677
xfrm_pol_put(pols[0]);
36773678
return 0;
36783679
}
3679-
pols[1]->curlft.use_time = ktime_get_real_seconds();
3680+
/* This write can happen from different cpus. */
3681+
WRITE_ONCE(pols[1]->curlft.use_time,
3682+
ktime_get_real_seconds());
36803683
npols++;
36813684
}
36823685
}
@@ -3742,6 +3745,9 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
37423745
goto reject;
37433746
}
37443747

3748+
if (if_id)
3749+
secpath_reset(skb);
3750+
37453751
xfrm_pols_put(pols, npols);
37463752
return 1;
37473753
}

net/xfrm/xfrm_state.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,7 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
577577
if (x->km.state == XFRM_STATE_EXPIRED)
578578
goto expired;
579579
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 +
581581
x->curlft.add_time - now;
582582
if (tmo <= 0) {
583583
if (x->xflags & XFRM_SOFT_EXPIRE) {
@@ -594,8 +594,8 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
594594
next = tmo;
595595
}
596596
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;
599599
if (tmo <= 0)
600600
goto expired;
601601
if (tmo < next)
@@ -604,7 +604,7 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
604604
if (x->km.dying)
605605
goto resched;
606606
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 +
608608
x->curlft.add_time - now;
609609
if (tmo <= 0) {
610610
warn = 1;
@@ -616,8 +616,8 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me)
616616
}
617617
}
618618
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;
621621
if (tmo <= 0)
622622
warn = 1;
623623
else if (tmo < next)
@@ -1906,7 +1906,7 @@ int xfrm_state_update(struct xfrm_state *x)
19061906

19071907
hrtimer_start(&x1->mtimer, ktime_set(1, 0),
19081908
HRTIMER_MODE_REL_SOFT);
1909-
if (x1->curlft.use_time)
1909+
if (READ_ONCE(x1->curlft.use_time))
19101910
xfrm_state_check_expire(x1);
19111911

19121912
if (x->props.smark.m || x->props.smark.v || x->if_id) {
@@ -1940,8 +1940,8 @@ int xfrm_state_check_expire(struct xfrm_state *x)
19401940
{
19411941
xfrm_dev_state_update_curlft(x);
19421942

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());
19451945

19461946
if (x->curlft.bytes >= x->lft.hard_byte_limit ||
19471947
x->curlft.packets >= x->lft.hard_packet_limit) {

0 commit comments

Comments
 (0)