Skip to content

Commit e36db40

Browse files
committed
Merge: xfrm: stable backports
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/6711 JIRA: https://issues.redhat.com/browse/RHEL-84576 Backport of commits: e952837 ("xfrm: state: fix out-of-bounds read during lookup") 600258d ("xfrm: delete intermediate secpath entry in packet offload mode") 1620c88 ("xfrm: Fix the usage of skb->sk") Signed-off-by: Sabrina Dubroca <sdubroca@redhat.com> Approved-by: Florian Westphal <fwestpha@redhat.com> Approved-by: Xin Long <lxin@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Augusto Caringi <acaringi@redhat.com>
2 parents 85718e6 + fbe3f10 commit e36db40

File tree

8 files changed

+89
-30
lines changed

8 files changed

+89
-30
lines changed

include/net/xfrm.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,9 +1174,19 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir,
11741174

11751175
if (xo) {
11761176
x = xfrm_input_state(skb);
1177-
if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
1178-
return (xo->flags & CRYPTO_DONE) &&
1179-
(xo->status & CRYPTO_SUCCESS);
1177+
if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) {
1178+
bool check = (xo->flags & CRYPTO_DONE) &&
1179+
(xo->status & CRYPTO_SUCCESS);
1180+
1181+
/* The packets here are plain ones and secpath was
1182+
* needed to indicate that hardware already handled
1183+
* them and there is no need to do nothing in addition.
1184+
*
1185+
* Consume secpath which was set by drivers.
1186+
*/
1187+
secpath_reset(skb);
1188+
return check;
1189+
}
11801190
}
11811191

11821192
return __xfrm_check_nopolicy(net, skb, dir) ||

net/ipv4/esp4.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ static void esp_output_done(struct crypto_async_request *base, int err)
280280
x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
281281
esp_output_tail_tcp(x, skb);
282282
else
283-
xfrm_output_resume(skb->sk, skb, err);
283+
xfrm_output_resume(skb_to_full_sk(skb), skb, err);
284284
}
285285
}
286286

net/ipv6/esp6.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ static void esp_output_done(struct crypto_async_request *base, int err)
315315
x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
316316
esp_output_tail_tcp(x, skb);
317317
else
318-
xfrm_output_resume(skb->sk, skb, err);
318+
xfrm_output_resume(skb_to_full_sk(skb), skb, err);
319319
}
320320
}
321321

net/ipv6/xfrm6_output.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,14 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
8282

8383
toobig = skb->len > mtu && !skb_is_gso(skb);
8484

85-
if (toobig && xfrm6_local_dontfrag(skb->sk)) {
85+
if (toobig && xfrm6_local_dontfrag(sk)) {
8686
xfrm6_local_rxpmtu(skb, mtu);
8787
kfree_skb(skb);
8888
return -EMSGSIZE;
8989
} else if (toobig && xfrm6_noneed_fragment(skb)) {
9090
skb->ignore_df = 1;
9191
goto skip_frag;
92-
} else if (!skb->ignore_df && toobig && skb->sk) {
92+
} else if (!skb->ignore_df && toobig && sk) {
9393
xfrm_local_error(skb, mtu);
9494
kfree_skb(skb);
9595
return -EMSGSIZE;

net/xfrm/xfrm_interface_core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
461461
skb_dst_set(skb, dst);
462462
skb->dev = tdev;
463463

464-
err = dst_output(xi->net, skb->sk, skb);
464+
err = dst_output(xi->net, skb_to_full_sk(skb), skb);
465465
if (net_xmit_eval(err) == 0) {
466466
dev_sw_netstats_tx_add(dev, 1, length);
467467
} else {

net/xfrm/xfrm_output.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
796796
!skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) {
797797
skb->protocol = htons(ETH_P_IP);
798798

799-
if (skb->sk)
799+
if (skb->sk && sk_fullsock(skb->sk))
800800
xfrm_local_error(skb, mtu);
801801
else
802802
icmp_send(skb, ICMP_DEST_UNREACH,
@@ -832,6 +832,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
832832
{
833833
int mtu, ret = 0;
834834
struct dst_entry *dst = skb_dst(skb);
835+
struct sock *sk = skb_to_full_sk(skb);
835836

836837
if (skb->ignore_df)
837838
goto out;
@@ -846,9 +847,9 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
846847
skb->dev = dst->dev;
847848
skb->protocol = htons(ETH_P_IPV6);
848849

849-
if (xfrm6_local_dontfrag(skb->sk))
850+
if (xfrm6_local_dontfrag(sk))
850851
ipv6_stub->xfrm6_local_rxpmtu(skb, mtu);
851-
else if (skb->sk)
852+
else if (sk)
852853
xfrm_local_error(skb, mtu);
853854
else
854855
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);

net/xfrm/xfrm_policy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2910,7 +2910,7 @@ static void xfrm_policy_queue_process(struct timer_list *t)
29102910
skb_dst_drop(skb);
29112911
skb_dst_set(skb, dst);
29122912

2913-
dst_output(net, skb->sk, skb);
2913+
dst_output(net, skb_to_full_sk(skb), skb);
29142914
}
29152915

29162916
out:

net/xfrm/xfrm_state.c

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
#define xfrm_state_deref_prot(table, net) \
3636
rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock))
37+
#define xfrm_state_deref_check(table, net) \
38+
rcu_dereference_check((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock))
3739

3840
static void xfrm_state_gc_task(struct work_struct *work);
3941

@@ -62,6 +64,8 @@ static inline unsigned int xfrm_dst_hash(struct net *net,
6264
u32 reqid,
6365
unsigned short family)
6466
{
67+
lockdep_assert_held(&net->xfrm.xfrm_state_lock);
68+
6569
return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask);
6670
}
6771

@@ -70,18 +74,24 @@ static inline unsigned int xfrm_src_hash(struct net *net,
7074
const xfrm_address_t *saddr,
7175
unsigned short family)
7276
{
77+
lockdep_assert_held(&net->xfrm.xfrm_state_lock);
78+
7379
return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask);
7480
}
7581

7682
static inline unsigned int
7783
xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr,
7884
__be32 spi, u8 proto, unsigned short family)
7985
{
86+
lockdep_assert_held(&net->xfrm.xfrm_state_lock);
87+
8088
return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
8189
}
8290

8391
static unsigned int xfrm_seq_hash(struct net *net, u32 seq)
8492
{
93+
lockdep_assert_held(&net->xfrm.xfrm_state_lock);
94+
8595
return __xfrm_seq_hash(seq, net->xfrm.state_hmask);
8696
}
8797

@@ -1032,16 +1042,38 @@ xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl,
10321042
x->props.family = tmpl->encap_family;
10331043
}
10341044

1035-
static struct xfrm_state *__xfrm_state_lookup_all(struct net *net, u32 mark,
1045+
struct xfrm_hash_state_ptrs {
1046+
const struct hlist_head *bydst;
1047+
const struct hlist_head *bysrc;
1048+
const struct hlist_head *byspi;
1049+
unsigned int hmask;
1050+
};
1051+
1052+
static void xfrm_hash_ptrs_get(const struct net *net, struct xfrm_hash_state_ptrs *ptrs)
1053+
{
1054+
unsigned int sequence;
1055+
1056+
do {
1057+
sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
1058+
1059+
ptrs->bydst = xfrm_state_deref_check(net->xfrm.state_bydst, net);
1060+
ptrs->bysrc = xfrm_state_deref_check(net->xfrm.state_bysrc, net);
1061+
ptrs->byspi = xfrm_state_deref_check(net->xfrm.state_byspi, net);
1062+
ptrs->hmask = net->xfrm.state_hmask;
1063+
} while (read_seqcount_retry(&net->xfrm.xfrm_state_hash_generation, sequence));
1064+
}
1065+
1066+
static struct xfrm_state *__xfrm_state_lookup_all(const struct xfrm_hash_state_ptrs *state_ptrs,
1067+
u32 mark,
10361068
const xfrm_address_t *daddr,
10371069
__be32 spi, u8 proto,
10381070
unsigned short family,
10391071
struct xfrm_dev_offload *xdo)
10401072
{
1041-
unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
1073+
unsigned int h = __xfrm_spi_hash(daddr, spi, proto, family, state_ptrs->hmask);
10421074
struct xfrm_state *x;
10431075

1044-
hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) {
1076+
hlist_for_each_entry_rcu(x, state_ptrs->byspi + h, byspi) {
10451077
#ifdef CONFIG_XFRM_OFFLOAD
10461078
if (xdo->type == XFRM_DEV_OFFLOAD_PACKET) {
10471079
if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
@@ -1075,15 +1107,16 @@ static struct xfrm_state *__xfrm_state_lookup_all(struct net *net, u32 mark,
10751107
return NULL;
10761108
}
10771109

1078-
static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
1110+
static struct xfrm_state *__xfrm_state_lookup(const struct xfrm_hash_state_ptrs *state_ptrs,
1111+
u32 mark,
10791112
const xfrm_address_t *daddr,
10801113
__be32 spi, u8 proto,
10811114
unsigned short family)
10821115
{
1083-
unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
1116+
unsigned int h = __xfrm_spi_hash(daddr, spi, proto, family, state_ptrs->hmask);
10841117
struct xfrm_state *x;
10851118

1086-
hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) {
1119+
hlist_for_each_entry_rcu(x, state_ptrs->byspi + h, byspi) {
10871120
if (x->props.family != family ||
10881121
x->id.spi != spi ||
10891122
x->id.proto != proto ||
@@ -1100,15 +1133,16 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
11001133
return NULL;
11011134
}
11021135

1103-
static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark,
1136+
static struct xfrm_state *__xfrm_state_lookup_byaddr(const struct xfrm_hash_state_ptrs *state_ptrs,
1137+
u32 mark,
11041138
const xfrm_address_t *daddr,
11051139
const xfrm_address_t *saddr,
11061140
u8 proto, unsigned short family)
11071141
{
1108-
unsigned int h = xfrm_src_hash(net, daddr, saddr, family);
1142+
unsigned int h = __xfrm_src_hash(daddr, saddr, family, state_ptrs->hmask);
11091143
struct xfrm_state *x;
11101144

1111-
hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) {
1145+
hlist_for_each_entry_rcu(x, state_ptrs->bysrc + h, bysrc) {
11121146
if (x->props.family != family ||
11131147
x->id.proto != proto ||
11141148
!xfrm_addr_equal(&x->id.daddr, daddr, family) ||
@@ -1128,14 +1162,17 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark,
11281162
static inline struct xfrm_state *
11291163
__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family)
11301164
{
1165+
struct xfrm_hash_state_ptrs state_ptrs;
11311166
struct net *net = xs_net(x);
11321167
u32 mark = x->mark.v & x->mark.m;
11331168

1169+
xfrm_hash_ptrs_get(net, &state_ptrs);
1170+
11341171
if (use_spi)
1135-
return __xfrm_state_lookup(net, mark, &x->id.daddr,
1172+
return __xfrm_state_lookup(&state_ptrs, mark, &x->id.daddr,
11361173
x->id.spi, x->id.proto, family);
11371174
else
1138-
return __xfrm_state_lookup_byaddr(net, mark,
1175+
return __xfrm_state_lookup_byaddr(&state_ptrs, mark,
11391176
&x->id.daddr,
11401177
&x->props.saddr,
11411178
x->id.proto, family);
@@ -1198,6 +1235,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
11981235
unsigned short family, u32 if_id)
11991236
{
12001237
static xfrm_address_t saddr_wildcard = { };
1238+
struct xfrm_hash_state_ptrs state_ptrs;
12011239
struct net *net = xp_net(pol);
12021240
unsigned int h, h_wildcard;
12031241
struct xfrm_state *x, *x0, *to_put;
@@ -1214,8 +1252,10 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
12141252
sequence = read_seqcount_begin(&net->xfrm.xfrm_state_hash_generation);
12151253

12161254
rcu_read_lock();
1217-
h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
1218-
hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
1255+
xfrm_hash_ptrs_get(net, &state_ptrs);
1256+
1257+
h = __xfrm_dst_hash(daddr, saddr, tmpl->reqid, encap_family, state_ptrs.hmask);
1258+
hlist_for_each_entry_rcu(x, state_ptrs.bydst + h, bydst) {
12191259
#ifdef CONFIG_XFRM_OFFLOAD
12201260
if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
12211261
if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
@@ -1248,8 +1288,9 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
12481288
if (best || acquire_in_progress)
12491289
goto found;
12501290

1251-
h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
1252-
hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) {
1291+
h_wildcard = __xfrm_dst_hash(daddr, &saddr_wildcard, tmpl->reqid,
1292+
encap_family, state_ptrs.hmask);
1293+
hlist_for_each_entry_rcu(x, state_ptrs.bydst + h_wildcard, bydst) {
12531294
#ifdef CONFIG_XFRM_OFFLOAD
12541295
if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
12551296
if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
@@ -1284,7 +1325,7 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
12841325
x = best;
12851326
if (!x && !error && !acquire_in_progress) {
12861327
if (tmpl->id.spi &&
1287-
(x0 = __xfrm_state_lookup_all(net, mark, daddr,
1328+
(x0 = __xfrm_state_lookup_all(&state_ptrs, mark, daddr,
12881329
tmpl->id.spi, tmpl->id.proto,
12891330
encap_family,
12901331
&pol->xdo)) != NULL) {
@@ -2030,10 +2071,13 @@ struct xfrm_state *
20302071
xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi,
20312072
u8 proto, unsigned short family)
20322073
{
2074+
struct xfrm_hash_state_ptrs state_ptrs;
20332075
struct xfrm_state *x;
20342076

20352077
rcu_read_lock();
2036-
x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family);
2078+
xfrm_hash_ptrs_get(net, &state_ptrs);
2079+
2080+
x = __xfrm_state_lookup(&state_ptrs, mark, daddr, spi, proto, family);
20372081
rcu_read_unlock();
20382082
return x;
20392083
}
@@ -2044,10 +2088,14 @@ xfrm_state_lookup_byaddr(struct net *net, u32 mark,
20442088
const xfrm_address_t *daddr, const xfrm_address_t *saddr,
20452089
u8 proto, unsigned short family)
20462090
{
2091+
struct xfrm_hash_state_ptrs state_ptrs;
20472092
struct xfrm_state *x;
20482093

20492094
spin_lock_bh(&net->xfrm.xfrm_state_lock);
2050-
x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family);
2095+
2096+
xfrm_hash_ptrs_get(net, &state_ptrs);
2097+
2098+
x = __xfrm_state_lookup_byaddr(&state_ptrs, mark, daddr, saddr, proto, family);
20512099
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
20522100
return x;
20532101
}

0 commit comments

Comments
 (0)