Patch "net: xfrm: skip policies marked as dead while reinserting policies" has been added to the 6.1-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    net: xfrm: skip policies marked as dead while reinserting policies

to the 6.1-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     net-xfrm-skip-policies-marked-as-dead-while-reinsert.patch
and it can be found in the queue-6.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit aceaae0532ca72b5bec91314f57c627992743869
Author: Dong Chenchen <dongchenchen2@xxxxxxxxxx>
Date:   Tue Aug 15 22:18:34 2023 +0800

    net: xfrm: skip policies marked as dead while reinserting policies
    
    [ Upstream commit 6d41d4fe28724db16ca1016df0713a07e0cc7448 ]
    
    BUG: KASAN: slab-use-after-free in xfrm_policy_inexact_list_reinsert+0xb6/0x430
    Read of size 1 at addr ffff8881051f3bf8 by task ip/668
    
    CPU: 2 PID: 668 Comm: ip Not tainted 6.5.0-rc5-00182-g25aa0bebba72-dirty #64
    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.13 04/01/2014
    Call Trace:
     <TASK>
     dump_stack_lvl+0x72/0xa0
     print_report+0xd0/0x620
     kasan_report+0xb6/0xf0
     xfrm_policy_inexact_list_reinsert+0xb6/0x430
     xfrm_policy_inexact_insert_node.constprop.0+0x537/0x800
     xfrm_policy_inexact_alloc_chain+0x23f/0x320
     xfrm_policy_inexact_insert+0x6b/0x590
     xfrm_policy_insert+0x3b1/0x480
     xfrm_add_policy+0x23c/0x3c0
     xfrm_user_rcv_msg+0x2d0/0x510
     netlink_rcv_skb+0x10d/0x2d0
     xfrm_netlink_rcv+0x49/0x60
     netlink_unicast+0x3fe/0x540
     netlink_sendmsg+0x528/0x970
     sock_sendmsg+0x14a/0x160
     ____sys_sendmsg+0x4fc/0x580
     ___sys_sendmsg+0xef/0x160
     __sys_sendmsg+0xf7/0x1b0
     do_syscall_64+0x3f/0x90
     entry_SYSCALL_64_after_hwframe+0x73/0xdd
    
    The root cause is:
    
    cpu 0                   cpu1
    xfrm_dump_policy
    xfrm_policy_walk
    list_move_tail
                            xfrm_add_policy
                            ... ...
                            xfrm_policy_inexact_list_reinsert
                            list_for_each_entry_reverse
                                    if (!policy->bydst_reinsert)
                                    //read non-existent policy
    xfrm_dump_policy_done
    xfrm_policy_walk_done
    list_del(&walk->walk.all);
    
    If dump_one_policy() returns err (triggered by netlink socket),
    xfrm_policy_walk() will move walk initialized by socket to list
    net->xfrm.policy_all. so this socket becomes visible in the global
    policy list. The head *walk can be traversed when users add policies
    with different prefixlen and trigger xfrm_policy node merge.
    
    The issue can also be triggered by policy list traversal while rehashing
    and flushing policies.
    
    It can be fixed by skip such "policies" with walk.dead set to 1.
    
    Fixes: 9cf545ebd591 ("xfrm: policy: store inexact policies in a tree ordered by destination address")
    Fixes: 12a169e7d8f4 ("ipsec: Put dumpers on the dump list")
    Signed-off-by: Dong Chenchen <dongchenchen2@xxxxxxxxxx>
    Signed-off-by: Steffen Klassert <steffen.klassert@xxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e4d320e036fed..e47c670c7e2cd 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -850,7 +850,7 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net,
 		struct hlist_node *newpos = NULL;
 		bool matches_s, matches_d;
 
-		if (!policy->bydst_reinsert)
+		if (policy->walk.dead || !policy->bydst_reinsert)
 			continue;
 
 		WARN_ON_ONCE(policy->family != family);
@@ -1255,8 +1255,11 @@ static void xfrm_hash_rebuild(struct work_struct *work)
 		struct xfrm_pol_inexact_bin *bin;
 		u8 dbits, sbits;
 
+		if (policy->walk.dead)
+			continue;
+
 		dir = xfrm_policy_id2dir(policy->index);
-		if (policy->walk.dead || dir >= XFRM_POLICY_MAX)
+		if (dir >= XFRM_POLICY_MAX)
 			continue;
 
 		if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) {
@@ -1788,9 +1791,11 @@ int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
 
 again:
 	list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
+		if (pol->walk.dead)
+			continue;
+
 		dir = xfrm_policy_id2dir(pol->index);
-		if (pol->walk.dead ||
-		    dir >= XFRM_POLICY_MAX ||
+		if (dir >= XFRM_POLICY_MAX ||
 		    pol->type != type)
 			continue;
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux