This commit adds a way to dump eBPF programs. The initial implementation
doesn't support maps, and therefore only allows dumping seccomp ebpf
programs which themselves don't currently support maps.

v2: don't export a prog_id for the filter

Signed-off-by: Tycho Andersen <tycho.ander...@canonical.com>
CC: Kees Cook <keesc...@chromium.org>
CC: Will Drewry <w...@chromium.org>
CC: Oleg Nesterov <o...@redhat.com>
CC: Andy Lutomirski <l...@amacapital.net>
CC: Pavel Emelyanov <xe...@parallels.com>
CC: Serge E. Hallyn <serge.hal...@ubuntu.com>
CC: Alexei Starovoitov <a...@kernel.org>
CC: Daniel Borkmann <dan...@iogearbox.net>
---
 include/uapi/linux/bpf.h | 14 ++++++++++++++
 kernel/bpf/syscall.c     | 41 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 631cdee..e037a76 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -107,6 +107,13 @@ enum bpf_cmd {
         * returns fd or negative error
         */
        BPF_PROG_LOAD,
+
+       /* dump an existing bpf
+        * err = bpf(BPF_PROG_DUMP, union bpf_attr *attr, u32 size)
+        * Using attr->prog_fd, attr->dump_insn_cnt, attr->dump_insns
+        * returns zero or negative error
+        */
+       BPF_PROG_DUMP,
 };
 
 enum bpf_map_type {
@@ -161,6 +168,13 @@ union bpf_attr {
                __aligned_u64   log_buf;        /* user supplied buffer */
                __u32           kern_version;   /* checked when 
prog_type=kprobe */
        };
+
+       struct { /* anonymous struct used by BPF_PROG_DUMP command */
+               __u32           prog_fd;
+               __u32           dump_insn_cnt;
+               __aligned_u64   dump_insns;     /* user supplied buffer */
+               __u8            gpl_compatible;
+       };
 } __attribute__((aligned(8)));
 
 /* integer value in 'imm' field of BPF_CALL instruction selects which helper
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index dc9b464..58ae9f4 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -586,6 +586,44 @@ free_prog:
        return err;
 }
 
+static int bpf_prog_dump(union bpf_attr *attr, union bpf_attr __user *uattr)
+{
+       int ufd = attr->prog_fd;
+       struct fd f = fdget(ufd);
+       struct bpf_prog *prog;
+       int ret = -EINVAL;
+
+       prog = get_prog(f);
+       if (IS_ERR(prog))
+               return PTR_ERR(prog);
+
+       /* For now, let's refuse to dump anything that isn't a seccomp program.
+        * Other program types have support for maps, which our current dump
+        * code doesn't support.
+        */
+       if (prog->type != BPF_PROG_TYPE_SECCOMP)
+               goto out;
+
+       ret = -EFAULT;
+       if (put_user(prog->len, &uattr->dump_insn_cnt))
+               goto out;
+
+       if (put_user((u8) prog->gpl_compatible, &uattr->gpl_compatible))
+               goto out;
+
+       if (attr->dump_insns) {
+               u32 len = prog->len * sizeof(struct bpf_insn);
+
+               if (copy_to_user(u64_to_ptr(attr->dump_insns),
+                                prog->insns, len) != 0)
+                       goto out;
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
 SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, 
size)
 {
        union bpf_attr attr = {};
@@ -650,6 +688,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, 
uattr, unsigned int, siz
        case BPF_PROG_LOAD:
                err = bpf_prog_load(&attr);
                break;
+       case BPF_PROG_DUMP:
+               err = bpf_prog_dump(&attr, uattr);
+               break;
        default:
                err = -EINVAL;
                break;
-- 
2.1.4

--
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/

Reply via email to