From nobody Mon Dec 1 22:05:43 2025 Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) (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 6A44630BBB9 for ; Mon, 1 Dec 2025 12:25:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.123 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591913; cv=none; b=Fcu4GyWs3iONVkH57hpqY8PrK/lVjeN6433Ni9CaZtpeU6lvxxBVnFeWfFVkSG+RgwUjhPTkwSxH/4Jq0tNKoSYzyonhDi6t0+aplKadtm1iJ9O3kBNmVg2s8bNtpslNTA/RYgb9TWssCZeMBu8ZsI4DtoGhpQ55I6TwpeJxR4M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764591913; c=relaxed/simple; bh=8MfDex+kidsWNd3urXjWl39OzEr3uA9ecYv97MZfhkQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gMIkX1eUoBKmRyXJcLB1Ve4IMqcMF8p88Esj3a0Hw4BZmTnov+gdk2bGmSEmuZqfqZWYQnguIOm09AHe85holWmDaJ3WV0mJ1BeD4btn8U6dj3seJS96WBqcRwDMfJe+cK9QURBu7xxvnPg4iMFv623+NVYkTHCGxmRtSjH3PkI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (4096-bit key) header.d=canonical.com header.i=@canonical.com header.b=ZAcgWLGX; arc=none smtp.client-ip=185.125.188.123 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (4096-bit key) header.d=canonical.com header.i=@canonical.com header.b="ZAcgWLGX" Received: from mail-ed1-f70.google.com (mail-ed1-f70.google.com [209.85.208.70]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 198EB3F2BA for ; Mon, 1 Dec 2025 12:24:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20251003; t=1764591871; bh=zW8+/HrAO0awxNuy3yAxkVCoMyJbpjCi4GDs+eaZJcc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ZAcgWLGXeyrJn2wSwtmea1SvBrf8p9zSVWaIfGWMJ1PX0FVxJuudtRHDStzdEEwHU oQfHwkvitseiPKbQVmAXOubulDYQpSjJo5EN1xzqlSBWTeVR/7Tom14tG3ekFqlSnc 8Q90oAqvfhF47J64/Ld9EopDADwMlgdVDmZXnBXZXd0UJY0+o6KXZOP0jdouKIThT+ 75jhAldgBj1crQ9QTuTTEcnU3/CJ19vfR39XXVlyYSrp4wEwfp8HeEerE/Rk3z+Suy 9I2Dlchj3acPegB/8hzWfzCorgJJd0sqjXOhAr3sN69hw+hoWz+ZYScPkUN7g/ACj8 LkXBrZFohlALUfD8jQaBEaG+Z+eRfzvd4/YBi+OtroimkXOohCFvQgPmXGZJABQ3zy ECUE7RCas2JVPsSYElEtNU72FycBRHp9i6KL5DNqU/PsXXfBncWTfhLYF13wPDKJJ/ i8dLlzFercmEAqHAcmLuFBCqiog3JDhkeMWaf9bcU0anu75ohm++jcJxqQyaOCwIUk 44i4rElGAMf8Gb5i2zXsCpADe+mXWMEFYjd88dMesD0Oc+frhlHSnOnmSJjXzPj8VY ba1/FnQx3gOK7UIYJUB1yY8kMyXnp1rs7Ez27j1UpF/VnRz1Cms4YX37amCQa2/psO ulJCakfXUOokepEoKgzYDENA= Received: by mail-ed1-f70.google.com with SMTP id 4fb4d7f45d1cf-640cdaf43aeso4819115a12.2 for ; Mon, 01 Dec 2025 04:24:31 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764591867; x=1765196667; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=zW8+/HrAO0awxNuy3yAxkVCoMyJbpjCi4GDs+eaZJcc=; b=fphMh0CsC9Tw4pl9A82jQiqsyR7AHz+0fhQTky8jMvtgu8IUiLULJdgXCI6NTo+Qm2 4GODI37hLhoGoDw5ibcf1/neEHDpFTO3Sj5dudc0/yK/MO39Rhs9AdmoXQ8bzC2t3Vip zD9qy/24KQgGdplL88hdaVjUJl2ERyp81xla8KThK1dq00LW+GQTyAXXIHwB+/6Gq22u 7879FxqZY6aMLuCjUQAnGobbTYBmnUm+ZELHQ0TyDD3F0beOhdgufbJaQR1m+1AceuCp EKbj/yGitTosDG+5jmqxX2jdifBLzZGZMNdZnEN4LzAaWxW7Eh1S34A/Ojiq2jU9U31H Jf0g== X-Forwarded-Encrypted: i=1; AJvYcCWhQAneDuvNhpDiayvWJNvGumb/Z9BtDq8cpoJ/k1pZOSNxLEINu39/PEA6i40JXAIDls4U4hLHRVLV2ZM=@vger.kernel.org X-Gm-Message-State: AOJu0YzdRnQXJEtFl3grQI5zKuDCxY52mHBPUrG7aozRIVhZNFXwPc4z iKI6XEcF/PHnYJXCwQmf0OZo6VgJfjYYeyMA9nfMrVY1ODj0or9MZPE58dGRXFfxETLfoWXthXM OXUAwyT4L8Eyxym2yN+gpX44hZNHNxGhS2eDyNAkyrbIoM66qNRP4zTE9sabXXo81xpkJuKUBTV 6rc5X/ig== X-Gm-Gg: ASbGncu3ZTmLyoLMAYGsWhcVUxVpXVqWyjFh/yPlXHcIiMrp/4Zd5mhtckQ7DsEzlcE hLEsLGiil4jkZWmphjlqAFU5DtqxxIVxTOl5sU7Sd0uMaCL7n6ut6yDTJpBBZCsu2Fd+Xv05yK6 Taclq0awFOHimAtfiz3OOLQy7MZD31/44nDfe44XB2xXCKZi0oo0X8JWPh5xde4SxZrG4rqKce/ LkwyOluosVcRuV6wb5yML6nKtvLdVHY1qLIEaVPFHNIPmH2rfb3KZIY9b5xLYUYH7GEDVr3ZiJw v1iahMf7PrWCfVZl+JnzDg+LxJ7XveBOxPxdsYMWIe0whl1fbAjuw5/Aiw317qnP+xQz6/PiBbb DLxzfR2OxRS2pShGWSInwUAGtnV8vKtdIbMNYX8oNdLUSy3o/5VG9Ka1KkZwICAD+/nwqv/aWaM tvaSY/kh7t6mmdb6YNkR5SwVdd X-Received: by 2002:a05:6402:24cc:b0:640:b814:bb81 with SMTP id 4fb4d7f45d1cf-645546a3c11mr36462569a12.32.1764591866620; Mon, 01 Dec 2025 04:24:26 -0800 (PST) X-Google-Smtp-Source: AGHT+IGN1tIOcPrGnJFOxXrUnXoTJlFWJRG9I1z+01CVFHJKk93OfxDzmlpm1HbJF02rEwstWrU0Vw== X-Received: by 2002:a05:6402:24cc:b0:640:b814:bb81 with SMTP id 4fb4d7f45d1cf-645546a3c11mr36462550a12.32.1764591866178; Mon, 01 Dec 2025 04:24:26 -0800 (PST) Received: from amikhalitsyn.lan (p200300cf5749de007c66abd95f8bdeba.dip0.t-ipconnect.de. [2003:cf:5749:de00:7c66:abd9:5f8b:deba]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-64750a6ea36sm12307884a12.2.2025.12.01.04.24.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 01 Dec 2025 04:24:25 -0800 (PST) From: Alexander Mikhalitsyn To: kees@kernel.org Cc: linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, bpf@vger.kernel.org, Andy Lutomirski , Will Drewry , Jonathan Corbet , Shuah Khan , Tycho Andersen , Andrei Vagin , Christian Brauner , =?UTF-8?q?St=C3=A9phane=20Graber?= , Alexander Mikhalitsyn , Alexander Mikhalitsyn Subject: [PATCH v1 5/6] seccomp: relax has_duplicate_listeners check Date: Mon, 1 Dec 2025 13:24:02 +0100 Message-ID: <20251201122406.105045-6-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251201122406.105045-1-aleksandr.mikhalitsyn@canonical.com> References: <20251201122406.105045-1-aleksandr.mikhalitsyn@canonical.com> 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 Now everything is ready to get rid of "only one listener per tree" limitation. Let's introduce a new uAPI flag SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS, so userspace may explicitly allow nested listeners when installing a listener. Note, that to install n-th listener, this flag must be set on all the listeners up the tree. Cc: linux-doc@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: bpf@vger.kernel.org Cc: Kees Cook Cc: Andy Lutomirski Cc: Will Drewry Cc: Jonathan Corbet Cc: Shuah Khan Cc: Tycho Andersen Cc: Andrei Vagin Cc: Christian Brauner Cc: St=C3=A9phane Graber Signed-off-by: Alexander Mikhalitsyn --- .../userspace-api/seccomp_filter.rst | 6 +++++ include/linux/seccomp.h | 3 ++- include/uapi/linux/seccomp.h | 13 ++++++----- kernel/seccomp.c | 22 +++++++++++++++---- tools/include/uapi/linux/seccomp.h | 13 ++++++----- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Documentation/userspace-api/seccomp_filter.rst b/Documentation= /userspace-api/seccomp_filter.rst index cff0fa7f3175..b9633ab1ed47 100644 --- a/Documentation/userspace-api/seccomp_filter.rst +++ b/Documentation/userspace-api/seccomp_filter.rst @@ -210,6 +210,12 @@ notifications from both tasks will appear on the same = filter fd. Reads and writes to/from a filter fd are also synchronized, so a filter fd can safely have many readers. =20 +By default, only one listener within seccomp filters tree is allowed. On a= ttempt +to add a new listener when one already exists in the filter tree, the +``seccomp()`` call will fail with ``-EBUSY``. To allow multiple listeners,= the +``SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS`` flag can be passed in addit= ion to +the ``SECCOMP_FILTER_FLAG_NEW_LISTENER`` flag. + The interface for a seccomp notification fd consists of two structures: =20 .. code-block:: c diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index 9b959972bf4a..9b060946019d 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -10,7 +10,8 @@ SECCOMP_FILTER_FLAG_SPEC_ALLOW | \ SECCOMP_FILTER_FLAG_NEW_LISTENER | \ SECCOMP_FILTER_FLAG_TSYNC_ESRCH | \ - SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) + SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV | \ + SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS) =20 /* sizeof() the first published struct seccomp_notif_addfd */ #define SECCOMP_NOTIFY_ADDFD_SIZE_VER0 24 diff --git a/include/uapi/linux/seccomp.h b/include/uapi/linux/seccomp.h index dbfc9b37fcae..de78d8e7a70b 100644 --- a/include/uapi/linux/seccomp.h +++ b/include/uapi/linux/seccomp.h @@ -18,13 +18,14 @@ #define SECCOMP_GET_NOTIF_SIZES 3 =20 /* Valid flags for SECCOMP_SET_MODE_FILTER */ -#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) -#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) -#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) -#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3) -#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) +#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) +#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3) +#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) /* Received notifications wait in killable state (only respond to fatal si= gnals) */ -#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5) +#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5) +#define SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS (1UL << 6) =20 /* * All BPF programs must return a 32-bit value. diff --git a/kernel/seccomp.c b/kernel/seccomp.c index ad733f849e0f..348e10d403b1 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -205,6 +205,7 @@ static inline void seccomp_cache_prepare(struct seccomp= _filter *sfilter) * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged * @wait_killable_recv: Put notifying process in killable state once the * notification is received by the userspace listener. + * @allow_nested_listeners: Allow nested seccomp listeners. * @prev: points to a previously installed, or inherited, filter * @prog: the BPF program to evaluate * @notif: the struct that holds all notification related information @@ -226,6 +227,7 @@ struct seccomp_filter { refcount_t users; bool log; bool wait_killable_recv; + bool allow_nested_listeners; struct action_cache cache; struct seccomp_filter *prev; struct bpf_prog *prog; @@ -974,6 +976,10 @@ static long seccomp_attach_filter(unsigned int flags, if (flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) filter->wait_killable_recv =3D true; =20 + /* Set nested listeners allow flag, if present. */ + if (flags & SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS) + filter->allow_nested_listeners =3D true; + /* * If there is an existing filter, make it the prev and don't drop its * task reference. @@ -1955,7 +1961,8 @@ static struct file *init_listener(struct seccomp_filt= er *filter) } =20 /* - * Does @new_child have a listener while an ancestor also has a listener? + * Does @new_child have a listener while an ancestor also has a listener + * and hasn't allowed nesting? * If so, we'll want to reject this filter. * This only has to be tested for the current process, even in the TSYNC c= ase, * because TSYNC installs @child with the same parent on all threads. @@ -1973,7 +1980,12 @@ static bool has_duplicate_listener(struct seccomp_fi= lter *new_child) return false; for (cur =3D current->seccomp.filter; cur; cur =3D cur->prev) { if (cur->notif) - return true; + /* + * We don't need to go up further, because if there is a + * listener with nesting allowed, then all the listeners + * up the tree have allowed nesting as well. + */ + return !cur->allow_nested_listeners; } =20 return false; @@ -2018,10 +2030,12 @@ static long seccomp_set_mode_filter(unsigned int fl= ags, return -EINVAL; =20 /* - * The SECCOMP_FILTER_FLAG_WAIT_KILLABLE_SENT flag doesn't make sense + * The SECCOMP_FILTER_FLAG_WAIT_KILLABLE_SENT and + * SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS flags don't make sense * without the SECCOMP_FILTER_FLAG_NEW_LISTENER flag. */ - if ((flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) && + if (((flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) || + (flags & SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS)) && ((flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) =3D=3D 0)) return -EINVAL; =20 diff --git a/tools/include/uapi/linux/seccomp.h b/tools/include/uapi/linux/= seccomp.h index dbfc9b37fcae..de78d8e7a70b 100644 --- a/tools/include/uapi/linux/seccomp.h +++ b/tools/include/uapi/linux/seccomp.h @@ -18,13 +18,14 @@ #define SECCOMP_GET_NOTIF_SIZES 3 =20 /* Valid flags for SECCOMP_SET_MODE_FILTER */ -#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) -#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) -#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) -#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3) -#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) +#define SECCOMP_FILTER_FLAG_TSYNC (1UL << 0) +#define SECCOMP_FILTER_FLAG_LOG (1UL << 1) +#define SECCOMP_FILTER_FLAG_SPEC_ALLOW (1UL << 2) +#define SECCOMP_FILTER_FLAG_NEW_LISTENER (1UL << 3) +#define SECCOMP_FILTER_FLAG_TSYNC_ESRCH (1UL << 4) /* Received notifications wait in killable state (only respond to fatal si= gnals) */ -#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5) +#define SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV (1UL << 5) +#define SECCOMP_FILTER_FLAG_ALLOW_NESTED_LISTENERS (1UL << 6) =20 /* * All BPF programs must return a 32-bit value. --=20 2.43.0