Skip to content

Commit f73aecb

Browse files
committed
bpf, x86: add new map type: instructions array
On bpf(BPF_PROG_LOAD) syscall user-supplied BPF programs are translated by the verifier into "xlated" BPF programs. During this process the original instructions offsets might be adjusted and/or individual instructions might be replaced by new sets of instructions, or deleted. Add a new BPF map type which is aimed to keep track of how, for a given program, the original instructions were relocated during the verification. Also, besides keeping track of the original -> xlated mapping, make x86 JIT to build the xlated -> jitted mapping for every instruction listed in an instruction array. This is required for every future application of instruction arrays: static keys, indirect jumps and indirect calls. A map of the BPF_MAP_TYPE_INSN_ARRAY type must be created with a u32 keys and value of size 8. The values have different semantics for userspace and for BPF space. For userspace a value consists of two u32 values – xlated and jitted offsets. For BPF side the value is a real pointer to a jitted instruction. On map creation/initialization, before loading the program, each element of the map should be initialized to point to an instruction offset within the program. Before the program load such maps should be made frozen. After the program verification xlated and jitted offsets can be read via the bpf(2) syscall. If a tracked instruction is removed by the verifier, then the xlated offset is set to (u32)-1 which is considered to be too big for a valid BPF program offset. One such a map can, obviously, be used to track one and only one BPF program. If the verification process was unsuccessful, then the same map can be re-used to verify the program with a different log level. However, if the program was loaded fine, then such a map, being frozen in any case, can't be reused by other programs even after the program release. Example. Consider the following original and xlated programs: Original prog: Xlated prog: 0: r1 = 0x0 0: r1 = 0 1: *(u32 *)(r10 - 0x4) = r1 1: *(u32 *)(r10 -4) = r1 2: r2 = r10 2: r2 = r10 3: r2 += -0x4 3: r2 += -4 4: r1 = 0x0 ll 4: r1 = map[id:88] 6: call 0x1 6: r1 += 272 7: r0 = *(u32 *)(r2 +0) 8: if r0 >= 0x1 goto pc+3 9: r0 <<= 3 10: r0 += r1 11: goto pc+1 12: r0 = 0 7: r6 = r0 13: r6 = r0 8: if r6 == 0x0 goto +0x2 14: if r6 == 0x0 goto pc+4 9: call 0x76 15: r0 = 0xffffffff8d2079c0 17: r0 = *(u64 *)(r0 +0) 10: *(u64 *)(r6 + 0x0) = r0 18: *(u64 *)(r6 +0) = r0 11: r0 = 0x0 19: r0 = 0x0 12: exit 20: exit An instruction array map, containing, e.g., instructions [0,4,7,12] will be translated by the verifier to [0,4,13,20]. A map with index 5 (the middle of 16-byte instruction) or indexes greater than 12 (outside the program boundaries) would be rejected. The functionality provided by this patch will be extended in consequent patches to implement BPF Static Keys, indirect jumps, and indirect calls. Signed-off-by: Anton Protopopov <[email protected]>
1 parent 8a7a024 commit f73aecb

File tree

10 files changed

+459
-1
lines changed

10 files changed

+459
-1
lines changed

arch/x86/net/bpf_jit_comp.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,6 +1612,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
16121612
prog = temp;
16131613

16141614
for (i = 1; i <= insn_cnt; i++, insn++) {
1615+
u32 abs_xlated_off = bpf_prog->aux->subprog_start + i - 1;
16151616
const s32 imm32 = insn->imm;
16161617
u32 dst_reg = insn->dst_reg;
16171618
u32 src_reg = insn->src_reg;
@@ -2642,6 +2643,13 @@ st: if (is_imm8(insn->off))
26422643
return -EFAULT;
26432644
}
26442645
memcpy(rw_image + proglen, temp, ilen);
2646+
2647+
/*
2648+
* Instruction arrays need to know how xlated code
2649+
* maps to jitted code
2650+
*/
2651+
bpf_prog_update_insn_ptr(bpf_prog, abs_xlated_off, proglen,
2652+
image + proglen);
26452653
}
26462654
proglen += ilen;
26472655
addrs[i] = proglen;

include/linux/bpf.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3596,4 +3596,32 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog)
35963596
return prog->aux->func_idx != 0;
35973597
}
35983598

3599+
int bpf_insn_array_init(struct bpf_map *map, const struct bpf_prog *prog);
3600+
int bpf_insn_array_ready(struct bpf_map *map);
3601+
void bpf_insn_array_release(struct bpf_map *map);
3602+
void bpf_insn_array_adjust(struct bpf_map *map, u32 off, u32 len);
3603+
void bpf_insn_array_adjust_after_remove(struct bpf_map *map, u32 off, u32 len);
3604+
3605+
/*
3606+
* The struct bpf_insn_ptr structure describes a pointer to a
3607+
* particular instruction in a loaded BPF program. Initially
3608+
* it is initialised from userspace via user_value.xlated_off.
3609+
* During the program verification all other fields are populated
3610+
* accordingly:
3611+
*
3612+
* jitted_ip: address of the instruction in the jitted image
3613+
* user_value: user-visible xlated and jitted offsets
3614+
* orig_xlated_off: original offset of the instruction
3615+
*/
3616+
struct bpf_insn_ptr {
3617+
void *jitted_ip;
3618+
struct bpf_insn_array_value user_value;
3619+
u32 orig_xlated_off;
3620+
};
3621+
3622+
void bpf_prog_update_insn_ptr(struct bpf_prog *prog,
3623+
u32 xlated_off,
3624+
u32 jitted_off,
3625+
void *jitted_ip);
3626+
35993627
#endif /* _LINUX_BPF_H */

include/linux/bpf_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ BPF_MAP_TYPE(BPF_MAP_TYPE_RINGBUF, ringbuf_map_ops)
133133
BPF_MAP_TYPE(BPF_MAP_TYPE_BLOOM_FILTER, bloom_filter_map_ops)
134134
BPF_MAP_TYPE(BPF_MAP_TYPE_USER_RINGBUF, user_ringbuf_map_ops)
135135
BPF_MAP_TYPE(BPF_MAP_TYPE_ARENA, arena_map_ops)
136+
BPF_MAP_TYPE(BPF_MAP_TYPE_INSN_ARRAY, insn_array_map_ops)
136137

137138
BPF_LINK_TYPE(BPF_LINK_TYPE_RAW_TRACEPOINT, raw_tracepoint)
138139
BPF_LINK_TYPE(BPF_LINK_TYPE_TRACING, tracing)

include/linux/bpf_verifier.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,8 +766,10 @@ struct bpf_verifier_env {
766766
struct list_head free_list; /* list of struct bpf_verifier_state_list */
767767
struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
768768
struct btf_mod_pair used_btfs[MAX_USED_BTFS]; /* array of BTF's used by BPF program */
769+
struct bpf_map *insn_array_maps[MAX_USED_MAPS]; /* array of INSN_ARRAY map's to be relocated */
769770
u32 used_map_cnt; /* number of used maps */
770771
u32 used_btf_cnt; /* number of used BTF objects */
772+
u32 insn_array_map_cnt; /* number of used maps of type BPF_MAP_TYPE_INSN_ARRAY */
771773
u32 id_gen; /* used to generate unique reg IDs */
772774
u32 hidden_subprog_cnt; /* number of hidden subprogs */
773775
int exception_callback_subprog;

include/uapi/linux/bpf.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,7 @@ enum bpf_map_type {
10131013
BPF_MAP_TYPE_USER_RINGBUF,
10141014
BPF_MAP_TYPE_CGRP_STORAGE,
10151015
BPF_MAP_TYPE_ARENA,
1016+
BPF_MAP_TYPE_INSN_ARRAY,
10161017
__MAX_BPF_MAP_TYPE
10171018
};
10181019

@@ -7589,4 +7590,14 @@ enum bpf_kfunc_flags {
75897590
BPF_F_PAD_ZEROS = (1ULL << 0),
75907591
};
75917592

7593+
/*
7594+
* Values of a BPF_MAP_TYPE_INSN_ARRAY entry must be of this type.
7595+
* On updates jitted_off must be equal to 0.
7596+
*/
7597+
struct bpf_insn_array_value {
7598+
__u32 jitted_off;
7599+
__u32 xlated_off;
7600+
};
7601+
7602+
75927603
#endif /* _UAPI__LINUX_BPF_H__ */

kernel/bpf/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ CFLAGS_core.o += -Wno-override-init $(cflags-nogcse-yy)
99
obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o
1010
obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o
1111
obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o
12-
obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
12+
obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o bpf_insn_array.o
1313
obj-$(CONFIG_BPF_SYSCALL) += bpf_local_storage.o bpf_task_storage.o
1414
obj-${CONFIG_BPF_LSM} += bpf_inode_storage.o
1515
obj-$(CONFIG_BPF_SYSCALL) += disasm.o mprog.o

0 commit comments

Comments
 (0)