Skip to content

Commit a766279

Browse files
pchaignoKernel Patches Daemon
authored andcommitted
bpf: Patch bytecode with oracle check instructions
This commit patches the BPF bytecode with special instructions to tell the interpreter to check the oracle. These instructions need to be added whenever we saved information on verifier states, so at each pruning point. At the moment, it relies on a special LD_IMM64 instruction with the address to the array map holding the information from the verifier states. This needs to be changed to not expose a new BPF_PSEUDO_MAP_* constant. One option would be to choose something closer to the existing BPF_ST_NOSPEC instruction, which serves a similar internal-only purpose. This patch defines a zero immediate for our LD_IMM64 instruction. The next patch sets the immediate to our map address. Signed-off-by: Paul Chaignon <[email protected]>
1 parent 99992b1 commit a766279

File tree

7 files changed

+71
-5
lines changed

7 files changed

+71
-5
lines changed

include/linux/bpf_verifier.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,6 +1107,8 @@ int bpf_jmp_offset(struct bpf_insn *insn);
11071107
struct bpf_iarray *bpf_insn_successors(struct bpf_verifier_env *env, u32 idx);
11081108
void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask);
11091109
bool bpf_calls_callback(struct bpf_verifier_env *env, int insn_idx);
1110+
struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
1111+
const struct bpf_insn *patch, u32 len);
11101112

11111113
int bpf_stack_liveness_init(struct bpf_verifier_env *env);
11121114
void bpf_stack_liveness_free(struct bpf_verifier_env *env);
@@ -1120,5 +1122,7 @@ bool bpf_stack_slot_alive(struct bpf_verifier_env *env, u32 frameno, u32 spi);
11201122
void bpf_reset_live_stack_callchain(struct bpf_verifier_env *env);
11211123

11221124
int save_state_in_oracle(struct bpf_verifier_env *env, int insn_idx);
1125+
struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bpf_insn *insn,
1126+
int i, int *cnt);
11231127

11241128
#endif /* _LINUX_BPF_VERIFIER_H */

include/uapi/linux/bpf.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,16 @@ enum {
13451345
#define BPF_PSEUDO_MAP_VALUE 2
13461346
#define BPF_PSEUDO_MAP_IDX_VALUE 6
13471347

1348+
/* Internal only.
1349+
* insn[0].dst_reg: 0
1350+
* insn[0].src_reg: BPF_PSEUDO_MAP_ORACLE
1351+
* insn[0].imm: address of oracle state list
1352+
* insn[1].imm: address of oracle state list
1353+
* insn[0].off: 0
1354+
* insn[1].off: 0
1355+
*/
1356+
#define BPF_PSEUDO_MAP_ORACLE 7
1357+
13481358
/* insn[0].src_reg: BPF_PSEUDO_BTF_ID
13491359
* insn[0].imm: kernel btd id of VAR
13501360
* insn[1].imm: 0

kernel/bpf/disasm.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,8 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs,
323323
*/
324324
u64 imm = ((u64)(insn + 1)->imm << 32) | (u32)insn->imm;
325325
bool is_ptr = insn->src_reg == BPF_PSEUDO_MAP_FD ||
326-
insn->src_reg == BPF_PSEUDO_MAP_VALUE;
326+
insn->src_reg == BPF_PSEUDO_MAP_VALUE ||
327+
insn->src_reg == BPF_PSEUDO_MAP_ORACLE;
327328
char tmp[64];
328329

329330
if (is_ptr && !allow_ptr_leaks)

kernel/bpf/oracle.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,39 @@ int save_state_in_oracle(struct bpf_verifier_env *env, int insn_idx)
6161

6262
return 0;
6363
}
64+
65+
struct bpf_prog *patch_oracle_check_insn(struct bpf_verifier_env *env, struct bpf_insn *insn,
66+
int i, int *cnt)
67+
{
68+
struct bpf_insn ld_addrs[2] = {
69+
BPF_LD_IMM64_RAW(0, BPF_PSEUDO_MAP_ORACLE, 0),
70+
};
71+
struct bpf_insn_aux_data *aux = &env->insn_aux_data[i];
72+
struct list_head *head = aux->oracle_states;
73+
struct bpf_insn *insn_buf = env->insn_buf;
74+
struct bpf_prog *new_prog = env->prog;
75+
int num_oracle_states;
76+
77+
if (env->subprog_cnt > 1)
78+
/* Skip the oracle if subprogs are used. */
79+
goto noop;
80+
81+
num_oracle_states = list_count_nodes(head);
82+
if (!num_oracle_states)
83+
goto noop;
84+
85+
insn_buf[0] = ld_addrs[0];
86+
insn_buf[1] = ld_addrs[1];
87+
insn_buf[2] = *insn;
88+
*cnt = 3;
89+
90+
new_prog = bpf_patch_insn_data(env, i, insn_buf, *cnt);
91+
if (!new_prog)
92+
return ERR_PTR(-ENOMEM);
93+
94+
return new_prog;
95+
96+
noop:
97+
*cnt = 1;
98+
return new_prog;
99+
}

kernel/bpf/syscall.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4863,7 +4863,8 @@ static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog,
48634863
for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) {
48644864
map = prog->aux->used_maps[i];
48654865
if (map == (void *)addr) {
4866-
*type = BPF_PSEUDO_MAP_FD;
4866+
if (*type != BPF_PSEUDO_MAP_ORACLE)
4867+
*type = BPF_PSEUDO_MAP_FD;
48674868
goto out;
48684869
}
48694870
if (!map->ops->map_direct_value_meta)
@@ -4925,6 +4926,7 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog,
49254926
if (code != (BPF_LD | BPF_IMM | BPF_DW))
49264927
continue;
49274928

4929+
type = insns[i].src_reg;
49284930
imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;
49294931
map = bpf_map_from_imm(prog, imm, &off, &type);
49304932
if (map) {

kernel/bpf/verifier.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21202,7 +21202,7 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
2120221202
for (i = 0; i < insn_cnt; i++, insn++) {
2120321203
if (insn->code != (BPF_LD | BPF_IMM | BPF_DW))
2120421204
continue;
21205-
if (insn->src_reg == BPF_PSEUDO_FUNC)
21205+
if (insn->src_reg == BPF_PSEUDO_FUNC || insn->src_reg == BPF_PSEUDO_MAP_ORACLE)
2120621206
continue;
2120721207
insn->src_reg = 0;
2120821208
}
@@ -21296,8 +21296,8 @@ static void adjust_poke_descs(struct bpf_prog *prog, u32 off, u32 len)
2129621296
}
2129721297
}
2129821298

21299-
static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
21300-
const struct bpf_insn *patch, u32 len)
21299+
struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
21300+
const struct bpf_insn *patch, u32 len)
2130121301
{
2130221302
struct bpf_prog *new_prog;
2130321303
struct bpf_insn_aux_data *new_data = NULL;
@@ -22639,6 +22639,16 @@ static int do_misc_fixups(struct bpf_verifier_env *env)
2263922639
}
2264022640

2264122641
for (i = 0; i < insn_cnt;) {
22642+
if (is_prune_point(env, i + delta)) {
22643+
new_prog = patch_oracle_check_insn(env, insn, i + delta, &cnt);
22644+
if (IS_ERR(new_prog))
22645+
return PTR_ERR(new_prog);
22646+
22647+
delta += cnt - 1;
22648+
env->prog = prog = new_prog;
22649+
insn = new_prog->insnsi + i + delta;
22650+
}
22651+
2264222652
if (insn->code == (BPF_ALU64 | BPF_MOV | BPF_X) && insn->imm) {
2264322653
if ((insn->off == BPF_ADDR_SPACE_CAST && insn->imm == 1) ||
2264422654
(((struct bpf_map *)env->prog->aux->arena)->map_flags & BPF_F_NO_USER_CONV)) {

tools/bpf/bpftool/xlated_dumper.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ static const char *print_imm(void *private_data,
206206
else if (insn->src_reg == BPF_PSEUDO_MAP_IDX_VALUE)
207207
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
208208
"map[idx:%d]+%d", insn->imm, (insn + 1)->imm);
209+
else if (insn->src_reg == BPF_PSEUDO_MAP_ORACLE)
210+
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
211+
"oracle_map[id:%d]", insn->imm);
209212
else if (insn->src_reg == BPF_PSEUDO_FUNC)
210213
snprintf(dd->scratch_buff, sizeof(dd->scratch_buff),
211214
"subprog[%+d]", insn->imm);

0 commit comments

Comments
 (0)