[PATCH v14 net-next 05/11] bpf: handle pseudo BPF_CALL insn

2014-09-21 Thread Alexei Starovoitov
in native eBPF programs userspace is using pseudo BPF_CALL instructions
which encode one of 'enum bpf_func_id' inside insn->imm field.
Verifier checks that program using correct function arguments to given func_id.
If all checks passed, kernel needs to fixup BPF_CALL->imm fields by
replacing func_id with in-kernel function pointer.
eBPF interpreter just calls the function.

In-kernel eBPF users continue to use generic BPF_CALL.

Signed-off-by: Alexei Starovoitov 
---
 kernel/bpf/syscall.c |   37 +
 1 file changed, 37 insertions(+)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0afb4eaa1887..b513659d120f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -357,6 +357,40 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl)
list_add(>list_node, _prog_types);
 }
 
+/* fixup insn->imm field of bpf_call instructions:
+ * if (insn->imm == BPF_FUNC_map_lookup_elem)
+ *  insn->imm = bpf_map_lookup_elem - __bpf_call_base;
+ * else if (insn->imm == BPF_FUNC_map_update_elem)
+ *  insn->imm = bpf_map_update_elem - __bpf_call_base;
+ * else ...
+ *
+ * this function is called after eBPF program passed verification
+ */
+static void fixup_bpf_calls(struct bpf_prog *prog)
+{
+   const struct bpf_func_proto *fn;
+   int i;
+
+   for (i = 0; i < prog->len; i++) {
+   struct bpf_insn *insn = >insnsi[i];
+
+   if (insn->code == (BPF_JMP | BPF_CALL)) {
+   /* we reach here when program has bpf_call instructions
+* and it passed bpf_check(), means that
+* ops->get_func_proto must have been supplied, check it
+*/
+   BUG_ON(!prog->aux->ops->get_func_proto);
+
+   fn = prog->aux->ops->get_func_proto(insn->imm);
+   /* all functions that have prototype and verifier 
allowed
+* programs to call them, must be real in-kernel 
functions
+*/
+   BUG_ON(!fn->func);
+   insn->imm = fn->func - __bpf_call_base;
+   }
+   }
+}
+
 /* drop refcnt on maps used by eBPF program and free auxilary data */
 static void free_used_maps(struct bpf_prog_aux *aux)
 {
@@ -478,6 +512,9 @@ static int bpf_prog_load(union bpf_attr *attr)
if (err < 0)
goto free_used_maps;
 
+   /* fixup BPF_CALL->imm field */
+   fixup_bpf_calls(prog);
+
/* eBPF program is ready to be JITed */
bpf_prog_select_runtime(prog);
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v14 net-next 05/11] bpf: handle pseudo BPF_CALL insn

2014-09-21 Thread Alexei Starovoitov
in native eBPF programs userspace is using pseudo BPF_CALL instructions
which encode one of 'enum bpf_func_id' inside insn-imm field.
Verifier checks that program using correct function arguments to given func_id.
If all checks passed, kernel needs to fixup BPF_CALL-imm fields by
replacing func_id with in-kernel function pointer.
eBPF interpreter just calls the function.

In-kernel eBPF users continue to use generic BPF_CALL.

Signed-off-by: Alexei Starovoitov a...@plumgrid.com
---
 kernel/bpf/syscall.c |   37 +
 1 file changed, 37 insertions(+)

diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0afb4eaa1887..b513659d120f 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -357,6 +357,40 @@ void bpf_register_prog_type(struct bpf_prog_type_list *tl)
list_add(tl-list_node, bpf_prog_types);
 }
 
+/* fixup insn-imm field of bpf_call instructions:
+ * if (insn-imm == BPF_FUNC_map_lookup_elem)
+ *  insn-imm = bpf_map_lookup_elem - __bpf_call_base;
+ * else if (insn-imm == BPF_FUNC_map_update_elem)
+ *  insn-imm = bpf_map_update_elem - __bpf_call_base;
+ * else ...
+ *
+ * this function is called after eBPF program passed verification
+ */
+static void fixup_bpf_calls(struct bpf_prog *prog)
+{
+   const struct bpf_func_proto *fn;
+   int i;
+
+   for (i = 0; i  prog-len; i++) {
+   struct bpf_insn *insn = prog-insnsi[i];
+
+   if (insn-code == (BPF_JMP | BPF_CALL)) {
+   /* we reach here when program has bpf_call instructions
+* and it passed bpf_check(), means that
+* ops-get_func_proto must have been supplied, check it
+*/
+   BUG_ON(!prog-aux-ops-get_func_proto);
+
+   fn = prog-aux-ops-get_func_proto(insn-imm);
+   /* all functions that have prototype and verifier 
allowed
+* programs to call them, must be real in-kernel 
functions
+*/
+   BUG_ON(!fn-func);
+   insn-imm = fn-func - __bpf_call_base;
+   }
+   }
+}
+
 /* drop refcnt on maps used by eBPF program and free auxilary data */
 static void free_used_maps(struct bpf_prog_aux *aux)
 {
@@ -478,6 +512,9 @@ static int bpf_prog_load(union bpf_attr *attr)
if (err  0)
goto free_used_maps;
 
+   /* fixup BPF_CALL-imm field */
+   fixup_bpf_calls(prog);
+
/* eBPF program is ready to be JITed */
bpf_prog_select_runtime(prog);
 
-- 
1.7.9.5

--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/