From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f48.google.com (mail-pj1-f48.google.com [209.85.216.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1063839280C for ; Tue, 25 Aug 2026 20:02:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.48 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787688180; cv=none; b=WEQTJpxYc3JCel8gF9ojcet7TOjYqHWOadVmLRYyDfpP/REbWyHYm67luiYBGTj290cytXQnSYuZcBffeOklvNGs/RyLJrhy4Fjd+4K1D+lHiS9B3W28Qkx7fH2p9MNZ04F6CBxqZYVsLIRO2oYMR2uG0Z0xYvGIBpZK+FPH+PA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787688180; c=relaxed/simple; bh=wSj/Bziwj2nKmZlwT90+vNBfPdmMDOGVBjj/fVWpTQE=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=rvmoULg2PU2zO8fI05MTZILi/TGiB8EEZVRnsvo3/m8a1zXcxTCx8AwQgQb4/NMykXkSPtSavCkd0LWeaXS4ZntYP7OQPf+Zosyp/zj+bhUYpJWr9+byhp/ciRXmfSyzcOpiJ0ND5r/dGLedo+1vifCLR/xgRy/koTXMMEMcf10= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=iznWfC13; arc=none smtp.client-ip=209.85.216.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iznWfC13" Received: by mail-pj1-f48.google.com with SMTP id 98e67ed59e1d1-38dc69c74b8so348483a91.0 for ; Tue, 25 Aug 2026 13:02:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787688178; x=1788292978; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=B3Pi1LU2yqNrQy/N3chmYaA7JCHAIIMXZlkkYLifKOw=; b=iznWfC13XjXB4QayCT0wCmxdnlnZbrZbkCPeNS6DUZIyJ25ozilf9yA17tOSp8qto7 b40Zu0DmVXmKz178Xl1ZEWrDpES6xrHHCZumhAfFShwTv3Eg0Vof7HvHI/ia/RH9e3k7 q6Kw9Ncu7Wge8Pw9quPK6Pz5+xrOeiw4psG28g4wr54c7d5G+4fg5OmmYzDu9wqYkJLx ZW4Y4IxUt9n68+/j5R0KxzloRTqc4GwGRAa0FgIyjmqfmltqeVajY8SmlD7jG3k+AuUV OUxUXk//ir0CEDBc3Vauer6sNNz+S5Xz87WHShDZzj5Q5vMGDBJuaqeNzQquBlNnllPK FWng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787688178; x=1788292978; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=B3Pi1LU2yqNrQy/N3chmYaA7JCHAIIMXZlkkYLifKOw=; b=s1DdRFZq+JL6Qfz7kjjjNezHFamx1WFT8OyElM4t+W4ydeLvQhQYKdCuywbcPfkJ5Y 4xTZtCdoqhYw/BVYp9rTHvenLtRVCr8rl8eX0VfWKoWwRU3Ivq3RY/JSwn/TNKR4eNI/ Z01tT65GMGvzJVZk/BiN4E6jxYrOpDEI1xqIESV9XN3uxRHGcXbIExMBx2Q6GezPQQzX duGVhgCxJse57xeINEngJnjdhKnyfHg58fm6rGjDdYbMUR9KxGkmwN+sAgJtOOou5B5T fUsoQ9QJ56I3qyoh9XkayGoQFp5JxdQCHddk90O0Bot15E5pQCbLivy/W5E+ioFpCayQ ksfQ== X-Forwarded-Encrypted: i=1; AHgh+RqjP+wfxjKpDNDRD6A9Tuw6o2mnw3CC6RmeTB5h7VjfXT1rG7LGT9puFXI7+NJzGc0FnuymrOy5QTyri0c=@vger.kernel.org X-Gm-Message-State: AFuF++l5gx2YbEpuu48NyJ0ViWrU0iS0Su5Zp/W2mHY2xIjpluWKexdk kCg0U53UW0ffz4Va0Lrs+NuuwG6hymNM9vbMoNePUEpeYt5ldKpuyjfd X-Gm-Gg: AR+sD11dJTdfZvwGkz8cPNOo4iQAGYOY3wWQ1hR89pizfQDlhXki+aXy1ZWYN3ysM4x W7yYMM32PHkenXAe6P671S7cY4ltUwc7D/4Zzo3QFkhh/aFSCddAx6A+ppE384wFltrhJyfQl96 ShYCUD6FEafimuxy8Kf7DdvGOP2K3bQBz56JG5/wvrau0WvFeWMyFIfY8OSB/vl7IBAQs0Vum/i aOkMPcNU2pyKjJmCu0VUHtzv/Olw1hjpwkBczxHJT0oFLz92P53h9Uh9R/i+Hi0xtbHdWsIHHNo fyNLjw3U6LoBeKGIRTLelu7rFOPd8l1HZwyxgxrH64MhgA7lEtjSoPT98IXytFSUIO0WZHhONxX NaldUO+bhUdXvaUg5c9qeF0xeijb7kFCWZ6cPFAeAC8NpBXkRlr0vDhIUcTNMOYqCcnN9erDNTh 6zhlFrakVpmMI6dTuIyyrkdvg3yVfsmImRHxhEzN+EXIxtik5TTmZd58VA9cO1e1/sJ754bj6fC xEu26k1Gmod+z0lw/ovcw== X-Received: by 2002:a17:90b:1d46:b0:396:5fce:8e24 with SMTP id 98e67ed59e1d1-3966d197b6dmr3482328a91.4.1787688178216; Tue, 25 Aug 2026 13:02:58 -0700 (PDT) Received: from localhost.localdomain ([2001:4898:a800:1012:54d7:ed:5a29:eac3]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-396686e840bsm952049a91.2.2026.08.25.13.02.55 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Tue, 25 Aug 2026 13:02:57 -0700 (PDT) From: "Cen Zhang (Microsoft)" To: pablo@netfilter.org, fw@strlen.de, davem@davemloft.net, edumazet@google.com, kuba@kernel.org, pabeni@redhat.com Cc: phil@nwl.cc, horms@kernel.org, xuanqiang.luo@linux.dev, kadlec@netfilter.org, kees@kernel.org, enrico.pozzobon@dissecto.com, sbrivio@redhat.com, netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, AutonomousCodeSecurity@microsoft.com, xmei5@asu.edu, tgopinath@linux.microsoft.com, kys@microsoft.com, blbllhy@gmail.com Subject: [PATCH net v2] netfilter: ipset: add synchronize_rcu() in destroy to close use-after-free race Date: Tue, 25 Aug 2026 16:02:43 -0400 Message-ID: <20260825200243.23077-1-blbllhy@gmail.com> X-Mailer: git-send-email 2.55.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit The child set refcount decrement in list_set_del() was moved from an RCU callback to the synchronous path, so that userspace sees accurate reference counts immediately. However, this broke an implicit invariant: previously ref could only reach zero after an RCU grace period, guaranteeing all RCU readers had finished before destroy could proceed. Now ref can hit zero while readers still hold a stale index, and ip_set_destroy() NULLs the slot out from under them: CPU 0 (softirq) CPU 1 (control path) --- --- rcu_read_lock() index = e->id list_set_del(): list_del_rcu(e) ip_set_put_byindex(index) // ref->0 ip_set_destroy(): ip_set_list[index] = NULL ip_set_rcu_get(index) -> NULL BUG_ON(!set) // crash kernel BUG at net/netfilter/ipset/ip_set_core.c:754! ip_set_test <- list_set_kadt <- ip_set_test <- set_match_v1 Insert synchronize_rcu() in ip_set_destroy() after confirming ref == 0 but before NULLing the slot, so it only pays the RCU wait cost when actually destroying. Because synchronize_rcu() sleeps, ip_set_ref_lock must be dropped first, which splits the critical section in two. A recheck of ref/ref_netlink is therefore needed in the second section, since a concurrent netlink dump continuation (which does not hold nfnl_lock) may have incremented ref_netlink in the interim. The bulk _destroy_all_sets() path does not need this recheck because its is_destroyed flag prevents dump from taking new references. Fixes: 439cd39ea136 ("netfilter: ipset: list:set: Decrease refcount synchronously on deletion and replace") Reported-by: AutonomousCodeSecurity@microsoft.com Reported-by: Xiang Mei (Microsoft) Reported-by: Cen Zhang (Microsoft) Closes: https://lore.kernel.org/all/20260820010617.46851-1-blbllhy@gmail.com/ Signed-off-by: Cen Zhang (Microsoft) --- net/netfilter/ipset/ip_set_core.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 0a86a170ba90..1295bea7944a 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1225,6 +1225,8 @@ _destroy_all_sets(struct ip_set_net *inst) /* Must wait for flush to be really finished */ if (need_wait) rcu_barrier(); + /* Wait for RCU readers before NULLing slots */ + synchronize_rcu(); for (i = 0; i < inst->ip_set_max; i++) { set = ip_set(inst, i); if (set) { @@ -1286,6 +1288,17 @@ static int ip_set_destroy(struct sk_buff *skb, const struct nfnl_info *info, ret = -IPSET_ERR_BUSY; goto out; } + read_unlock_bh(&ip_set_ref_lock); + + /* Wait for RCU readers before NULLing slot */ + synchronize_rcu(); + + read_lock_bh(&ip_set_ref_lock); + /* Dump may have taken a ref while lock was dropped */ + if (s->ref || s->ref_netlink) { + ret = -IPSET_ERR_BUSY; + goto out; + } features = s->type->features; ip_set(inst, i) = NULL; read_unlock_bh(&ip_set_ref_lock); -- 2.55.0