Skip to content

Commit cdb52e6

Browse files
pchaignoKernel Patches Daemon
authored andcommitted
bpf: Create inner oracle maps
This patch creates the inner oracle maps that will store the information on verifier states. Each pruning point needs an inner oracle map. They are called inner because they will all be referred by a hashmap in a later commit, indexed by instruction indexes. They are also referred in the oracle instructions, for easier lookup from the interpreter. For the inner maps, we can rely on array maps because at the time we create them we know how many states will need to be saved. They won't grow after program loading so they can have a static size. These maps are not only useful for the oracle to iterate through states, but also for debugging from userspace after we hit an oracle test warning. Userspace should however never need to update them, so let's limit permissions accordingly. The bytecode ends up looking like: 0: (bf) r2 = r10 1: (7a) *(u64 *)(r2 -40) = -44 2: (79) r6 = *(u64 *)(r2 -40) 3: (85) call bpf_user_rnd_u32#28800 4: (18) r0 = oracle_map[id:21] 6: (b7) r0 = 0 7: (95) exit with our special instruction at index 4. A subsequent patch teaches the interpreter to skip this special instruction at runtime, to avoid overwriting R0. Signed-off-by: Paul Chaignon <[email protected]>
1 parent 94df226 commit cdb52e6

File tree

5 files changed

+76
-7
lines changed

5 files changed

+76
-7
lines changed

include/linux/bpf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,9 @@ void bpf_rb_root_free(const struct btf_field *field, void *rb_root,
617617
u64 bpf_arena_get_kern_vm_start(struct bpf_arena *arena);
618618
u64 bpf_arena_get_user_vm_start(struct bpf_arena *arena);
619619
int bpf_obj_name_cpy(char *dst, const char *src, unsigned int size);
620+
int bpf_map_alloc_id(struct bpf_map *map);
621+
void bpf_map_save_memcg(struct bpf_map *map);
622+
void bpf_map_free(struct bpf_map *map);
620623

621624
struct bpf_offload_dev;
622625
struct bpf_offloaded_map;

include/linux/bpf_verifier.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,10 @@ struct bpf_insn_aux_data {
575575
};
576576
struct bpf_iarray *jt; /* jump table for gotox or bpf_tailcall call instruction */
577577
struct btf_struct_meta *kptr_struct_meta;
578-
struct list_head *oracle_states;
578+
union {
579+
struct list_head *oracle_states;
580+
struct bpf_map *oracle_inner_map;
581+
};
579582
u64 map_key_state; /* constant (32 bit) key tracking for maps */
580583
int ctx_field_size; /* the ctx field size for load insn, maybe 0 */
581584
u32 seen; /* this insn was processed by the verifier at env->pass_cnt */
@@ -1109,6 +1112,7 @@ void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask);
11091112
bool bpf_calls_callback(struct bpf_verifier_env *env, int insn_idx);
11101113
struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
11111114
const struct bpf_insn *patch, u32 len);
1115+
int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map);
11121116

11131117
int bpf_stack_liveness_init(struct bpf_verifier_env *env);
11141118
void bpf_stack_liveness_free(struct bpf_verifier_env *env);

kernel/bpf/oracle.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,53 @@ int save_state_in_oracle(struct bpf_verifier_env *env, int insn_idx)
6262
return 0;
6363
}
6464

65+
static struct bpf_map *create_inner_oracle_map(size_t size)
66+
{
67+
struct bpf_map *map;
68+
int err;
69+
70+
union bpf_attr map_attr = {
71+
.map_type = BPF_MAP_TYPE_ARRAY,
72+
.key_size = sizeof(__u32),
73+
.value_size = sizeof(struct bpf_oracle_state),
74+
.max_entries = size,
75+
.map_flags = BPF_F_INNER_MAP | BPF_F_RDONLY,
76+
.map_name = "oracle_inner",
77+
};
78+
map = array_map_ops.map_alloc(&map_attr);
79+
if (IS_ERR(map))
80+
return map;
81+
82+
map->ops = &array_map_ops;
83+
map->map_type = BPF_MAP_TYPE_ARRAY;
84+
85+
err = bpf_obj_name_cpy(map->name, map_attr.map_name,
86+
sizeof(map_attr.map_name));
87+
if (err < 0)
88+
goto free_map;
89+
90+
mutex_init(&map->freeze_mutex);
91+
spin_lock_init(&map->owner_lock);
92+
93+
err = security_bpf_map_create(map, &map_attr, NULL, false);
94+
if (err)
95+
goto free_map_sec;
96+
97+
err = bpf_map_alloc_id(map);
98+
if (err)
99+
goto free_map_sec;
100+
101+
bpf_map_save_memcg(map);
102+
103+
return map;
104+
105+
free_map_sec:
106+
security_bpf_map_free(map);
107+
free_map:
108+
bpf_map_free(map);
109+
return ERR_PTR(err);
110+
}
111+
65112
struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bpf_insn *insn,
66113
int i, int *cnt)
67114
{
@@ -72,7 +119,8 @@ struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bp
72119
struct list_head *head = aux->oracle_states;
73120
struct bpf_insn *insn_buf = env->insn_buf;
74121
struct bpf_prog *new_prog = env->prog;
75-
int num_oracle_states;
122+
int num_oracle_states, err;
123+
struct bpf_map *inner_map;
76124

77125
if (env->subprog_cnt > 1)
78126
/* Skip the oracle if subprogs are used. */
@@ -82,6 +130,12 @@ struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bp
82130
if (!num_oracle_states)
83131
goto noop;
84132

133+
inner_map = create_inner_oracle_map(num_oracle_states);
134+
if (IS_ERR(inner_map))
135+
return (void *)inner_map;
136+
137+
ld_addrs[0].imm = (u32)(u64)inner_map;
138+
ld_addrs[1].imm = ((u64)inner_map) >> 32;
85139
insn_buf[0] = ld_addrs[0];
86140
insn_buf[1] = ld_addrs[1];
87141
insn_buf[2] = *insn;
@@ -91,6 +145,14 @@ struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bp
91145
if (!new_prog)
92146
return ERR_PTR(-ENOMEM);
93147

148+
/* Attach oracle inner map to new LDIMM64 instruction. */
149+
aux = &env->insn_aux_data[i];
150+
aux->oracle_inner_map = inner_map;
151+
152+
err = __add_used_map(env, inner_map);
153+
if (err < 0)
154+
return ERR_PTR(err);
155+
94156
return new_prog;
95157

96158
noop:

kernel/bpf/syscall.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -441,7 +441,7 @@ void bpf_map_init_from_attr(struct bpf_map *map, union bpf_attr *attr)
441441
map->map_extra = attr->map_extra;
442442
}
443443

444-
static int bpf_map_alloc_id(struct bpf_map *map)
444+
int bpf_map_alloc_id(struct bpf_map *map)
445445
{
446446
int id;
447447

@@ -480,7 +480,7 @@ void bpf_map_free_id(struct bpf_map *map)
480480
}
481481

482482
#ifdef CONFIG_MEMCG
483-
static void bpf_map_save_memcg(struct bpf_map *map)
483+
void bpf_map_save_memcg(struct bpf_map *map)
484484
{
485485
/* Currently if a map is created by a process belonging to the root
486486
* memory cgroup, get_obj_cgroup_from_current() will return NULL.
@@ -580,7 +580,7 @@ void __percpu *bpf_map_alloc_percpu(const struct bpf_map *map, size_t size,
580580
}
581581

582582
#else
583-
static void bpf_map_save_memcg(struct bpf_map *map)
583+
void bpf_map_save_memcg(struct bpf_map *map)
584584
{
585585
}
586586

@@ -880,7 +880,7 @@ void bpf_obj_free_fields(const struct btf_record *rec, void *obj)
880880
}
881881
}
882882

883-
static void bpf_map_free(struct bpf_map *map)
883+
void bpf_map_free(struct bpf_map *map)
884884
{
885885
struct btf_record *rec = map->record;
886886
struct btf *btf = map->btf;

kernel/bpf/verifier.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20969,7 +20969,7 @@ static int check_map_prog_compatibility(struct bpf_verifier_env *env,
2096920969
return 0;
2097020970
}
2097120971

20972-
static int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map)
20972+
int __add_used_map(struct bpf_verifier_env *env, struct bpf_map *map)
2097320973
{
2097420974
int i, err;
2097520975

0 commit comments

Comments
 (0)