diff options
| author | Alexei Starovoitov <ast@plumgrid.com> | 2014-12-01 18:06:34 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2014-12-06 00:47:32 -0500 |
| commit | ddd872bc3098f9d9abe1680a6b2013e59e3337f7 (patch) | |
| tree | be98ca10e99f38fc5f84e94bacee95db64183b15 /kernel/bpf | |
| parent | f51a5e82ea9aaf05106c00d976e772ca384a9199 (diff) | |
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 <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/bpf')
| -rw-r--r-- | kernel/bpf/verifier.c | 70 |
1 files changed, 68 insertions, 2 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index b6a1f7c14a67..a28e09c7825d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
| @@ -1172,6 +1172,70 @@ static int check_ld_imm(struct verifier_env *env, struct bpf_insn *insn) | |||
| 1172 | return 0; | 1172 | return 0; |
| 1173 | } | 1173 | } |
| 1174 | 1174 | ||
| 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 | |||
| 1175 | /* non-recursive DFS pseudo code | 1239 | /* non-recursive DFS pseudo code |
| 1176 | * 1 procedure DFS-iterative(G,v): | 1240 | * 1 procedure DFS-iterative(G,v): |
| 1177 | * 2 label v as discovered | 1241 | * 2 label v as discovered |
| @@ -1677,8 +1741,10 @@ process_bpf_exit: | |||
| 1677 | u8 mode = BPF_MODE(insn->code); | 1741 | u8 mode = BPF_MODE(insn->code); |
| 1678 | 1742 | ||
| 1679 | if (mode == BPF_ABS || mode == BPF_IND) { | 1743 | if (mode == BPF_ABS || mode == BPF_IND) { |
| 1680 | verbose("LD_ABS is not supported yet\n"); | 1744 | err = check_ld_abs(env, insn); |
| 1681 | return -EINVAL; | 1745 | if (err) |
| 1746 | return err; | ||
| 1747 | |||
| 1682 | } else if (mode == BPF_IMM) { | 1748 | } else if (mode == BPF_IMM) { |
| 1683 | err = check_ld_imm(env, insn); | 1749 | err = check_ld_imm(env, insn); |
| 1684 | if (err) | 1750 | if (err) |
