We need to limit number of listeners in seccomp tree to
MAX_LISTENERS_PER_PATH, because we don't want to use dynamic
memory allocations in a very hot __seccomp_filter() function
and we use preallocated static array on the stack.
Also, let's return ELOOP to userspace if it attempts to install
more than MAX_LISTENERS_PER_PATH listeners, instead of ENOMEM as
we do when userspace hits the limit of cBPF instructions.
This will make uAPI a bit more convenient.
Notice, that has_duplicate_listener() check is still in place, so this
change is a preparational.
Cc: linux-kernel@vger.kernel.org
Cc: bpf@vger.kernel.org
Cc: Kees Cook <kees@kernel.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Will Drewry <wad@chromium.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Tycho Andersen <tycho@tycho.pizza>
Cc: Andrei Vagin <avagin@gmail.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Stéphane Graber <stgraber@stgraber.org>
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com>
---
kernel/seccomp.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index c9a1062a53bd..ded3f6a6430b 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -931,17 +931,25 @@ static long seccomp_attach_filter(unsigned int flags,
struct seccomp_filter *filter)
{
unsigned long total_insns;
+ unsigned char total_listeners;
struct seccomp_filter *walker;
assert_spin_locked(¤t->sighand->siglock);
- /* Validate resulting filter length. */
+ /* Validate resulting filter length and number of nested listeners. */
total_insns = filter->prog->len;
- for (walker = current->seccomp.filter; walker; walker = walker->prev)
+ total_listeners = filter->notif ? 1 : 0;
+ for (walker = current->seccomp.filter; walker; walker = walker->prev) {
total_insns += walker->prog->len + 4; /* 4 instr penalty */
+ total_listeners += walker->notif ? 1 : 0;
+ }
+
if (total_insns > MAX_INSNS_PER_PATH)
return -ENOMEM;
+ if (total_listeners > MAX_LISTENERS_PER_PATH)
+ return -ELOOP;
+
/* If thread sync has been requested, check that it is possible. */
if (flags & SECCOMP_FILTER_FLAG_TSYNC) {
int ret;
--
2.43.0