Skip to content

Commit 550d561

Browse files
pchaignoKernel Patches Daemon
authored andcommitted
bpf: Create and populate oracle map
This creates and populates the main oracle map for our BPF program. The map is populated with the inner oracle map created and populated in previous patches. This main oracle map is a hashmap of maps with pruning point indexes as keys and inner oracle maps as values. Map flag BPF_F_INNER_MAP is required because our inner oracle maps won't all hold the same number of states. Signed-off-by: Paul Chaignon <[email protected]>
1 parent aa61888 commit 550d561

File tree

5 files changed

+143
-3
lines changed

5 files changed

+143
-3
lines changed

include/linux/bpf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2794,6 +2794,9 @@ int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file,
27942794
int bpf_fd_array_map_lookup_elem(struct bpf_map *map, void *key, u32 *value);
27952795
int bpf_fd_htab_map_update_elem(struct bpf_map *map, struct file *map_file,
27962796
void *key, void *value, u64 map_flags);
2797+
long htab_map_update_elem_in_place(struct bpf_map *map, void *key,
2798+
void *value, u64 map_flags,
2799+
bool percpu, bool onallcpus);
27972800
int bpf_fd_htab_map_lookup_elem(struct bpf_map *map, void *key, u32 *value);
27982801

27992802
int bpf_get_file_flag(int flags);

include/linux/bpf_verifier.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,7 @@ struct bpf_verifier_env {
846846
u32 longest_mark_read_walk;
847847
u32 free_list_size;
848848
u32 explored_states_size;
849+
u32 num_prune_points;
849850
u32 num_backedges;
850851
bpfptr_t fd_array;
851852

@@ -1128,5 +1129,6 @@ void bpf_reset_live_stack_callchain(struct bpf_verifier_env *env);
11281129
int save_state_in_oracle(struct bpf_verifier_env *env, int insn_idx);
11291130
struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bpf_insn *insn,
11301131
int i, int *cnt);
1132+
int create_and_populate_oracle_map(struct bpf_verifier_env *env);
11311133

11321134
#endif /* _LINUX_BPF_VERIFIER_H */

kernel/bpf/hashtab.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,9 +1249,9 @@ static long htab_lru_map_update_elem(struct bpf_map *map, void *key, void *value
12491249
return ret;
12501250
}
12511251

1252-
static long htab_map_update_elem_in_place(struct bpf_map *map, void *key,
1253-
void *value, u64 map_flags,
1254-
bool percpu, bool onallcpus)
1252+
long htab_map_update_elem_in_place(struct bpf_map *map, void *key,
1253+
void *value, u64 map_flags,
1254+
bool percpu, bool onallcpus)
12551255
{
12561256
struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
12571257
struct htab_elem *l_new, *l_old;

kernel/bpf/oracle.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,133 @@ struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bp
190190
*cnt = 1;
191191
return new_prog;
192192
}
193+
194+
static int populate_oracle_map(struct bpf_verifier_env *env, struct bpf_map *oracle_map)
195+
{
196+
struct bpf_insn_aux_data *aux;
197+
int i, err;
198+
199+
/* Oracle checks are always before pruning points, so they cannot be the last
200+
* instruction.
201+
*/
202+
for (i = 0; i < env->prog->len - 1; i++) {
203+
aux = &env->insn_aux_data[i];
204+
if (!aux->oracle_inner_map || !aux->oracle_inner_map->max_entries)
205+
continue;
206+
207+
bpf_map_inc(aux->oracle_inner_map);
208+
209+
rcu_read_lock();
210+
err = htab_map_update_elem_in_place(oracle_map, &i, &aux->oracle_inner_map,
211+
BPF_NOEXIST, false, false);
212+
rcu_read_unlock();
213+
if (err) {
214+
bpf_map_put(aux->oracle_inner_map);
215+
return err;
216+
}
217+
}
218+
219+
return 0;
220+
}
221+
222+
static struct bpf_map *alloc_oracle_inner_map_meta(void)
223+
{
224+
struct bpf_array *inner_array_meta;
225+
struct bpf_map *inner_map_meta;
226+
227+
inner_map_meta = kzalloc(sizeof(*inner_map_meta), GFP_USER);
228+
if (!inner_map_meta)
229+
return ERR_PTR(-ENOMEM);
230+
231+
inner_map_meta->map_type = BPF_MAP_TYPE_ARRAY;
232+
inner_map_meta->key_size = sizeof(__u32);
233+
inner_map_meta->value_size = sizeof(struct bpf_oracle_state);
234+
inner_map_meta->map_flags = BPF_F_INNER_MAP;
235+
inner_map_meta->max_entries = 1;
236+
237+
inner_map_meta->ops = &array_map_ops;
238+
239+
inner_array_meta = container_of(inner_map_meta, struct bpf_array, map);
240+
inner_array_meta->index_mask = 0;
241+
inner_array_meta->elem_size = round_up(inner_map_meta->value_size, 8);
242+
inner_map_meta->bypass_spec_v1 = true;
243+
244+
return inner_map_meta;
245+
}
246+
247+
static struct bpf_map *create_oracle_map(struct bpf_verifier_env *env)
248+
{
249+
struct bpf_map *map = NULL, *inner_map;
250+
int err;
251+
252+
union bpf_attr map_attr = {
253+
.map_type = BPF_MAP_TYPE_HASH_OF_MAPS,
254+
.key_size = sizeof(__u32),
255+
.value_size = sizeof(__u32),
256+
.max_entries = env->num_prune_points,
257+
.map_flags = BPF_F_RDONLY,
258+
.map_name = "oracle_map",
259+
};
260+
/* We don't want to use htab_of_maps_map_ops here because it expects map_attr.inner_map_fd
261+
* to be set to the fd of inner_map_meta, which we don't have. Instead we can allocate and
262+
* set inner_map_meta ourselves.
263+
*/
264+
map = htab_map_ops.map_alloc(&map_attr);
265+
if (IS_ERR(map))
266+
return map;
267+
268+
map->ops = &htab_of_maps_map_ops;
269+
map->map_type = BPF_MAP_TYPE_HASH_OF_MAPS;
270+
271+
inner_map = alloc_oracle_inner_map_meta();
272+
if (IS_ERR(inner_map)) {
273+
err = PTR_ERR(inner_map);
274+
goto free_map;
275+
}
276+
map->inner_map_meta = inner_map;
277+
278+
err = bpf_obj_name_cpy(map->name, map_attr.map_name,
279+
sizeof(map_attr.map_name));
280+
if (err < 0)
281+
goto free_map;
282+
283+
mutex_init(&map->freeze_mutex);
284+
spin_lock_init(&map->owner_lock);
285+
286+
err = security_bpf_map_create(map, &map_attr, NULL, false);
287+
if (err)
288+
goto free_map_sec;
289+
290+
err = bpf_map_alloc_id(map);
291+
if (err)
292+
goto free_map_sec;
293+
294+
bpf_map_save_memcg(map);
295+
296+
return map;
297+
298+
free_map_sec:
299+
security_bpf_map_free(map);
300+
free_map:
301+
bpf_map_free(map);
302+
return ERR_PTR(err);
303+
}
304+
305+
int create_and_populate_oracle_map(struct bpf_verifier_env *env)
306+
{
307+
struct bpf_map *oracle_map;
308+
int err;
309+
310+
if (env->num_prune_points == 0 || env->subprog_cnt > 1)
311+
return 0;
312+
313+
oracle_map = create_oracle_map(env);
314+
if (IS_ERR(oracle_map))
315+
return PTR_ERR(oracle_map);
316+
317+
err = __add_used_map(env, oracle_map);
318+
if (err < 0)
319+
return err;
320+
321+
return populate_oracle_map(env, oracle_map);
322+
}

kernel/bpf/verifier.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17560,6 +17560,8 @@ enum {
1756017560

1756117561
static void mark_prune_point(struct bpf_verifier_env *env, int idx)
1756217562
{
17563+
if (!env->insn_aux_data[idx].prune_point)
17564+
env->num_prune_points++;
1756317565
env->insn_aux_data[idx].prune_point = true;
1756417566
}
1756517567

@@ -25301,6 +25303,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
2530125303
if (ret == 0)
2530225304
ret = do_misc_fixups(env);
2530325305

25306+
if (ret == 0)
25307+
ret = create_and_populate_oracle_map(env);
25308+
2530425309
/* do 32-bit optimization after insn patching has done so those patched
2530525310
* insns could be handled correctly.
2530625311
*/

0 commit comments

Comments
 (0)