* [PATCH bpf-next v2 1/8] bpf: Add check_func_arg_reg_off function
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 2/8] bpf: Fix PTR_TO_BTF_ID var_off check Kumar Kartikeya Dwivedi
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Lift the list of register types allowed for having fixed and variable
offsets when passed as helper function arguments into a common helper,
so that they can be reused for kfunc checks in later commits. Keeping a
common helper aids maintainability and allows us to follow the same
consistent rules across helpers and kfuncs. Also, convert check_func_arg
to use this function.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
include/linux/bpf_verifier.h | 3 ++
kernel/bpf/verifier.c | 69 +++++++++++++++++++++---------------
2 files changed, 44 insertions(+), 28 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 7a7be8c057f2..38b24ee8d8c2 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -521,6 +521,9 @@ bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt);
int check_ptr_off_reg(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg, int regno);
+int check_func_arg_reg_off(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg, int regno,
+ enum bpf_arg_type arg_type);
int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
u32 regno);
int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index d7473fee247c..a641e61767b4 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5353,6 +5353,44 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
return 0;
}
+int check_func_arg_reg_off(struct bpf_verifier_env *env,
+ const struct bpf_reg_state *reg, int regno,
+ enum bpf_arg_type arg_type)
+{
+ enum bpf_reg_type type = reg->type;
+ int err;
+
+ switch ((u32)type) {
+ case SCALAR_VALUE:
+ /* Pointer types where reg offset is explicitly allowed: */
+ case PTR_TO_PACKET:
+ case PTR_TO_PACKET_META:
+ case PTR_TO_MAP_KEY:
+ case PTR_TO_MAP_VALUE:
+ case PTR_TO_MEM:
+ case PTR_TO_MEM | MEM_RDONLY:
+ case PTR_TO_MEM | MEM_ALLOC:
+ case PTR_TO_BUF:
+ case PTR_TO_BUF | MEM_RDONLY:
+ case PTR_TO_STACK:
+ /* Some of the argument types nevertheless require a
+ * zero register offset.
+ */
+ if (arg_type == ARG_PTR_TO_ALLOC_MEM)
+ goto force_off_check;
+ break;
+ /* All the rest must be rejected: */
+ default:
+force_off_check:
+ err = __check_ptr_off_reg(env, reg, regno,
+ type == PTR_TO_BTF_ID);
+ if (err < 0)
+ return err;
+ break;
+ }
+ return 0;
+}
+
static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
struct bpf_call_arg_meta *meta,
const struct bpf_func_proto *fn)
@@ -5402,34 +5440,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
if (err)
return err;
- switch ((u32)type) {
- case SCALAR_VALUE:
- /* Pointer types where reg offset is explicitly allowed: */
- case PTR_TO_PACKET:
- case PTR_TO_PACKET_META:
- case PTR_TO_MAP_KEY:
- case PTR_TO_MAP_VALUE:
- case PTR_TO_MEM:
- case PTR_TO_MEM | MEM_RDONLY:
- case PTR_TO_MEM | MEM_ALLOC:
- case PTR_TO_BUF:
- case PTR_TO_BUF | MEM_RDONLY:
- case PTR_TO_STACK:
- /* Some of the argument types nevertheless require a
- * zero register offset.
- */
- if (arg_type == ARG_PTR_TO_ALLOC_MEM)
- goto force_off_check;
- break;
- /* All the rest must be rejected: */
- default:
-force_off_check:
- err = __check_ptr_off_reg(env, reg, regno,
- type == PTR_TO_BTF_ID);
- if (err < 0)
- return err;
- break;
- }
+ err = check_func_arg_reg_off(env, reg, regno, arg_type);
+ if (err)
+ return err;
skip_type_check:
if (reg->ref_obj_id) {
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH bpf-next v2 2/8] bpf: Fix PTR_TO_BTF_ID var_off check
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 1/8] bpf: Add check_func_arg_reg_off function Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 3/8] bpf: Disallow negative offset in check_ptr_off_reg Kumar Kartikeya Dwivedi
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau
When kfunc support was added, check_ctx_reg was called for PTR_TO_CTX
register, but no offset checks were made for PTR_TO_BTF_ID. Only
reg->off was taken into account by btf_struct_ids_match, which protected
against type mismatch due to non-zero reg->off, but when reg->off was
zero, a user could set the variable offset of the register and allow it
to be passed to kfunc, leading to bad pointer being passed into the
kernel.
Fix this by reusing the extracted helper check_func_arg_reg_off from
previous commit, and make one call before checking all supported
register types. Since the list is maintained, any future changes will be
taken into account by updating check_func_arg_reg_off. This function
prevents non-zero var_off to be set for PTR_TO_BTF_ID, but still allows
a fixed non-zero reg->off, which is needed for type matching to work
correctly when using pointer arithmetic.
ARG_DONTCARE is passed as arg_type, since kfunc doesn't support
accepting a ARG_PTR_TO_ALLOC_MEM without relying on size of parameter
type from BTF (in case of pointer), or using a mem, len pair. The
forcing of offset check for ARG_PTR_TO_ALLOC_MEM is done because ringbuf
helpers obtain the size from the header located at the beginning of the
memory region, hence any changes to the original pointer shouldn't be
allowed. In case of kfunc, size is always known, either at verification
time, or using the length parameter, hence this forcing is not required.
Since this check will happen once already for PTR_TO_CTX, remove the
check_ptr_off_reg call inside its block.
Cc: Martin KaFai Lau <kafai@fb.com>
Fixes: e6ac2450d6de ("bpf: Support bpf program calling kernel function")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
kernel/bpf/btf.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index b472cf0c8fdb..7f6a0ae5028b 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -5726,7 +5726,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
const char *func_name, *ref_tname;
const struct btf_type *t, *ref_t;
const struct btf_param *args;
- int ref_regno = 0;
+ int ref_regno = 0, ret;
bool rel = false;
t = btf_type_by_id(btf, func_id);
@@ -5776,6 +5776,11 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
+
+ ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE);
+ if (ret < 0)
+ return ret;
+
if (btf_get_prog_ctx_type(log, btf, t,
env->prog->type, i)) {
/* If function expects ctx type in BTF check that caller
@@ -5787,8 +5792,6 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
i, btf_type_str(t));
return -EINVAL;
}
- if (check_ptr_off_reg(env, reg, regno))
- return -EINVAL;
} else if (is_kfunc && (reg->type == PTR_TO_BTF_ID ||
(reg2btf_ids[base_type(reg->type)] && !type_flag(reg->type)))) {
const struct btf_type *reg_ref_t;
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH bpf-next v2 3/8] bpf: Disallow negative offset in check_ptr_off_reg
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 1/8] bpf: Add check_func_arg_reg_off function Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 2/8] bpf: Fix PTR_TO_BTF_ID var_off check Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 4/8] bpf: Harden register offset checks for release helpers and kfuncs Kumar Kartikeya Dwivedi
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
check_ptr_off_reg only allows fixed offset to be set for PTR_TO_BTF_ID,
where reg->off < 0 doesn't make sense. This would shift the pointer
backwards, and fails later in btf_struct_ids_match or btf_struct_walk
due to out of bounds access (since offset is interpreted as unsigned).
Improve the verifier by rejecting this case by using a better error
message for BPF helpers and kfunc, by putting a check inside the
check_func_arg_reg_off function.
Also, update existing verifier selftests to work with new error string.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
kernel/bpf/verifier.c | 6 ++++++
tools/testing/selftests/bpf/verifier/bounds_deduction.c | 2 +-
tools/testing/selftests/bpf/verifier/ctx.c | 8 ++++----
3 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a641e61767b4..9f12a343bb6e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -3984,6 +3984,12 @@ static int __check_ptr_off_reg(struct bpf_verifier_env *env,
* is only allowed in its original, unmodified form.
*/
+ if (reg->off < 0) {
+ verbose(env, "negative offset %s ptr R%d off=%d disallowed\n",
+ reg_type_str(env, reg->type), regno, reg->off);
+ return -EACCES;
+ }
+
if (!fixed_off_ok && reg->off) {
verbose(env, "dereference of modified %s ptr R%d off=%d disallowed\n",
reg_type_str(env, reg->type), regno, reg->off);
diff --git a/tools/testing/selftests/bpf/verifier/bounds_deduction.c b/tools/testing/selftests/bpf/verifier/bounds_deduction.c
index 91869aea6d64..3931c481e30c 100644
--- a/tools/testing/selftests/bpf/verifier/bounds_deduction.c
+++ b/tools/testing/selftests/bpf/verifier/bounds_deduction.c
@@ -105,7 +105,7 @@
BPF_EXIT_INSN(),
},
.errstr_unpriv = "R1 has pointer with unsupported alu operation",
- .errstr = "dereference of modified ctx ptr",
+ .errstr = "negative offset ctx ptr R1 off=-1 disallowed",
.result = REJECT,
.flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
},
diff --git a/tools/testing/selftests/bpf/verifier/ctx.c b/tools/testing/selftests/bpf/verifier/ctx.c
index 23080862aafd..e47a001c2bcd 100644
--- a/tools/testing/selftests/bpf/verifier/ctx.c
+++ b/tools/testing/selftests/bpf/verifier/ctx.c
@@ -58,7 +58,7 @@
},
.prog_type = BPF_PROG_TYPE_SCHED_CLS,
.result = REJECT,
- .errstr = "dereference of modified ctx ptr",
+ .errstr = "negative offset ctx ptr R1 off=-612 disallowed",
},
{
"pass modified ctx pointer to helper, 2",
@@ -71,8 +71,8 @@
},
.result_unpriv = REJECT,
.result = REJECT,
- .errstr_unpriv = "dereference of modified ctx ptr",
- .errstr = "dereference of modified ctx ptr",
+ .errstr_unpriv = "negative offset ctx ptr R1 off=-612 disallowed",
+ .errstr = "negative offset ctx ptr R1 off=-612 disallowed",
},
{
"pass modified ctx pointer to helper, 3",
@@ -141,7 +141,7 @@
.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
.expected_attach_type = BPF_CGROUP_UDP6_SENDMSG,
.result = REJECT,
- .errstr = "dereference of modified ctx ptr",
+ .errstr = "negative offset ctx ptr R1 off=-612 disallowed",
},
{
"pass ctx or null check, 5: null (connect)",
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH bpf-next v2 4/8] bpf: Harden register offset checks for release helpers and kfuncs
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
` (2 preceding siblings ...)
2022-03-03 4:50 ` [PATCH bpf-next v2 3/8] bpf: Disallow negative offset in check_ptr_off_reg Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 5/8] compiler-clang.h: Add __diag infrastructure for clang Kumar Kartikeya Dwivedi
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Let's ensure that the PTR_TO_BTF_ID reg being passed in to release BPF
helpers and kfuncs always has its offset set to 0. While not a real
problem now, there's a very real possibility this will become a problem
when more and more kfuncs are exposed, and more BPF helpers are added
which can release PTR_TO_BTF_ID.
Previous commits already protected against non-zero var_off. One of the
case we are concerned about now is when we have a type that can be
returned by e.g. an acquire kfunc:
struct foo {
int a;
int b;
struct bar b;
};
... and struct bar is also a type that can be returned by another
acquire kfunc.
Then, doing the following sequence:
struct foo *f = bpf_get_foo(); // acquire kfunc
if (!f)
return 0;
bpf_put_bar(&f->b); // release kfunc
... would work with the current code, since the btf_struct_ids_match
takes reg->off into account for matching pointer type with release kfunc
argument type, but would obviously be incorrect, and most likely lead to
a kernel crash. A test has been included later to prevent regressions in
this area.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
include/linux/bpf_verifier.h | 3 ++-
kernel/bpf/btf.c | 13 +++++++++----
kernel/bpf/verifier.c | 27 +++++++++++++++++++++++----
3 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 38b24ee8d8c2..7a684050495a 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -523,7 +523,8 @@ int check_ptr_off_reg(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg, int regno);
int check_func_arg_reg_off(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg, int regno,
- enum bpf_arg_type arg_type);
+ enum bpf_arg_type arg_type,
+ bool is_release_function);
int check_kfunc_mem_size_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
u32 regno);
int check_mem_reg(struct bpf_verifier_env *env, struct bpf_reg_state *reg,
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 7f6a0ae5028b..c9a1019dc60d 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -5753,6 +5753,9 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
return -EINVAL;
}
+ if (is_kfunc)
+ rel = btf_kfunc_id_set_contains(btf, resolve_prog_type(env->prog),
+ BTF_KFUNC_TYPE_RELEASE, func_id);
/* check that BTF function arguments match actual types that the
* verifier sees.
*/
@@ -5777,7 +5780,7 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
ref_t = btf_type_skip_modifiers(btf, t->type, &ref_id);
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
- ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE);
+ ret = check_func_arg_reg_off(env, reg, regno, ARG_DONTCARE, rel);
if (ret < 0)
return ret;
@@ -5809,7 +5812,11 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
if (reg->type == PTR_TO_BTF_ID) {
reg_btf = reg->btf;
reg_ref_id = reg->btf_id;
- /* Ensure only one argument is referenced PTR_TO_BTF_ID */
+ /* Ensure only one argument is referenced
+ * PTR_TO_BTF_ID, check_func_arg_reg_off relies
+ * on only one referenced register being allowed
+ * for kfuncs.
+ */
if (reg->ref_obj_id) {
if (ref_obj_id) {
bpf_log(log, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n",
@@ -5892,8 +5899,6 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env,
/* Either both are set, or neither */
WARN_ON_ONCE((ref_obj_id && !ref_regno) || (!ref_obj_id && ref_regno));
if (is_kfunc) {
- rel = btf_kfunc_id_set_contains(btf, resolve_prog_type(env->prog),
- BTF_KFUNC_TYPE_RELEASE, func_id);
/* We already made sure ref_obj_id is set only for one argument */
if (rel && !ref_obj_id) {
bpf_log(log, "release kernel function %s expects refcounted PTR_TO_BTF_ID\n",
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 9f12a343bb6e..1cf18061f402 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -5361,11 +5361,28 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
int check_func_arg_reg_off(struct bpf_verifier_env *env,
const struct bpf_reg_state *reg, int regno,
- enum bpf_arg_type arg_type)
+ enum bpf_arg_type arg_type,
+ bool is_release_func)
{
enum bpf_reg_type type = reg->type;
+ bool fixed_off_ok = false;
int err;
+ /* When referenced PTR_TO_BTF_ID is passed to release function, it's
+ * fixed offset must be 0. We rely on the property that only one
+ * referenced register can be passed to BPF helpers and kfuncs.
+ */
+ if (type == PTR_TO_BTF_ID) {
+ bool release_reg = is_release_func && reg->ref_obj_id;
+
+ if (release_reg && reg->off) {
+ verbose(env, "R%d must have zero offset when passed to release func\n",
+ regno);
+ return -EINVAL;
+ }
+ fixed_off_ok = release_reg ? false : true;
+ }
+
switch ((u32)type) {
case SCALAR_VALUE:
/* Pointer types where reg offset is explicitly allowed: */
@@ -5388,8 +5405,7 @@ int check_func_arg_reg_off(struct bpf_verifier_env *env,
/* All the rest must be rejected: */
default:
force_off_check:
- err = __check_ptr_off_reg(env, reg, regno,
- type == PTR_TO_BTF_ID);
+ err = __check_ptr_off_reg(env, reg, regno, fixed_off_ok);
if (err < 0)
return err;
break;
@@ -5446,11 +5462,14 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
if (err)
return err;
- err = check_func_arg_reg_off(env, reg, regno, arg_type);
+ err = check_func_arg_reg_off(env, reg, regno, arg_type, is_release_function(meta->func_id));
if (err)
return err;
skip_type_check:
+ /* check_func_arg_reg_off relies on only one referenced register being
+ * allowed for BPF helpers.
+ */
if (reg->ref_obj_id) {
if (meta->ref_obj_id) {
verbose(env, "verifier internal error: more than one arg with ref_obj_id R%d %u %u\n",
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH bpf-next v2 5/8] compiler-clang.h: Add __diag infrastructure for clang
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
` (3 preceding siblings ...)
2022-03-03 4:50 ` [PATCH bpf-next v2 4/8] bpf: Harden register offset checks for release helpers and kfuncs Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
2022-03-03 18:14 ` Nathan Chancellor
2022-03-03 4:50 ` [PATCH bpf-next v2 6/8] compiler_types.h: Add unified __diag_ignore_all for GCC/LLVM Kumar Kartikeya Dwivedi
` (2 subsequent siblings)
7 siblings, 1 reply; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf
Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Nathan Chancellor, Nick Desaulniers, llvm
From: Nathan Chancellor <nathan@kernel.org>
Add __diag macros similar to those in compiler-gcc.h, so that warnings
that need to be adjusted for specific cases but not globally can be
ignored for LLVM compilation mode as well.
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <ndesaulniers@google.com>
Cc: llvm@lists.linux.dev
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
---
include/linux/compiler-clang.h | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h
index 3c4de9b6c6e3..f1aa41d520bd 100644
--- a/include/linux/compiler-clang.h
+++ b/include/linux/compiler-clang.h
@@ -68,3 +68,25 @@
#define __nocfi __attribute__((__no_sanitize__("cfi")))
#define __cficanonical __attribute__((__cfi_canonical_jump_table__))
+
+/*
+ * Turn individual warnings and errors on and off locally, depending
+ * on version.
+ */
+#define __diag_clang(version, severity, s) \
+ __diag_clang_ ## version(__diag_clang_ ## severity s)
+
+/* Severity used in pragma directives */
+#define __diag_clang_ignore ignored
+#define __diag_clang_warn warning
+#define __diag_clang_error error
+
+#define __diag_str1(s) #s
+#define __diag_str(s) __diag_str1(s)
+#define __diag(s) _Pragma(__diag_str(clang diagnostic s))
+
+#if CONFIG_CLANG_VERSION >= 110000
+#define __diag_clang_11(s) __diag(s)
+#else
+#define __diag_clang_11(s)
+#endif
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH bpf-next v2 5/8] compiler-clang.h: Add __diag infrastructure for clang
2022-03-03 4:50 ` [PATCH bpf-next v2 5/8] compiler-clang.h: Add __diag infrastructure for clang Kumar Kartikeya Dwivedi
@ 2022-03-03 18:14 ` Nathan Chancellor
0 siblings, 0 replies; 10+ messages in thread
From: Nathan Chancellor @ 2022-03-03 18:14 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: bpf, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Nick Desaulniers, llvm
Hi Kumar,
Thanks for sending this along!
On Thu, Mar 03, 2022 at 10:20:26AM +0530, Kumar Kartikeya Dwivedi wrote:
> From: Nathan Chancellor <nathan@kernel.org>
>
> Add __diag macros similar to those in compiler-gcc.h, so that warnings
> that need to be adjusted for specific cases but not globally can be
> ignored for LLVM compilation mode as well.
I would word this last sentence as:
"ignored when building with clang."
Technically speaking, LLVM is not the one emitting the warnings, clang
is :) this is useful with LLVM=1 or CC=clang.
> Cc: Nathan Chancellor <nathan@kernel.org>
> Cc: Nick Desaulniers <ndesaulniers@google.com>
> Cc: llvm@lists.linux.dev
> Signed-off-by: Nathan Chancellor <nathan@kernel.org>
You should add your signed-off-by here to notate that you have touched
the patch per Documentation/process/submitting-patches.rst. It is also
courteous to note that you wrote the commit message, something along the
lines of:
"[Kumar: Wrote commit message]
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>"
Regardless, this looks good to me with the context of the other two
patches:
https://lore.kernel.org/r/20220303045029.2645297-7-memxor@gmail.com/
https://lore.kernel.org/r/20220303045029.2645297-8-memxor@gmail.com/
Cheers,
Nathan
> ---
> include/linux/compiler-clang.h | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h
> index 3c4de9b6c6e3..f1aa41d520bd 100644
> --- a/include/linux/compiler-clang.h
> +++ b/include/linux/compiler-clang.h
> @@ -68,3 +68,25 @@
>
> #define __nocfi __attribute__((__no_sanitize__("cfi")))
> #define __cficanonical __attribute__((__cfi_canonical_jump_table__))
> +
> +/*
> + * Turn individual warnings and errors on and off locally, depending
> + * on version.
> + */
> +#define __diag_clang(version, severity, s) \
> + __diag_clang_ ## version(__diag_clang_ ## severity s)
> +
> +/* Severity used in pragma directives */
> +#define __diag_clang_ignore ignored
> +#define __diag_clang_warn warning
> +#define __diag_clang_error error
> +
> +#define __diag_str1(s) #s
> +#define __diag_str(s) __diag_str1(s)
> +#define __diag(s) _Pragma(__diag_str(clang diagnostic s))
> +
> +#if CONFIG_CLANG_VERSION >= 110000
> +#define __diag_clang_11(s) __diag(s)
> +#else
> +#define __diag_clang_11(s)
> +#endif
> --
> 2.35.1
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH bpf-next v2 6/8] compiler_types.h: Add unified __diag_ignore_all for GCC/LLVM
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
` (4 preceding siblings ...)
2022-03-03 4:50 ` [PATCH bpf-next v2 5/8] compiler-clang.h: Add __diag infrastructure for clang Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 7/8] bpf: Replace __diag_ignore with unified __diag_ignore_all Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 8/8] selftests/bpf: Add tests for kfunc register offset checks Kumar Kartikeya Dwivedi
7 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
linux-kernel
Add a __diag_ignore_all macro, to ignore warnings for both GCC and LLVM,
without having to specify the compiler type and version. By default, GCC
8 and clang 11 are used. This will be used by bpf subsystem to ignore
-Wmissing-prototypes warning for functions that are meant to be global
functions so that they are in vmlinux BTF, but don't have a prototype.
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
include/linux/compiler-clang.h | 3 +++
include/linux/compiler-gcc.h | 3 +++
include/linux/compiler_types.h | 4 ++++
3 files changed, 10 insertions(+)
diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h
index f1aa41d520bd..babb1347148c 100644
--- a/include/linux/compiler-clang.h
+++ b/include/linux/compiler-clang.h
@@ -90,3 +90,6 @@
#else
#define __diag_clang_11(s)
#endif
+
+#define __diag_ignore_all(option, comment) \
+ __diag_clang(11, ignore, option)
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index ccbbd31b3aae..d364c98a4a80 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -151,6 +151,9 @@
#define __diag_GCC_8(s)
#endif
+#define __diag_ignore_all(option, comment) \
+ __diag_GCC(8, ignore, option)
+
/*
* Prior to 9.1, -Wno-alloc-size-larger-than (and therefore the "alloc_size"
* attribute) do not work, and must be disabled.
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index 3f31ff400432..8e5d2f50f951 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -371,4 +371,8 @@ struct ftrace_likely_data {
#define __diag_error(compiler, version, option, comment) \
__diag_ ## compiler(version, error, option)
+#ifndef __diag_ignore_all
+#define __diag_ignore_all(option, comment)
+#endif
+
#endif /* __LINUX_COMPILER_TYPES_H */
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH bpf-next v2 7/8] bpf: Replace __diag_ignore with unified __diag_ignore_all
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
` (5 preceding siblings ...)
2022-03-03 4:50 ` [PATCH bpf-next v2 6/8] compiler_types.h: Add unified __diag_ignore_all for GCC/LLVM Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
2022-03-03 4:50 ` [PATCH bpf-next v2 8/8] selftests/bpf: Add tests for kfunc register offset checks Kumar Kartikeya Dwivedi
7 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
netfilter-devel
Currently, -Wmissing-prototypes warning is ignored for GCC, but not
clang. This leads to clang builds warning on W=1 mode. Since the flag
used by both compilers is same, we can use the unified __diag_ignore_all
macro that works for all supported versions and compilers which have
__diag macro support (currently GCC >= 8.0, and Clang >= 11.0).
Also add nf_conntrack_bpf.h include to prevent missing prototype warning
for register_nf_conntrack_bpf.
Cc: netfilter-devel@vger.kernel.org
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
net/bpf/test_run.c | 4 ++--
net/netfilter/nf_conntrack_bpf.c | 5 +++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index eb129e48f90b..fcc83017cd03 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -201,8 +201,8 @@ static int bpf_test_finish(const union bpf_attr *kattr,
* future.
*/
__diag_push();
-__diag_ignore(GCC, 8, "-Wmissing-prototypes",
- "Global functions as their definitions will be in vmlinux BTF");
+__diag_ignore_all("-Wmissing-prototypes",
+ "Global functions as their definitions will be in vmlinux BTF");
int noinline bpf_fentry_test1(int a)
{
return a + 1;
diff --git a/net/netfilter/nf_conntrack_bpf.c b/net/netfilter/nf_conntrack_bpf.c
index 8ad3f52579f3..fe98673dd5ac 100644
--- a/net/netfilter/nf_conntrack_bpf.c
+++ b/net/netfilter/nf_conntrack_bpf.c
@@ -12,6 +12,7 @@
#include <linux/btf_ids.h>
#include <linux/net_namespace.h>
#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_conntrack_bpf.h>
#include <net/netfilter/nf_conntrack_core.h>
/* bpf_ct_opts - Options for CT lookup helpers
@@ -102,8 +103,8 @@ static struct nf_conn *__bpf_nf_ct_lookup(struct net *net,
}
__diag_push();
-__diag_ignore(GCC, 8, "-Wmissing-prototypes",
- "Global functions as their definitions will be in nf_conntrack BTF");
+__diag_ignore_all("-Wmissing-prototypes",
+ "Global functions as their definitions will be in nf_conntrack BTF");
/* bpf_xdp_ct_lookup - Lookup CT entry for the given tuple, and acquire a
* reference to it
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH bpf-next v2 8/8] selftests/bpf: Add tests for kfunc register offset checks
2022-03-03 4:50 [PATCH bpf-next v2 0/8] Fixes for bad PTR_TO_BTF_ID offset Kumar Kartikeya Dwivedi
` (6 preceding siblings ...)
2022-03-03 4:50 ` [PATCH bpf-next v2 7/8] bpf: Replace __diag_ignore with unified __diag_ignore_all Kumar Kartikeya Dwivedi
@ 2022-03-03 4:50 ` Kumar Kartikeya Dwivedi
7 siblings, 0 replies; 10+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2022-03-03 4:50 UTC (permalink / raw)
To: bpf; +Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
Include a few verifier selftests that test against the problems being
fixed by previous commits, i.e. release kfunc always require
PTR_TO_BTF_ID fixed and var_off to be 0, and negative offset is not
permitted and returns a helpful error message.
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
net/bpf/test_run.c | 11 +++
tools/testing/selftests/bpf/verifier/calls.c | 83 ++++++++++++++++++++
2 files changed, 94 insertions(+)
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index fcc83017cd03..ba410b069824 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -270,9 +270,14 @@ struct sock * noinline bpf_kfunc_call_test3(struct sock *sk)
return sk;
}
+struct prog_test_member {
+ u64 c;
+};
+
struct prog_test_ref_kfunc {
int a;
int b;
+ struct prog_test_member memb;
struct prog_test_ref_kfunc *next;
};
@@ -295,6 +300,10 @@ noinline void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p)
{
}
+noinline void bpf_kfunc_call_memb_release(struct prog_test_member *p)
+{
+}
+
struct prog_test_pass1 {
int x0;
struct {
@@ -379,6 +388,7 @@ BTF_ID(func, bpf_kfunc_call_test2)
BTF_ID(func, bpf_kfunc_call_test3)
BTF_ID(func, bpf_kfunc_call_test_acquire)
BTF_ID(func, bpf_kfunc_call_test_release)
+BTF_ID(func, bpf_kfunc_call_memb_release)
BTF_ID(func, bpf_kfunc_call_test_pass_ctx)
BTF_ID(func, bpf_kfunc_call_test_pass1)
BTF_ID(func, bpf_kfunc_call_test_pass2)
@@ -396,6 +406,7 @@ BTF_SET_END(test_sk_acquire_kfunc_ids)
BTF_SET_START(test_sk_release_kfunc_ids)
BTF_ID(func, bpf_kfunc_call_test_release)
+BTF_ID(func, bpf_kfunc_call_memb_release)
BTF_SET_END(test_sk_release_kfunc_ids)
BTF_SET_START(test_sk_ret_null_kfunc_ids)
diff --git a/tools/testing/selftests/bpf/verifier/calls.c b/tools/testing/selftests/bpf/verifier/calls.c
index 0a8ea60c2a80..7bc077198033 100644
--- a/tools/testing/selftests/bpf/verifier/calls.c
+++ b/tools/testing/selftests/bpf/verifier/calls.c
@@ -115,6 +115,89 @@
{ "bpf_kfunc_call_test_release", 5 },
},
},
+{
+ "calls: invalid kfunc call: reg->off must be zero when passed to release kfunc",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+ BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+ BPF_EXIT_INSN(),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+ .result = REJECT,
+ .errstr = "R1 must have zero offset when passed to release func",
+ .fixup_kfunc_btf_id = {
+ { "bpf_kfunc_call_test_acquire", 3 },
+ { "bpf_kfunc_call_memb_release", 8 },
+ },
+},
+{
+ "calls: invalid kfunc call: PTR_TO_BTF_ID with negative offset",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+ BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+ BPF_EXIT_INSN(),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_LDX_MEM(BPF_DW, BPF_REG_1, BPF_REG_1, 16),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -4),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+ .fixup_kfunc_btf_id = {
+ { "bpf_kfunc_call_test_acquire", 3 },
+ { "bpf_kfunc_call_test_release", 9 },
+ },
+ .result_unpriv = REJECT,
+ .result = REJECT,
+ .errstr = "negative offset ptr_ ptr R1 off=-4 disallowed",
+},
+{
+ "calls: invalid kfunc call: PTR_TO_BTF_ID with variable offset",
+ .insns = {
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_10),
+ BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8),
+ BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 0),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+ BPF_EXIT_INSN(),
+ BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),
+ BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_0, 4),
+ BPF_JMP_IMM(BPF_JLE, BPF_REG_2, 4, 3),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ BPF_JMP_IMM(BPF_JGE, BPF_REG_2, 0, 3),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
+ BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, BPF_PSEUDO_KFUNC_CALL, 0, 0),
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ },
+ .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+ .fixup_kfunc_btf_id = {
+ { "bpf_kfunc_call_test_acquire", 3 },
+ { "bpf_kfunc_call_test_release", 9 },
+ { "bpf_kfunc_call_test_release", 13 },
+ { "bpf_kfunc_call_test_release", 17 },
+ },
+ .result_unpriv = REJECT,
+ .result = REJECT,
+ .errstr = "variable ptr_ access var_off=(0x0; 0x7) disallowed",
+},
{
"calls: basic sanity",
.insns = {
--
2.35.1
^ permalink raw reply related [flat|nested] 10+ messages in thread