From nobody Tue Feb 10 07:40:39 2026 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (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 25CCF3148AE for ; Tue, 2 Dec 2025 11:52:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764676354; cv=none; b=MKVsloJEdXR9gsRVSMi+dtAIZ+VjywAfStaswGY40nIwJCb3aw7SBYkglcP1uAF4nIThcisF/VP96aqGPphpKITfUBqMNvsK8CdS38bq99Qkbez2C1QtEV5NmLcfcVXU/XZ04rMHc2Ti2EEAhPbj41DStipjSpdBd00apdxphCQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764676354; c=relaxed/simple; bh=C77QVCaNFi1rF9WKTVN6GD+egWOqsJOFJ8DOWl6QG9I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ohrwMz+s672AnO5wvKzBYVZc7EOmcRO6GYL8VHmDMap+tf86Ny2pT5kxNVuJTe0lHmhZZGCOAUKABc/0ey06AJzaIFHpl7dOoDTcvwOwCvYZjeVP3YduXu1B9hfzdFtg+6JmCoEHlA7gs1TD982QF3+f4oRE5+n3wQL47WzyF20= 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=CVIUNiBa; arc=none smtp.client-ip=185.125.188.122 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="CVIUNiBa" Received: from mail-ej1-f71.google.com (mail-ej1-f71.google.com [209.85.218.71]) (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-0.canonical.com (Postfix) with ESMTPS id 17C013FD47 for ; Tue, 2 Dec 2025 11:52:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20251003; t=1764676345; bh=Axv6vUiwWJhlCZhCOlctIB31d1FHH589LkNbghFTla0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CVIUNiBahbXGR6qqf7QcDtr2WeRZvaE0kEbqmaPs4SY8Ehqqpyfzt+0+/uXuJd7OG u8OWZ+rp50X5GGtUJ0WnaxXOsKvkkaetGaL2+RZldhfJ95hO+KfWUFLnAU8ij3Nv7o au/RFbJSJwydGY0q1B4p2eyiatWUkbR+LpVA5U7oCc7kA2LuCGa/vo4fEVAV3jDiBT L2+4YEorc+ltHSCBwPaBLznEwkTodZoeTG+eQXMGv7kxxVpnNAVDqC+KA5euIPp4bt L6yRaoBaAkFwJEOM8Jvjf2Kj/N8TBmMXZj+1jniXy8NM7i7ScX8eTsbfg6llaDPVpy k7vtrp1W8nDdCrptu4c9vZ62+DRyvUtF/H4aT1s3h3rHfpJQjvGM4autKFQoVJ3Hmh lVtvGaFoSV9uWH3TOkriKLT9cMknF9M6EDTMDf1bYITMiBiTEfMB4V/t1hat87te4n AriFtLbp3NO1kKDGRDdfWFNF/FRiY4vd9Q0MloJ2m822LsuLpe8s1cB97qi5cVhPsv Zjkg2SJZHCYYrdVU3az3hukoXxGy43YOI4Qq0e1a6eSO3FUkiSXfms9Ic32omwgBiW AEt8DQz+oifFv4YvJvmIuD5kk1F8ABzLJOw1MpY/TcLJDWyYD5IZ59iV7DWP4cUGVq 0Loa1SvAhpPjCh099NNlTulg= Received: by mail-ej1-f71.google.com with SMTP id a640c23a62f3a-b73599315adso391150766b.2 for ; Tue, 02 Dec 2025 03:52:25 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764676340; x=1765281140; 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=Axv6vUiwWJhlCZhCOlctIB31d1FHH589LkNbghFTla0=; b=LYIpK9R3M/j8OoqW9mDk9NdvTiex9gVgShEgAD/r6+wCK9ca1Xd84lEYW1rK9+bOvb enJUuZms35sJi/fwFYccxo0S6AAH38RPeOrA7Suyw3zp59+B0P+kV1k3H6iikoMXi7iX DgxKK7fn/dDGuBxxxmFbXizVN6+JhwKuuXdMRu3Bfs/mVjdQsFmadyzvhRVhbpGufqum 0ZfU7N13YrZxb4StR20YCo5CokvXbi9PztgwmvsWcHbkikyUn2dLABueIyzu9SlCHzu9 2Vss9Z5ZPeSRWlKI83brf2HKjHv+R8tHiu9FOABYlvTyNQmAWaK7WZlszMkiz08p4JIR XixQ== X-Forwarded-Encrypted: i=1; AJvYcCVMuq+I7pMPyV8ao3e1s7jC03bKmjzsAMpuN9sFZoHfrHh93+to0rJXIFbq5kfKTZ/CkWSQPGYY7gHK4RQ=@vger.kernel.org X-Gm-Message-State: AOJu0YxAQQ3Ft8Rf2tXUB59DsaSiiQQKEBogFoAIAP0wnYWDjyWiV0wp HPtiKV38tHhEhsT0mOX1lOpzJ9C33wqUoxBFI6dT+kiOMawNaYLmP4ZiWT217JQUuVw13kXm3yP 2E3zew+KGki1urutienxNQrWGrz00P5ubMZvdBIJAvBPy06GYR2OIHSgjWguV1jYZJ0LTXHhkYw TeesfFmw== X-Gm-Gg: ASbGnctbXiiC8+IcLaHVNIIiOkVpQPfOh3YAdfBly3FcrJRmSahOeDKi2WODmmAgmjg 8DgaJuA9H0XrxwmQh/eHmnbTc+KHk2RfP1m1xvsQUiYXynCuDigUPPDPN73H3RzzpXEOlch6jXG e4BcIa7DRyRPysoXAsxm17jxODRMrlxG2SZl0sPQcGC1mKyYKmkVsjDqE1og/IoxemFlz0AYjoE t6fcPlojHavX49drZYO7RlJhuNIkFUzYFEtkl8ZuRbcz6nMtGw6Feu5SvZbIiOU+9uVOMTJFq5Y GYON4MRB94KUDQI8Tg7NuXZhZgkVgOzgFEvmLZjJeCLq4oMbInOUr/C44IvxOXL0Bty3Fba7vOt sldwjuw1RSi7PsbZYstGzL+DLTttY4kxtzItqpHrwSdqszgddSm+wGLIBC9rIoZgz+3e0sX8Pww LYLD84C9qq0vQAf4ItpZwrBXA= X-Received: by 2002:a17:906:c14a:b0:b6d:3a00:983a with SMTP id a640c23a62f3a-b76c551504dmr3315911866b.38.1764676340074; Tue, 02 Dec 2025 03:52:20 -0800 (PST) X-Google-Smtp-Source: AGHT+IEPpx1/rOUbEn0W22PLKyuLu+FnwfRlf+qjfej6kw7xz7j4ARHbtg4setflSyZMmAZJqJtjow== X-Received: by 2002:a17:906:c14a:b0:b6d:3a00:983a with SMTP id a640c23a62f3a-b76c551504dmr3315907366b.38.1764676339489; Tue, 02 Dec 2025 03:52:19 -0800 (PST) Received: from amikhalitsyn.lan (p200300cf5702200011ee99ed0f378a51.dip0.t-ipconnect.de. [2003:cf:5702:2000:11ee:99ed:f37:8a51]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-647510519efsm15206765a12.29.2025.12.02.03.52.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 02 Dec 2025 03:52:19 -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 , Aleksa Sarai , Tycho Andersen , Andrei Vagin , Christian Brauner , =?UTF-8?q?St=C3=A9phane=20Graber?= , Alexander Mikhalitsyn , Alexander Mikhalitsyn Subject: [PATCH v2 5/6] seccomp: relax has_duplicate_listeners check Date: Tue, 2 Dec 2025 12:51:57 +0100 Message-ID: <20251202115200.110646-6-aleksandr.mikhalitsyn@canonical.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251202115200.110646-1-aleksandr.mikhalitsyn@canonical.com> References: <20251202115200.110646-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: Aleksa Sarai 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 262390451ff1..a59276afc5b4 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; @@ -984,6 +986,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. @@ -1972,7 +1978,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. @@ -1990,7 +1997,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; @@ -2035,10 +2047,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