From 4b77208477b17b0b9e9cf9aba01b79740cda1a8d Mon Sep 17 00:00:00 2001
From: Luis Gerhorst <gerhorst@cs.fau.de>
Date: Thu, 21 Dec 2023 17:09:54 +0100
Subject: [PATCH] [DRAFT] bpf: Sysctl for spec. push_stack() with nospec_v1
 (for loxilb)

loxilb needs 64k jmp_seq when inserting nospec_v1 after 8k jmp_seq.

[DRAFT] bpf: No spec. push_stack() after stack_size>limit/8

[DRAFT] bpf: Add sysctl for (spec_v1_)complexity_limit_jmp_seq
---
 include/linux/bpf.h   |  2 ++
 kernel/bpf/syscall.c  | 16 ++++++++++++++++
 kernel/bpf/verifier.c | 10 +++++++---
 3 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 95459e959472..df8a260b1fc4 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -2053,7 +2053,9 @@ static inline bool bpf_allow_uninit_stack(void)
 	return perfmon_capable();
 }
 
+extern int bpf_complexity_limit_jmp_seq;
 extern int bpf_spec_v1;
+extern int bpf_spec_v1_complexity_limit_jmp_seq;
 extern int bpf_spec_v4;
 
 static inline bool bpf_bypass_spec_v1(void)
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index c8ce04d942be..4dfb7f225504 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -58,7 +58,9 @@ static DEFINE_SPINLOCK(link_idr_lock);
 int sysctl_unprivileged_bpf_disabled __read_mostly =
 	IS_BUILTIN(CONFIG_BPF_UNPRIV_DEFAULT_OFF) ? 2 : 0;
 
+int bpf_complexity_limit_jmp_seq = 8192;
 int bpf_spec_v1 = 0;
+int bpf_spec_v1_complexity_limit_jmp_seq = 4096;
 int bpf_spec_v4 = 0;
 
 static const struct bpf_map_ops * const bpf_map_types[] = {
@@ -5484,6 +5486,13 @@ static struct ctl_table bpf_syscall_table[] = {
 		.mode		= 0644,
 		.proc_handler	= bpf_stats_handler,
 	},
+	{
+		.procname	= "bpf_complexity_limit_jmp_seq",
+		.data		= &bpf_complexity_limit_jmp_seq,
+		.maxlen		= sizeof(bpf_complexity_limit_jmp_seq),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 	{
 		.procname	= "bpf_spec_v1",
 		.data		= &bpf_spec_v1,
@@ -5493,6 +5502,13 @@ static struct ctl_table bpf_syscall_table[] = {
 		/* .extra1		= SYSCTL_ZERO, */
 		/* .extra2		= SYSCTL_ONE, */
 	},
+	{
+		.procname	= "bpf_spec_v1_complexity_limit_jmp_seq",
+		.data		= &bpf_spec_v1_complexity_limit_jmp_seq,
+		.maxlen		= sizeof(bpf_spec_v1_complexity_limit_jmp_seq),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
 	{
 		.procname	= "bpf_spec_v4",
 		.data		= &bpf_spec_v4,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index f50d3837914d..043be689adcd 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -178,7 +178,6 @@ struct bpf_verifier_stack_elem {
 	u32 log_pos;
 };
 
-#define BPF_COMPLEXITY_LIMIT_JMP_SEQ	8192
 #define BPF_COMPLEXITY_LIMIT_STATES	64
 
 #define BPF_MAP_KEY_POISON	(1ULL << 63)
@@ -1829,6 +1828,11 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env,
 	struct bpf_verifier_stack_elem *elem;
 	int err;
 
+	if (!env->bypass_spec_v1 && cur->speculative && env->stack_size > bpf_spec_v1_complexity_limit_jmp_seq) {
+		verbose(env, "avoiding spec. push_stack()\n");
+		return NULL;
+	}
+
 	elem = kzalloc(sizeof(struct bpf_verifier_stack_elem), GFP_KERNEL);
 	if (!elem)
 		goto err;
@@ -1843,7 +1847,7 @@ static struct bpf_verifier_state *push_stack(struct bpf_verifier_env *env,
 	if (err)
 		goto err;
 	elem->st.speculative |= speculative;
-	if (env->stack_size > BPF_COMPLEXITY_LIMIT_JMP_SEQ) {
+	if (env->stack_size > bpf_complexity_limit_jmp_seq) {
 		verbose(env, "The sequence of %d jumps is too complex.\n",
 			env->stack_size);
 		goto err;
@@ -2375,7 +2379,7 @@ static struct bpf_verifier_state *push_async_cb(struct bpf_verifier_env *env,
 	elem->log_pos = env->log.end_pos;
 	env->head = elem;
 	env->stack_size++;
-	if (env->stack_size > BPF_COMPLEXITY_LIMIT_JMP_SEQ) {
+	if (env->stack_size > bpf_complexity_limit_jmp_seq) {
 		verbose(env,
 			"The sequence of %d jumps is too complex for async cb.\n",
 			env->stack_size);
-- 
GitLab