Skip to content

Commit f6c7b42

Browse files
committed
Merge tag 'ipsec-2023-10-17' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec
Steffen Klassert says: ==================== pull request (net): ipsec 2023-10-17 1) Fix a slab-use-after-free in xfrm_policy_inexact_list_reinsert. From Dong Chenchen. 2) Fix data-races in the xfrm interfaces dev->stats fields. From Eric Dumazet. 3) Fix a data-race in xfrm_gen_index. From Eric Dumazet. 4) Fix an inet6_dev refcount underflow. From Zhang Changzhong. 5) Check the return value of pskb_trim in esp_remove_trailer for esp4 and esp6. From Ma Ke. 6) Fix a data-race in xfrm_lookup_with_ifid. From Eric Dumazet. * tag 'ipsec-2023-10-17' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec: xfrm: fix a data-race in xfrm_lookup_with_ifid() net: ipv4: fix return value check in esp_remove_trailer net: ipv6: fix return value check in esp_remove_trailer xfrm6: fix inet6_dev refcount underflow problem xfrm: fix a data-race in xfrm_gen_index() xfrm: interface: use DEV_STATS_INC() net: xfrm: skip policies marked as dead while reinserting policies ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents c53647a + de5724c commit f6c7b42

File tree

6 files changed

+35
-27
lines changed

6 files changed

+35
-27
lines changed

include/net/netns/xfrm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ struct netns_xfrm {
5050
struct list_head policy_all;
5151
struct hlist_head *policy_byidx;
5252
unsigned int policy_idx_hmask;
53+
unsigned int idx_generator;
5354
struct hlist_head policy_inexact[XFRM_POLICY_MAX];
5455
struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX];
5556
unsigned int policy_count[XFRM_POLICY_MAX * 2];

net/ipv4/esp4.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -732,7 +732,9 @@ static inline int esp_remove_trailer(struct sk_buff *skb)
732732
skb->csum = csum_block_sub(skb->csum, csumdiff,
733733
skb->len - trimlen);
734734
}
735-
pskb_trim(skb, skb->len - trimlen);
735+
ret = pskb_trim(skb, skb->len - trimlen);
736+
if (unlikely(ret))
737+
return ret;
736738

737739
ret = nexthdr[1];
738740

net/ipv6/esp6.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,9 @@ static inline int esp_remove_trailer(struct sk_buff *skb)
770770
skb->csum = csum_block_sub(skb->csum, csumdiff,
771771
skb->len - trimlen);
772772
}
773-
pskb_trim(skb, skb->len - trimlen);
773+
ret = pskb_trim(skb, skb->len - trimlen);
774+
if (unlikely(ret))
775+
return ret;
774776

775777
ret = nexthdr[1];
776778

net/ipv6/xfrm6_policy.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,10 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
117117
{
118118
struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
119119

120-
if (likely(xdst->u.rt6.rt6i_idev))
121-
in6_dev_put(xdst->u.rt6.rt6i_idev);
122120
dst_destroy_metrics_generic(dst);
123121
rt6_uncached_list_del(&xdst->u.rt6);
122+
if (likely(xdst->u.rt6.rt6i_idev))
123+
in6_dev_put(xdst->u.rt6.rt6i_idev);
124124
xfrm_dst_destroy(xdst);
125125
}
126126

net/xfrm/xfrm_interface_core.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,8 @@ static int xfrmi_rcv_cb(struct sk_buff *skb, int err)
380380
skb->dev = dev;
381381

382382
if (err) {
383-
dev->stats.rx_errors++;
384-
dev->stats.rx_dropped++;
383+
DEV_STATS_INC(dev, rx_errors);
384+
DEV_STATS_INC(dev, rx_dropped);
385385

386386
return 0;
387387
}
@@ -426,7 +426,6 @@ static int
426426
xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
427427
{
428428
struct xfrm_if *xi = netdev_priv(dev);
429-
struct net_device_stats *stats = &xi->dev->stats;
430429
struct dst_entry *dst = skb_dst(skb);
431430
unsigned int length = skb->len;
432431
struct net_device *tdev;
@@ -473,7 +472,7 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
473472
tdev = dst->dev;
474473

475474
if (tdev == dev) {
476-
stats->collisions++;
475+
DEV_STATS_INC(dev, collisions);
477476
net_warn_ratelimited("%s: Local routing loop detected!\n",
478477
dev->name);
479478
goto tx_err_dst_release;
@@ -512,13 +511,13 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
512511
if (net_xmit_eval(err) == 0) {
513512
dev_sw_netstats_tx_add(dev, 1, length);
514513
} else {
515-
stats->tx_errors++;
516-
stats->tx_aborted_errors++;
514+
DEV_STATS_INC(dev, tx_errors);
515+
DEV_STATS_INC(dev, tx_aborted_errors);
517516
}
518517

519518
return 0;
520519
tx_err_link_failure:
521-
stats->tx_carrier_errors++;
520+
DEV_STATS_INC(dev, tx_carrier_errors);
522521
dst_link_failure(skb);
523522
tx_err_dst_release:
524523
dst_release(dst);
@@ -528,7 +527,6 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
528527
static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
529528
{
530529
struct xfrm_if *xi = netdev_priv(dev);
531-
struct net_device_stats *stats = &xi->dev->stats;
532530
struct dst_entry *dst = skb_dst(skb);
533531
struct flowi fl;
534532
int ret;
@@ -545,7 +543,7 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
545543
dst = ip6_route_output(dev_net(dev), NULL, &fl.u.ip6);
546544
if (dst->error) {
547545
dst_release(dst);
548-
stats->tx_carrier_errors++;
546+
DEV_STATS_INC(dev, tx_carrier_errors);
549547
goto tx_err;
550548
}
551549
skb_dst_set(skb, dst);
@@ -561,7 +559,7 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
561559
fl.u.ip4.flowi4_flags |= FLOWI_FLAG_ANYSRC;
562560
rt = __ip_route_output_key(dev_net(dev), &fl.u.ip4);
563561
if (IS_ERR(rt)) {
564-
stats->tx_carrier_errors++;
562+
DEV_STATS_INC(dev, tx_carrier_errors);
565563
goto tx_err;
566564
}
567565
skb_dst_set(skb, &rt->dst);
@@ -580,8 +578,8 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
580578
return NETDEV_TX_OK;
581579

582580
tx_err:
583-
stats->tx_errors++;
584-
stats->tx_dropped++;
581+
DEV_STATS_INC(dev, tx_errors);
582+
DEV_STATS_INC(dev, tx_dropped);
585583
kfree_skb(skb);
586584
return NETDEV_TX_OK;
587585
}

net/xfrm/xfrm_policy.c

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net,
851851
struct hlist_node *newpos = NULL;
852852
bool matches_s, matches_d;
853853

854-
if (!policy->bydst_reinsert)
854+
if (policy->walk.dead || !policy->bydst_reinsert)
855855
continue;
856856

857857
WARN_ON_ONCE(policy->family != family);
@@ -1256,8 +1256,11 @@ static void xfrm_hash_rebuild(struct work_struct *work)
12561256
struct xfrm_pol_inexact_bin *bin;
12571257
u8 dbits, sbits;
12581258

1259+
if (policy->walk.dead)
1260+
continue;
1261+
12591262
dir = xfrm_policy_id2dir(policy->index);
1260-
if (policy->walk.dead || dir >= XFRM_POLICY_MAX)
1263+
if (dir >= XFRM_POLICY_MAX)
12611264
continue;
12621265

12631266
if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
@@ -1372,17 +1375,15 @@ EXPORT_SYMBOL(xfrm_policy_hash_rebuild);
13721375
* of an absolute inpredictability of ordering of rules. This will not pass. */
13731376
static u32 xfrm_gen_index(struct net *net, int dir, u32 index)
13741377
{
1375-
static u32 idx_generator;
1376-
13771378
for (;;) {
13781379
struct hlist_head *list;
13791380
struct xfrm_policy *p;
13801381
u32 idx;
13811382
int found;
13821383

13831384
if (!index) {
1384-
idx = (idx_generator | dir);
1385-
idx_generator += 8;
1385+
idx = (net->xfrm.idx_generator | dir);
1386+
net->xfrm.idx_generator += 8;
13861387
} else {
13871388
idx = index;
13881389
index = 0;
@@ -1823,9 +1824,11 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
18231824

18241825
again:
18251826
list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
1827+
if (pol->walk.dead)
1828+
continue;
1829+
18261830
dir = xfrm_policy_id2dir(pol->index);
1827-
if (pol->walk.dead ||
1828-
dir >= XFRM_POLICY_MAX ||
1831+
if (dir >= XFRM_POLICY_MAX ||
18291832
pol->type != type)
18301833
continue;
18311834

@@ -1862,9 +1865,11 @@ int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
18621865

18631866
again:
18641867
list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
1868+
if (pol->walk.dead)
1869+
continue;
1870+
18651871
dir = xfrm_policy_id2dir(pol->index);
1866-
if (pol->walk.dead ||
1867-
dir >= XFRM_POLICY_MAX ||
1872+
if (dir >= XFRM_POLICY_MAX ||
18681873
pol->xdo.dev != dev)
18691874
continue;
18701875

@@ -3215,7 +3220,7 @@ struct dst_entry *xfrm_lookup_with_ifid(struct net *net,
32153220
}
32163221

32173222
for (i = 0; i < num_pols; i++)
3218-
pols[i]->curlft.use_time = ktime_get_real_seconds();
3223+
WRITE_ONCE(pols[i]->curlft.use_time, ktime_get_real_seconds());
32193224

32203225
if (num_xfrms < 0) {
32213226
/* Prohibit the flow */

0 commit comments

Comments
 (0)