Skip to content

Commit ddd872b

Browse files
Alexei Starovoitovdavem330
Alexei Starovoitov
authored andcommitted
bpf: verifier: add checks for BPF_ABS | BPF_IND instructions
introduce program type BPF_PROG_TYPE_SOCKET_FILTER that is used for attaching programs to sockets where ctx == skb. add verifier checks for ABS/IND instructions which can only be seen in socket filters, therefore the check: if (env->prog->aux->prog_type != BPF_PROG_TYPE_SOCKET_FILTER) verbose("BPF_LD_ABS|IND instructions are only allowed in socket filters\n"); Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f51a5e8 commit ddd872b

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

Diff for: include/uapi/linux/bpf.h

+1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ enum bpf_map_type {
117117

118118
enum bpf_prog_type {
119119
BPF_PROG_TYPE_UNSPEC,
120+
BPF_PROG_TYPE_SOCKET_FILTER,
120121
};
121122

122123
/* flags for BPF_MAP_UPDATE_ELEM command */

Diff for: kernel/bpf/verifier.c

+68-2
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,70 @@ static int check_ld_imm(struct verifier_env *env, struct bpf_insn *insn)
11721172
return 0;
11731173
}
11741174

1175+
/* verify safety of LD_ABS|LD_IND instructions:
1176+
* - they can only appear in the programs where ctx == skb
1177+
* - since they are wrappers of function calls, they scratch R1-R5 registers,
1178+
* preserve R6-R9, and store return value into R0
1179+
*
1180+
* Implicit input:
1181+
* ctx == skb == R6 == CTX
1182+
*
1183+
* Explicit input:
1184+
* SRC == any register
1185+
* IMM == 32-bit immediate
1186+
*
1187+
* Output:
1188+
* R0 - 8/16/32-bit skb data converted to cpu endianness
1189+
*/
1190+
static int check_ld_abs(struct verifier_env *env, struct bpf_insn *insn)
1191+
{
1192+
struct reg_state *regs = env->cur_state.regs;
1193+
u8 mode = BPF_MODE(insn->code);
1194+
struct reg_state *reg;
1195+
int i, err;
1196+
1197+
if (env->prog->aux->prog_type != BPF_PROG_TYPE_SOCKET_FILTER) {
1198+
verbose("BPF_LD_ABS|IND instructions are only allowed in socket filters\n");
1199+
return -EINVAL;
1200+
}
1201+
1202+
if (insn->dst_reg != BPF_REG_0 || insn->off != 0 ||
1203+
(mode == BPF_ABS && insn->src_reg != BPF_REG_0)) {
1204+
verbose("BPF_LD_ABS uses reserved fields\n");
1205+
return -EINVAL;
1206+
}
1207+
1208+
/* check whether implicit source operand (register R6) is readable */
1209+
err = check_reg_arg(regs, BPF_REG_6, SRC_OP);
1210+
if (err)
1211+
return err;
1212+
1213+
if (regs[BPF_REG_6].type != PTR_TO_CTX) {
1214+
verbose("at the time of BPF_LD_ABS|IND R6 != pointer to skb\n");
1215+
return -EINVAL;
1216+
}
1217+
1218+
if (mode == BPF_IND) {
1219+
/* check explicit source operand */
1220+
err = check_reg_arg(regs, insn->src_reg, SRC_OP);
1221+
if (err)
1222+
return err;
1223+
}
1224+
1225+
/* reset caller saved regs to unreadable */
1226+
for (i = 0; i < CALLER_SAVED_REGS; i++) {
1227+
reg = regs + caller_saved[i];
1228+
reg->type = NOT_INIT;
1229+
reg->imm = 0;
1230+
}
1231+
1232+
/* mark destination R0 register as readable, since it contains
1233+
* the value fetched from the packet
1234+
*/
1235+
regs[BPF_REG_0].type = UNKNOWN_VALUE;
1236+
return 0;
1237+
}
1238+
11751239
/* non-recursive DFS pseudo code
11761240
* 1 procedure DFS-iterative(G,v):
11771241
* 2 label v as discovered
@@ -1677,8 +1741,10 @@ static int do_check(struct verifier_env *env)
16771741
u8 mode = BPF_MODE(insn->code);
16781742

16791743
if (mode == BPF_ABS || mode == BPF_IND) {
1680-
verbose("LD_ABS is not supported yet\n");
1681-
return -EINVAL;
1744+
err = check_ld_abs(env, insn);
1745+
if (err)
1746+
return err;
1747+
16821748
} else if (mode == BPF_IMM) {
16831749
err = check_ld_imm(env, insn);
16841750
if (err)

0 commit comments

Comments
 (0)