Skip to content

Commit 0837907

Browse files
committed
bpf: Normalize accessing netfilter ctx fields
BPF netfilter programs are currently not portable across 32-bit and 64-bit systems: within 'struct bpf_nf_ctx' size and offsets vary with system word size; the .is_valid_access() verifier hook rejects u64 loads on 32-bit hosts; and no .convert_ctx_access hook exists to rewrite such loads as u32. Update 'struct bpf_nf_ctx' ptr fields with __bpf_md_ptr() to gain stable sizing and offsets. In nf_is_valid_access() use bpf_ctx_range_ptr() for handling ptr field offsets, and create common bpf_ctx_ptr_size_valid() to check load sizes. Finally, add the verifier hook nf_convert_ctx_access() which rewrites loads according to system ptr size. Before: libbpf: prog 'with_invalid_return_code_test1': BPF program load failed: -EACCES libbpf: prog 'with_invalid_return_code_test1': failed to load: -EACCES libbpf: failed to load object 'verifier_netfilter_retcode' run_subtest:PASS:unexpected_load_success 0 nsec validate_msgs:FAIL:748 expect_msg VERIFIER LOG: ============= Global function with_invalid_return_code_test1() doesn't return scalar. Only those are supported. 0: R1=ctx() R10=fp0 ; asm volatile (" \ @ verifier_netfilter_retcode.c:12 0: (79) r0 = *(u64 *)(r1 +0) invalid bpf_context access off=0 size=8 is_valid_access=nf_is_valid_access processed 1 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 ============= EXPECTED SUBSTR: 'R0 is not a known value' torvalds#534/1 verifier_netfilter_retcode/bpf_exit with invalid return code. test1:FAIL After: torvalds#534/1 verifier_netfilter_retcode/bpf_exit with invalid return code. test1:OK torvalds#534/2 verifier_netfilter_retcode/bpf_exit with valid return code. test2:OK torvalds#534/3 verifier_netfilter_retcode/bpf_exit with valid return code. test3:OK torvalds#534/4 verifier_netfilter_retcode/bpf_exit with invalid return code. test4:OK torvalds#534 verifier_netfilter_retcode:OK Summary: 1/4 PASSED, 0 SKIPPED, 0 FAILED Signed-off-by: Tony Ambardar <[email protected]>
1 parent 13ae5a6 commit 0837907

File tree

2 files changed

+32
-6
lines changed

2 files changed

+32
-6
lines changed

include/net/netfilter/nf_bpf_link.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22

33
struct bpf_nf_ctx {
4-
const struct nf_hook_state *state;
5-
struct sk_buff *skb;
4+
__bpf_md_ptr(const struct nf_hook_state *, state);
5+
__bpf_md_ptr(struct sk_buff *, skb);
66
};
77

88
#if IS_ENABLED(CONFIG_NETFILTER_BPF_LINK)

net/netfilter/nf_bpf_link.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,13 @@ static bool nf_is_valid_access(int off, int size, enum bpf_access_type type,
303303
return false;
304304

305305
switch (off) {
306-
case bpf_ctx_range(struct bpf_nf_ctx, skb):
307-
if (size != sizeof_field(struct bpf_nf_ctx, skb))
306+
case bpf_ctx_range_ptr(struct bpf_nf_ctx, skb):
307+
if (size != sizeof(__u64) && size != sizeof(long))
308308
return false;
309309

310310
return nf_ptr_to_btf_id(info, "sk_buff");
311-
case bpf_ctx_range(struct bpf_nf_ctx, state):
312-
if (size != sizeof_field(struct bpf_nf_ctx, state))
311+
case bpf_ctx_range_ptr(struct bpf_nf_ctx, state):
312+
if (size != sizeof(__u64) && size != sizeof(long))
313313
return false;
314314

315315
return nf_ptr_to_btf_id(info, "nf_hook_state");
@@ -320,6 +320,31 @@ static bool nf_is_valid_access(int off, int size, enum bpf_access_type type,
320320
return false;
321321
}
322322

323+
static u32 nf_convert_ctx_access(enum bpf_access_type type,
324+
const struct bpf_insn *si,
325+
struct bpf_insn *insn_buf,
326+
struct bpf_prog *prog, u32 *target_size)
327+
{
328+
struct bpf_insn *insn = insn_buf;
329+
330+
switch (si->off) {
331+
case offsetof(struct bpf_nf_ctx, state):
332+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_nf_ctx, state),
333+
si->dst_reg, si->src_reg,
334+
offsetof(struct bpf_nf_ctx, state));
335+
break;
336+
case offsetof(struct bpf_nf_ctx, skb):
337+
*insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct bpf_nf_ctx, skb),
338+
si->dst_reg, si->src_reg,
339+
offsetof(struct bpf_nf_ctx, skb));
340+
break;
341+
default:
342+
return false;
343+
}
344+
345+
return insn - insn_buf;
346+
}
347+
323348
static const struct bpf_func_proto *
324349
bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
325350
{
@@ -328,5 +353,6 @@ bpf_nf_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
328353

329354
const struct bpf_verifier_ops netfilter_verifier_ops = {
330355
.is_valid_access = nf_is_valid_access,
356+
.convert_ctx_access = nf_convert_ctx_access,
331357
.get_func_proto = bpf_nf_func_proto,
332358
};

0 commit comments

Comments
 (0)