From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f173.google.com (mail-pf1-f173.google.com [209.85.210.173]) (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 2DE23DF72 for ; Sat, 22 Aug 2026 18:47:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.173 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787424439; cv=none; b=FANeym25ZAJP6H/VZ/WLzRJB91Nt9ksSxGFKG9MPuHtFBukCZt6+cqfD9rEa9VJlEr1JSazMaibq9TEiB8yJzE8JHT0f6O5v1fMMRHL/tGYQZ1Jcr+EW1WaJl7vjzpPYKgbqHYjqi9v4urK3iZUm4UuIxfEf95YXXNtwALQf3fc= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787424439; c=relaxed/simple; bh=5G43uPiVL/j+Dzwm9QTc44uc3K3VaXP56vy3ld8EoOE=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=igyXz07yluaCuoDTfXptBrJ3Ruj/UHwtENCrxlqVdvponNW5iQldkLgwbMwKX1W9ZMo/h2DwMFwfZ4qNfjXgyF3vR9GmR1KZydHnZDH/PnBMRP6Qa0vM9e3A0y7vmXtBzKPHZm4Xtt93TOssy1P9uzoM5kVwdplyCdnKysEgpDU= 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=OfMgf1F+; arc=none smtp.client-ip=209.85.210.173 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="OfMgf1F+" Received: by mail-pf1-f173.google.com with SMTP id d2e1a72fcca58-84a3323d858so157095b3a.3 for ; Sat, 22 Aug 2026 11:47:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1787424437; x=1788029237; 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=r6krEZZrAdPiGjprMWBKZfrQRUv9wjYiRrwTo40Vuek=; b=OfMgf1F+Vxyq+yV3XHsyCTTLvHGVdO9N2BEk2bI0Cg/SdKLPaG1cxRuI2tqTWTvXCV Y3SQRzlLUu12A0F8mGV2EFw0H+ibPj2q4JPDAS2u14w7PXHzRl2QXka2LO9uNYoq2fU0 nOEb8EJr7lC6PnsAdjhuE/7u/t03Da/tvvJlZD39+Ru/MGF9Znl9zGLVkL3jxyzCCc04 DkYV2YtMu6q2hlM9Nf4mKfnE9LN25anbFu2cAa4utOJ1Q66ou8LLvdWrilANCDtX2nKk OajxTqC6tuo3QMfiPKKfvyhi7kiMxybM+FqZaTSzVZBA96ZmnXCrolRKh0KKLWjvrgQQ C4wQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1787424437; x=1788029237; 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=r6krEZZrAdPiGjprMWBKZfrQRUv9wjYiRrwTo40Vuek=; b=P6/EoPcrZA7sHqkNvQbFhqKmKKdLnMHVu9FVnX1pD15zFWsLIxenkpjmv+HbuwzEZ+ LVaOXG/m3sMKawNNcqPPyWSGA19QJss6o7zzBZfpJEfW+0JmT7rbQOMbMG3kxqHFFnsd tRfBMMFLLFeivXEgqPEHehPFJkZKwl79Cc0A0GCD6mQ+HjGyfxN4G7ZzM85BAUo7BY7k RAy1t/bprtxvq0d85LuBNeC+8xlTMuWi/m7ilWn5oy+AjtGGlOLHGDVHl6J1GTMNsNKR AxSjAzFEx8tpOhulOPpZcBeuNTUOESOGxDLjh7fSJYIY2x0sHcMEJrZcKXSfvjNJiyA0 uwfg== X-Forwarded-Encrypted: i=1; AHgh+Rohvrl8foDHEjgMefGj2d5ZvZ3KyBpa34vqfujop5PBjE482GyRJNwjm0YfzxUMxRDX4Uq7FhDZAno8QtU=@vger.kernel.org X-Gm-Message-State: AFuF++nCuTaSDGRkebLAYO1IMS0Lzy0W6lSRf/vC4RWVAa+cauNF6+y3 7bFbaONYhtcmHyUCSYXk4vZYAiJclfUJZJ2goWCzn4HXw75Tz9vj0Isi X-Gm-Gg: AR+sD12biLNBPwScM0wqp+YLbLmrG3KxzXpZ4a8Qg1cyZiolvNND3ZkNNndYoUpjDUO ISyRgdVICMNjxSR6WRUKYE1rtWrd3ie/oxn+tIlmCORtrTrWxnw15zWf3vlZp3qDIvoF40fJ4PW bXJ7SopBEejdP4qn1pc+gbODEyiJoeubaaCgCTRQTjothqobvL+T19q5pEJiT9U6yKLvcTebiM2 CZ//6QRoUmsYXJ6ux5waycJZhjEP3JYIMBqjcSQdJdT6qkOBMwShKanz8uIsfs3AazN4fyTod3f pEHYVWCksKMNsoOWfE0x5Yo1OX0oYMsa6NNGEUK70ywc1yxaNP/nANln5Xx/E6p0+LCOaSNZRpC DYV81ZIlW8KE+q+dWSGCwbMmyjJcbJKpwtzqzFh57h+wBk0fkIhbNTCt2HXtRLLQ6qLFXlNCegW zzgck6WhQgazYeq71eN8ZxEYoDTWRtWyItFtrQGnUPa0rbGxqzna71LW0h8ch2uGJFZgoL6D8ZV c7YHE7b2SW7ZaigiBZG1IvBOo8EutvtsLWAzpJQ+2wt00Gdm9j5Z+0= X-Received: by 2002:a17:902:fc4e:b0:2d3:aecd:51f7 with SMTP id d9443c01a7336-2d64ae3a7c7mr135100305ad.1.1787424437214; Sat, 22 Aug 2026 11:47:17 -0700 (PDT) Received: from localhost.localdomain (45.78.65.84.16clouds.com. [45.78.65.84]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-327f9209fafsm16623681eec.23.2026.08.22.11.47.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 22 Aug 2026 11:47:16 -0700 (PDT) From: Chengfeng Ye To: Pablo Neira Ayuso , Florian Westphal , Phil Sutter , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Gao feng Cc: netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Chengfeng Ye , stable@vger.kernel.org Subject: [PATCH] netfilter: nf_log: clear per-net loggers on unregister Date: Sun, 23 Aug 2026 02:46:58 +0800 Message-ID: <20260822184658.3787672-1-nicoyip.dev@gmail.com> X-Mailer: git-send-email 2.43.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 Logger backends unregister their per-network namespace operations before unregistering their global logger. This leaves a window where a sysctl or netlink writer can rebind a per-net logger after the old per-net selection was cleared, but before the global logger registration is removed. The race looks like this: CPU 0 CPU 1 ---- ---- unregister_pernet_subsys() nf_log_unset(net, logger) net->nf.nf_loggers[pf] = NULL lock nf_log_mutex find logger in loggers[][] net->nf.nf_loggers[pf] = logger unlock nf_log_mutex nf_log_unregister(logger) lock nf_log_mutex loggers[pf][type] = NULL unlock nf_log_mutex synchronize_rcu() module exit returns module core frees backend memory Later, a sysctl read or nf_log_packet() reads net->nf.nf_loggers[pf] and dereferences the stale logger. nf_log_unregister() only removes the backend from the global logger table. It does not clear matching net->nf.nf_loggers[] entries that were rebound by CPU 1 after per-net teardown. Once module unload completes, those per-net pointers can still reference static data from the unloaded logger backend, and later readers can dereference freed module memory. The kernel reported: BUG: unable to handle page fault for address: fffffbfff806d2f4 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page Oops: Oops: 0000 [#1] SMP KASAN NOPTI RIP: 0010:nf_log_proc_dostring+0x2aa/0x4d0 Call Trace: proc_sys_call_handler+0x325/0x540 vfs_read+0x6e1/0xa20 ksys_read+0xf7/0x1c0 do_syscall_64+0xf9/0x520 Modules linked in: [last unloaded: nf_log_syslog] Fix this by clearing matching per-net logger selections in every live network namespace while holding nf_log_mutex after removing the global registrations. Writers that run before this pass are covered by the per-net clears, and writes that run later can no longer find the logger in loggers[][]. The existing synchronize_rcu() then covers readers of both the global and per-net pointers before module memory is released. Fixes: 5b023fc8d8e0 ("netfilter: enable per netns support for nf_loggers") Cc: stable@vger.kernel.org Signed-off-by: Chengfeng Ye --- net/netfilter/nf_log.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index f4d80654dfe6..442c69f544a1 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -42,6 +42,18 @@ static struct nf_logger *__find_logger(int pf, const char *str_logger) return NULL; } +static void __nf_log_unset(struct net *net, const struct nf_logger *logger) +{ + const struct nf_logger *log; + int i; + + for (i = 0; i < NFPROTO_NUMPROTO; i++) { + log = nft_log_dereference(net->nf.nf_loggers[i]); + if (log == logger) + RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL); + } +} + int nf_log_set(struct net *net, u_int8_t pf, const struct nf_logger *logger) { const struct nf_logger *log; @@ -62,15 +74,8 @@ EXPORT_SYMBOL(nf_log_set); void nf_log_unset(struct net *net, const struct nf_logger *logger) { - int i; - const struct nf_logger *log; - mutex_lock(&nf_log_mutex); - for (i = 0; i < NFPROTO_NUMPROTO; i++) { - log = nft_log_dereference(net->nf.nf_loggers[i]); - if (log == logger) - RCU_INIT_POINTER(net->nf.nf_loggers[i], NULL); - } + __nf_log_unset(net, logger); mutex_unlock(&nf_log_mutex); } EXPORT_SYMBOL(nf_log_unset); @@ -112,6 +117,7 @@ EXPORT_SYMBOL(nf_log_register); void nf_log_unregister(struct nf_logger *logger) { const struct nf_logger *log; + struct net *net; int i; mutex_lock(&nf_log_mutex); @@ -120,6 +126,10 @@ void nf_log_unregister(struct nf_logger *logger) if (log == logger) RCU_INIT_POINTER(loggers[i][logger->type], NULL); } + rcu_read_lock(); + for_each_net_rcu(net) + __nf_log_unset(net, logger); + rcu_read_unlock(); mutex_unlock(&nf_log_mutex); synchronize_rcu(); } -- 2.43.0