bpf: rework prog_digest into prog_tag
authorDaniel Borkmann <daniel@iogearbox.net>
Fri, 13 Jan 2017 22:38:15 +0000 (23:38 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 16 Jan 2017 19:03:31 +0000 (14:03 -0500)
Commit 7bd509e311f4 ("bpf: add prog_digest and expose it via
fdinfo/netlink") was recently discussed, partially due to
admittedly suboptimal name of "prog_digest" in combination
with sha1 hash usage, thus inevitably and rightfully concerns
about its security in terms of collision resistance were
raised with regards to use-cases.

The intended use cases are for debugging resp. introspection
only for providing a stable "tag" over the instruction sequence
that both kernel and user space can calculate independently.
It's not usable at all for making a security relevant decision.
So collisions where two different instruction sequences generate
the same tag can happen, but ideally at a rather low rate. The
"tag" will be dumped in hex and is short enough to introspect
in tracepoints or kallsyms output along with other data such
as stack trace, etc. Thus, this patch performs a rename into
prog_tag and truncates the tag to a short output (64 bits) to
make it obvious it's not collision-free.

Should in future a hash or facility be needed with a security
relevant focus, then we can think about requirements, constraints,
etc that would fit to that situation. For now, rework the exposed
parts for the current use cases as long as nothing has been
released yet. Tested on x86_64 and s390x.

Fixes: 7bd509e311f4 ("bpf: add prog_digest and expose it via fdinfo/netlink")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/bpf.h
include/linux/filter.h
include/uapi/linux/pkt_cls.h
include/uapi/linux/tc_act/tc_bpf.h
kernel/bpf/core.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
net/sched/act_bpf.c
net/sched/cls_bpf.c

index f74ae68086dc69b3c02ced58a13f6daed0b4cd77..05cf951df3fedd12b742b9478af13aeace86749c 100644 (file)
@@ -216,7 +216,7 @@ u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5);
 u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
 
 bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp);
-int bpf_prog_calc_digest(struct bpf_prog *fp);
+int bpf_prog_calc_tag(struct bpf_prog *fp);
 
 const struct bpf_func_proto *bpf_get_trace_printk_proto(void);
 
index a0934e6c9babf8436a18b28f4dea285894e5dca5..e4eb2546339afbf2764f5ba335e1e66947fc5af3 100644 (file)
@@ -57,6 +57,8 @@ struct bpf_prog_aux;
 /* BPF program can access up to 512 bytes of stack space. */
 #define MAX_BPF_STACK  512
 
+#define BPF_TAG_SIZE   8
+
 /* Helper macros for filter block array initializers. */
 
 /* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
@@ -408,7 +410,7 @@ struct bpf_prog {
        kmemcheck_bitfield_end(meta);
        enum bpf_prog_type      type;           /* Type of BPF program */
        u32                     len;            /* Number of filter blocks */
-       u32                     digest[SHA_DIGEST_WORDS]; /* Program digest */
+       u8                      tag[BPF_TAG_SIZE];
        struct bpf_prog_aux     *aux;           /* Auxiliary fields */
        struct sock_fprog_kern  *orig_prog;     /* Original BPF program */
        unsigned int            (*bpf_func)(const void *ctx,
@@ -519,7 +521,7 @@ static inline u32 bpf_prog_insn_size(const struct bpf_prog *prog)
        return prog->len * sizeof(struct bpf_insn);
 }
 
-static inline u32 bpf_prog_digest_scratch_size(const struct bpf_prog *prog)
+static inline u32 bpf_prog_tag_scratch_size(const struct bpf_prog *prog)
 {
        return round_up(bpf_prog_insn_size(prog) +
                        sizeof(__be64) + 1, SHA_MESSAGE_BYTES);
index cb4bcdc5854372e514865c30315e65ae30080527..a4dcd88ec2718621c2cf8e801566e5264c75c071 100644 (file)
@@ -397,7 +397,7 @@ enum {
        TCA_BPF_NAME,
        TCA_BPF_FLAGS,
        TCA_BPF_FLAGS_GEN,
-       TCA_BPF_DIGEST,
+       TCA_BPF_TAG,
        __TCA_BPF_MAX,
 };
 
index a6b88a6f7f712b271f07e809ee7a79697e6cb8cf..975b50dc8d1d466bb60c6279de7ebde1d05bd54f 100644 (file)
@@ -27,7 +27,7 @@ enum {
        TCA_ACT_BPF_FD,
        TCA_ACT_BPF_NAME,
        TCA_ACT_BPF_PAD,
-       TCA_ACT_BPF_DIGEST,
+       TCA_ACT_BPF_TAG,
        __TCA_ACT_BPF_MAX,
 };
 #define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)
index 1eb4f1303756164f2893d964198eecd40b0bcd62..503d4211988afe1d3eddd6d39aba520dc4c245ef 100644 (file)
@@ -146,10 +146,11 @@ void __bpf_prog_free(struct bpf_prog *fp)
        vfree(fp);
 }
 
-int bpf_prog_calc_digest(struct bpf_prog *fp)
+int bpf_prog_calc_tag(struct bpf_prog *fp)
 {
        const u32 bits_offset = SHA_MESSAGE_BYTES - sizeof(__be64);
-       u32 raw_size = bpf_prog_digest_scratch_size(fp);
+       u32 raw_size = bpf_prog_tag_scratch_size(fp);
+       u32 digest[SHA_DIGEST_WORDS];
        u32 ws[SHA_WORKSPACE_WORDS];
        u32 i, bsize, psize, blocks;
        struct bpf_insn *dst;
@@ -162,7 +163,7 @@ int bpf_prog_calc_digest(struct bpf_prog *fp)
        if (!raw)
                return -ENOMEM;
 
-       sha_init(fp->digest);
+       sha_init(digest);
        memset(ws, 0, sizeof(ws));
 
        /* We need to take out the map fd for the digest calculation
@@ -204,13 +205,14 @@ int bpf_prog_calc_digest(struct bpf_prog *fp)
        *bits = cpu_to_be64((psize - 1) << 3);
 
        while (blocks--) {
-               sha_transform(fp->digest, todo, ws);
+               sha_transform(digest, todo, ws);
                todo += SHA_MESSAGE_BYTES;
        }
 
-       result = (__force __be32 *)fp->digest;
+       result = (__force __be32 *)digest;
        for (i = 0; i < SHA_DIGEST_WORDS; i++)
-               result[i] = cpu_to_be32(fp->digest[i]);
+               result[i] = cpu_to_be32(digest[i]);
+       memcpy(fp->tag, result, sizeof(fp->tag));
 
        vfree(raw);
        return 0;
index e89acea22ecfc9a625de1924b2e4f997d88d158b..1d6b29e4e2c35ec14cec0a0d68bb7b636102a395 100644 (file)
@@ -688,17 +688,17 @@ static int bpf_prog_release(struct inode *inode, struct file *filp)
 static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
 {
        const struct bpf_prog *prog = filp->private_data;
-       char prog_digest[sizeof(prog->digest) * 2 + 1] = { };
+       char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
 
-       bin2hex(prog_digest, prog->digest, sizeof(prog->digest));
+       bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
        seq_printf(m,
                   "prog_type:\t%u\n"
                   "prog_jited:\t%u\n"
-                  "prog_digest:\t%s\n"
+                  "prog_tag:\t%s\n"
                   "memlock:\t%llu\n",
                   prog->type,
                   prog->jited,
-                  prog_digest,
+                  prog_tag,
                   prog->pages * 1ULL << PAGE_SHIFT);
 }
 #endif
index 83ed2f8f6f228b1ae90f66d89e436b71a5c6a27c..cdc43b899f281ebd01dd8cf8110e6fb966c2a1fa 100644 (file)
@@ -2936,7 +2936,7 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env)
        int insn_cnt = env->prog->len;
        int i, j, err;
 
-       err = bpf_prog_calc_digest(env->prog);
+       err = bpf_prog_calc_tag(env->prog);
        if (err)
                return err;
 
index 1c60317f01214ad77c17415bb2d7bc194b124615..520baa41cba3a8d24a659b67c5a5ed8a44129f37 100644 (file)
@@ -123,12 +123,11 @@ static int tcf_bpf_dump_ebpf_info(const struct tcf_bpf *prog,
            nla_put_string(skb, TCA_ACT_BPF_NAME, prog->bpf_name))
                return -EMSGSIZE;
 
-       nla = nla_reserve(skb, TCA_ACT_BPF_DIGEST,
-                         sizeof(prog->filter->digest));
+       nla = nla_reserve(skb, TCA_ACT_BPF_TAG, sizeof(prog->filter->tag));
        if (nla == NULL)
                return -EMSGSIZE;
 
-       memcpy(nla_data(nla), prog->filter->digest, nla_len(nla));
+       memcpy(nla_data(nla), prog->filter->tag, nla_len(nla));
 
        return 0;
 }
index adc776048d1a899f7955d0a92dd48b374178f3bb..d9c97018317dd7e26b6c99dfa83b8d6daeca6d19 100644 (file)
@@ -555,11 +555,11 @@ static int cls_bpf_dump_ebpf_info(const struct cls_bpf_prog *prog,
            nla_put_string(skb, TCA_BPF_NAME, prog->bpf_name))
                return -EMSGSIZE;
 
-       nla = nla_reserve(skb, TCA_BPF_DIGEST, sizeof(prog->filter->digest));
+       nla = nla_reserve(skb, TCA_BPF_TAG, sizeof(prog->filter->tag));
        if (nla == NULL)
                return -EMSGSIZE;
 
-       memcpy(nla_data(nla), prog->filter->digest, nla_len(nla));
+       memcpy(nla_data(nla), prog->filter->tag, nla_len(nla));
 
        return 0;
 }