Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions include/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,9 @@ void bpf_rb_root_free(const struct btf_field *field, void *rb_root,
u64 bpf_arena_get_kern_vm_start(struct bpf_arena *arena);
u64 bpf_arena_get_user_vm_start(struct bpf_arena *arena);
int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size);
int bpf_map_alloc_id(struct bpf_map *map);
void bpf_map_save_memcg(struct bpf_map *map);
void bpf_map_free(struct bpf_map *map);

struct bpf_offload_dev;
struct bpf_offloaded_map;
Expand Down Expand Up @@ -2775,6 +2778,9 @@ int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file,
int bpf_fd_array_map_lookup_elem(struct bpf_map *map, void *key, u32 *value);
int bpf_fd_htab_map_update_elem(struct bpf_map *map, struct file *map_file,
void *key, void *value, u64 map_flags);
long htab_map_update_elem_in_place(struct bpf_map *map, void *key,
void *value, u64 map_flags,
bool percpu, bool onallcpus);
int bpf_fd_htab_map_lookup_elem(struct bpf_map *map, void *key, u32 *value);

int bpf_get_file_flag(int flags);
Expand Down
45 changes: 45 additions & 0 deletions include/linux/bpf_verifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,30 @@ struct bpf_verifier_state_list {
u32 in_free_list:1;
};

struct bpf_reg_oracle_state {
bool scalar;
bool ptr_not_null;

struct tnum var_off;
s64 smin_value;
s64 smax_value;
u64 umin_value;
u64 umax_value;
s32 s32_min_value;
s32 s32_max_value;
u32 u32_min_value;
u32 u32_max_value;
};

struct bpf_oracle_state {
struct bpf_reg_oracle_state regs[MAX_BPF_REG - 1];
};

struct bpf_oracle_state_list {
struct bpf_oracle_state state;
struct list_head node;
};

struct bpf_loop_inline_state {
unsigned int initialized:1; /* set to true upon first entry */
unsigned int fit_for_inline:1; /* true if callback function is the same
Expand Down Expand Up @@ -551,6 +575,10 @@ struct bpf_insn_aux_data {
};
struct bpf_iarray *jt; /* jump table for gotox or bpf_tailcall call instruction */
struct btf_struct_meta *kptr_struct_meta;
union {
struct list_head *oracle_states;
struct bpf_map *oracle_inner_map;
};
u64 map_key_state; /* constant (32 bit) key tracking for maps */
int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
u32 seen; /* this insn was processed by the verifier at env->pass_cnt */
Expand Down Expand Up @@ -818,6 +846,7 @@ struct bpf_verifier_env {
u32 longest_mark_read_walk;
u32 free_list_size;
u32 explored_states_size;
u32 num_prune_points;
u32 num_backedges;
bpfptr_t fd_array;

Expand Down Expand Up @@ -1060,11 +1089,18 @@ static inline bool insn_is_gotox(struct bpf_insn *insn)
BPF_SRC(insn->code) == BPF_X;
}

static inline struct bpf_insn_aux_data *cur_aux(const struct bpf_verifier_env *env)
{
return &env->insn_aux_data[env->insn_idx];
}

const char *reg_type_str(struct bpf_verifier_env *env, enum bpf_reg_type type);
const char *dynptr_type_str(enum bpf_dynptr_type type);
const char *iter_type_str(const struct btf *btf, u32 btf_id);
const char *iter_state_str(enum bpf_iter_state state);

bool reg_not_null(const struct bpf_reg_state *reg);

void print_verifier_state(struct bpf_verifier_env *env, const struct bpf_verifier_state *vstate,
u32 frameno, bool print_all);
void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_state *vstate,
Expand All @@ -1075,6 +1111,9 @@ int bpf_jmp_offset(struct bpf_insn *insn);
struct bpf_iarray *bpf_insn_successors(struct bpf_verifier_env *env, u32 idx);
void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask);
bool bpf_calls_callback(struct bpf_verifier_env *env, int insn_idx);
struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
const struct bpf_insn *patch, u32 len);
int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map);

int bpf_stack_liveness_init(struct bpf_verifier_env *env);
void bpf_stack_liveness_free(struct bpf_verifier_env *env);
Expand All @@ -1087,4 +1126,10 @@ int bpf_live_stack_query_init(struct bpf_verifier_env *env, struct bpf_verifier_
bool bpf_stack_slot_alive(struct bpf_verifier_env *env, u32 frameno, u32 spi);
void bpf_reset_live_stack_callchain(struct bpf_verifier_env *env);

int save_state_in_oracle(struct bpf_verifier_env *env, int insn_idx);
struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bpf_insn *insn,
int i, int *cnt);
int create_and_populate_oracle_map(struct bpf_verifier_env *env);
void oracle_test(struct bpf_map *oracle_states, u64 *regs);

#endif /* _LINUX_BPF_VERIFIER_H */
3 changes: 3 additions & 0 deletions include/linux/tnum.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ struct tnum tnum_mul(struct tnum a, struct tnum b);
/* Return true if the known bits of both tnums have the same value */
bool tnum_overlap(struct tnum a, struct tnum b);

/* Return true if tnum a matches value b. */
bool tnum_match(struct tnum a, u64 b);

/* Return a tnum representing numbers satisfying both @a and @b */
struct tnum tnum_intersect(struct tnum a, struct tnum b);

Expand Down
10 changes: 10 additions & 0 deletions include/uapi/linux/bpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -1334,6 +1334,16 @@ enum {
#define BPF_PSEUDO_MAP_VALUE 2
#define BPF_PSEUDO_MAP_IDX_VALUE 6

/* Internal only.
* insn[0].dst_reg: 0
* insn[0].src_reg: BPF_PSEUDO_MAP_ORACLE
* insn[0].imm: address of oracle state list
* insn[1].imm: address of oracle state list
* insn[0].off: 0
* insn[1].off: 0
*/
#define BPF_PSEUDO_MAP_ORACLE 7

/* insn[0].src_reg: BPF_PSEUDO_BTF_ID
* insn[0].imm: kernel btd id of VAR
* insn[1].imm: 0
Expand Down
14 changes: 14 additions & 0 deletions kernel/bpf/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,18 @@ config BPF_LSM

If you are unsure how to answer this question, answer N.

config BPF_ORACLE
bool "Enable BPF test oracle"
depends on BPF_SYSCALL
depends on DEBUG_KERNEL
depends on !BPF_JIT_ALWAYS_ON
default n
help
Enable the BPF test oracle to compare concrete runtime values of
registers with their verification-time bounds. This will throw a kernel
warning if the runtime values don't match the expected bounds from the
verifier.

If you are unsure how to answer this question, answer N.

endmenu # "BPF subsystem"
1 change: 1 addition & 0 deletions kernel/bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ obj-$(CONFIG_BPF_SYSCALL) += kmem_cache_iter.o
ifeq ($(CONFIG_DMA_SHARED_BUFFER),y)
obj-$(CONFIG_BPF_SYSCALL) += dmabuf_iter.o
endif
obj-$(CONFIG_BPF_ORACLE) += oracle.o

CFLAGS_REMOVE_percpu_freelist.o = $(CC_FLAGS_FTRACE)
CFLAGS_REMOVE_bpf_lru_list.o = $(CC_FLAGS_FTRACE)
Expand Down
16 changes: 13 additions & 3 deletions kernel/bpf/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ void bpf_prog_kallsyms_del_all(struct bpf_prog *fp)

#ifdef CONFIG_BPF_JIT
/* All BPF JIT sysctl knobs here. */
int bpf_jit_enable __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON);
int bpf_jit_enable __read_mostly = 0;
int bpf_jit_kallsyms __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON);
int bpf_jit_harden __read_mostly;
long bpf_jit_limit __read_mostly;
Expand Down Expand Up @@ -1846,10 +1846,20 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn)
ALU64_MOV_K:
DST = IMM;
CONT;
LD_IMM_DW:
DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32;
LD_IMM_DW: {
u64 address = (u64)(u32)insn[0].imm | ((u64)(u32)insn[1].imm) << 32;

#ifdef CONFIG_BPF_ORACLE
if (insn[0].src_reg == BPF_PSEUDO_MAP_ORACLE) {
oracle_test((struct bpf_map *)address, regs);
insn++;
CONT;
}
#endif
DST = address;
insn++;
CONT;
}
ALU_ARSH_X:
DST = (u64) (u32) (((s32) DST) >> (SRC & 31));
CONT;
Expand Down
3 changes: 2 additions & 1 deletion kernel/bpf/disasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs,
*/
u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD ||
insn->src_reg == BPF_PSEUDO_MAP_VALUE;
insn->src_reg == BPF_PSEUDO_MAP_VALUE ||
insn->src_reg == BPF_PSEUDO_MAP_ORACLE;
char tmp[64];

if (is_ptr && !allow_ptr_leaks)
Expand Down
6 changes: 3 additions & 3 deletions kernel/bpf/hashtab.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,9 +1249,9 @@ static long htab_lru_map_update_elem(struct bpf_map *map, void *key, void *value
return ret;
}

static long htab_map_update_elem_in_place(struct bpf_map *map, void *key,
void *value, u64 map_flags,
bool percpu, bool onallcpus)
long htab_map_update_elem_in_place(struct bpf_map *map, void *key,
void *value, u64 map_flags,
bool percpu, bool onallcpus)
{
struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
struct htab_elem *l_new, *l_old;
Expand Down
Loading
Loading