From nobody Mon Sep 28 23:13:08 2026 Received: from oss.cyber.gouv.fr (oss.cyber.gouv.fr [51.159.188.251]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C113B42586C for ; Sat, 15 Aug 2026 15:55:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=51.159.188.251 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786809310; cv=none; b=UIFrwUqx2wTN2fJlngKi8TgZhqAF8SbfTrPeWIvdnJAODqWUyRs7bmLIpShCuwkby+62zoM1lAjjhNQvVGCkWuU2o9dFCkn7Fy6aALCoIP95sz+jnf20tKNwyCwwzLKZ/4C6fTAwq1/Amc/L791gGO4XMLdIU3kGFxZGrQDyXb0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786809310; c=relaxed/simple; bh=S9+e8Gezo8WgXtF2SOl2Xm15YWGo9e1VKU7GZlDcSAU=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version:Content-Type; b=Z+qlnFP533RYogsJdqgsVEqWNt4KyPlV1Vf+giQ/VvJc59qq9xGKnnPRCZ7/89RYULSAvi50s13oxYmMQfHy+Mlf+Wz1hEx/iGnMc8nnk4LPz++VcLFzWcvdX0n3kpRaP8w7jL97hlvEN0uJ8Nr65XBrhHtVOY8Yd2qwMbC9FBg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr; spf=pass smtp.mailfrom=oss.cyber.gouv.fr; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b=Z2+K0qai; arc=none smtp.client-ip=51.159.188.251 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.cyber.gouv.fr Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=oss.cyber.gouv.fr header.i=@oss.cyber.gouv.fr header.b="Z2+K0qai" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=oss.cyber.gouv.fr; s=default; h=Content-Transfer-Encoding:Content-Type: MIME-Version:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=PDAoROoa+wEPK8AEh4yjRofEq3yu9FfPmDW1p5QIARQ=; b=Z2+K0qaiqpehugTlw/jzmpJXil /F3clXxdpQgCmCKQj16i6D04YEi7VOWZQIB25edRTJa/oNFk1hDRhwRcpjHmWmjl0NDtXORXULwN5 yGqSq+8ZR8LbPYyo1YePDN+0rcCLkFwmWhOl0D/RSfw4zVoiDIVMrtWVhaMHuzairc6Jhr2g0Ur4m oQ/r1/MQpfNpoPN4q1JV+LIx1skRmudqTeCvhoeRJUhZul5t87jwtHJYIiG+SCiqGWre/JxYRH8RX +TTUL7E0jX+uWE6Yr6kah7L1zJeySzyGWy4RZTndA1aGuIolTuMB7F+ysYYHc+f3kig0J2NIb+IvG qqR1+ctg==; Received: from [151.115.150.205] (port=35486 helo=gepetto..) by pf-012.whm.fr-par.scw.cloud with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.99.5) (envelope-from ) id 1wvGir-00000001ThB-1XwO; Sat, 15 Aug 2026 17:54:57 +0200 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= To: Joel Granados Cc: Kees Cook , linux-kernel@vger.kernel.org, =?UTF-8?q?J=C3=A9r=C3=A9my=20Jean?= Subject: [PATCH] pid: keep cad_pid in init pidns and serialize access Date: Sat, 15 Aug 2026 15:54:14 +0000 Message-ID: <20260815155413.135280-2-Jeremy.Jean@oss.cyber.gouv.fr> X-Mailer: git-send-email 2.47.3 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - pf-012.whm.fr-par.scw.cloud X-AntiAbuse: Original Domain - vger.kernel.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - oss.cyber.gouv.fr X-Get-Message-Sender-Via: pf-012.whm.fr-par.scw.cloud: authenticated_id: jeremy.jean@oss.cyber.gouv.fr X-Authenticated-Sender: pf-012.whm.fr-par.scw.cloud: jeremy.jean@oss.cyber.gouv.fr X-Source: X-Source-Args: X-Source-Dir: Commit e054bcbe7e7a ("sysctl: move cad_pid into kernel/pid.c") made the global cad_pid target visible through every PID namespace's sysctl table. proc_do_cad_pid() then read that pointer without taking a reference while a concurrent writer could replace it and drop the old struct pid, leaving readers and kill_cad_pid() with a use-after- free window. Keep the sysctl entry in the initial PID namespace only and serialize cad_pid access through get/set helpers that hold a stable struct pid reference for readers. Preserve pid_max registration for child namespaces when CONFIG_PROC_SYSCTL is disabled. Fixes: e054bcbe7e7a ("sysctl: move cad_pid into kernel/pid.c") Assisted-by: Codex:gpt-5 Signed-off-by: J=C3=A9r=C3=A9my Jean --- include/linux/sched/signal.h | 14 +++++++++++++- init/main.c | 3 ++- kernel/pid.c | 16 +++++++++++----- kernel/reboot.c | 29 +++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index 584ae88b435e..f2fc428d32c4 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -562,9 +562,21 @@ static inline sigset_t *sigmask_to_save(void) return res; } =20 +/* + * get_cad_pid() returns a referenced pid. + * set_cad_pid() consumes the caller's reference. + */ +struct pid *get_cad_pid(void); +void set_cad_pid(struct pid *pid); + static inline int kill_cad_pid(int sig, int priv) { - return kill_pid(cad_pid, sig, priv); + struct pid *pid =3D get_cad_pid(); + int ret; + + ret =3D kill_pid(pid, sig, priv); + put_pid(pid); + return ret; } =20 /* These can be the second arg to send_sig_info/send_group_sig_info. */ diff --git a/init/main.c b/init/main.c index e363232b428b..3531a2efb054 100644 --- a/init/main.c +++ b/init/main.c @@ -74,6 +74,7 @@ #include #include #include +#include #include #include #include @@ -1636,7 +1637,7 @@ static noinline void __init kernel_init_freeable(void) */ set_mems_allowed(node_states[N_MEMORY]); =20 - cad_pid =3D get_pid(task_pid(current)); + set_cad_pid(get_pid(task_pid(current))); =20 smp_prepare_cpus(setup_max_cpus); =20 diff --git a/kernel/pid.c b/kernel/pid.c index f55189a3d07d..4a0afd156d2a 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -767,12 +767,14 @@ static struct ctl_table_root pid_table_root =3D { static int proc_do_cad_pid(const struct ctl_table *table, int write, void = *buffer, size_t *lenp, loff_t *ppos) { - struct pid *new_pid; + struct pid *pid, *new_pid; pid_t tmp_pid; int r; struct ctl_table tmp_table =3D *table; =20 - tmp_pid =3D pid_vnr(cad_pid); + pid =3D get_cad_pid(); + tmp_pid =3D pid_vnr(pid); + put_pid(pid); tmp_table.data =3D &tmp_pid; =20 r =3D proc_dointvec(&tmp_table, write, buffer, lenp, ppos); @@ -783,7 +785,7 @@ static int proc_do_cad_pid(const struct ctl_table *tabl= e, int write, void *buffe if (!new_pid) return -ESRCH; =20 - put_pid(xchg(&cad_pid, new_pid)); + set_cad_pid(new_pid); return 0; } =20 @@ -812,10 +814,14 @@ int register_pidns_sysctls(struct pid_namespace *pidn= s) { #ifdef CONFIG_SYSCTL struct ctl_table *tbl; + size_t table_size =3D ARRAY_SIZE(pid_table); + + if (IS_ENABLED(CONFIG_PROC_SYSCTL) && pidns !=3D &init_pid_ns) + table_size--; =20 setup_sysctl_set(&pidns->set, &pid_table_root, set_is_seen); =20 - tbl =3D kmemdup(pid_table, sizeof(pid_table), GFP_KERNEL); + tbl =3D kmemdup(pid_table, table_size * sizeof(*tbl), GFP_KERNEL); if (!tbl) return -ENOMEM; tbl->data =3D &pidns->pid_max; @@ -823,7 +829,7 @@ int register_pidns_sysctls(struct pid_namespace *pidns) PIDS_PER_CPU_DEFAULT * num_possible_cpus())); =20 pidns->sysctls =3D __register_sysctl_table(&pidns->set, "kernel", tbl, - ARRAY_SIZE(pid_table)); + table_size); if (!pidns->sysctls) { kfree(tbl); retire_sysctl_set(&pidns->set); diff --git a/kernel/reboot.c b/kernel/reboot.c index 695c33e75efd..226ac81ecf82 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -26,6 +28,33 @@ static int C_A_D =3D 1; struct pid *cad_pid; EXPORT_SYMBOL(cad_pid); +static DEFINE_SPINLOCK(cad_pid_lock); + +struct pid *get_cad_pid(void) +{ + unsigned long flags; + struct pid *pid; + + spin_lock_irqsave(&cad_pid_lock, flags); + pid =3D get_pid(cad_pid); + spin_unlock_irqrestore(&cad_pid_lock, flags); + return pid; +} +EXPORT_SYMBOL_GPL(get_cad_pid); + +void set_cad_pid(struct pid *pid) +{ + unsigned long flags; + struct pid *old_pid; + + spin_lock_irqsave(&cad_pid_lock, flags); + old_pid =3D cad_pid; + cad_pid =3D pid; + spin_unlock_irqrestore(&cad_pid_lock, flags); + + put_pid(old_pid); +} +EXPORT_SYMBOL_GPL(set_cad_pid); =20 #if defined(CONFIG_ARM) #define DEFAULT_REBOOT_MODE =3D REBOOT_HARD --=20 2.47.3