aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2017-01-13 17:38:15 -0500
committerDavid S. Miller <davem@davemloft.net>2017-01-16 14:03:31 -0500
commitf1f7714ea51c56b7163fb1a5acf39c6a204dd758 (patch)
tree9e1d9aeda7fe5b358c6d7ed71ccfcdcd576f313a
parent57d5f64d83ab5b5a5118b1597386dd76eaf4340d (diff)
bpf: rework prog_digest into prog_tag
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>
-rw-r--r--include/linux/bpf.h2
-rw-r--r--include/linux/filter.h6
-rw-r--r--include/uapi/linux/pkt_cls.h2
-rw-r--r--include/uapi/linux/tc_act/tc_bpf.h2
-rw-r--r--kernel/bpf/core.c14
-rw-r--r--kernel/bpf/syscall.c8
-rw-r--r--kernel/bpf/verifier.c2
-rw-r--r--net/sched/act_bpf.c5
-rw-r--r--net/sched/cls_bpf.c4
9 files changed, 24 insertions, 21 deletions
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index f74ae68086dc..05cf951df3fe 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -216,7 +216,7 @@ u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5);
216u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); 216u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
217 217
218bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp); 218bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp);
219int bpf_prog_calc_digest(struct bpf_prog *fp); 219int bpf_prog_calc_tag(struct bpf_prog *fp);
220 220
221const struct bpf_func_proto *bpf_get_trace_printk_proto(void); 221const struct bpf_func_proto *bpf_get_trace_printk_proto(void);
222 222
diff --git a/include/linux/filter.h b/include/linux/filter.h
index a0934e6c9bab..e4eb2546339a 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -57,6 +57,8 @@ struct bpf_prog_aux;
57/* BPF program can access up to 512 bytes of stack space. */ 57/* BPF program can access up to 512 bytes of stack space. */
58#define MAX_BPF_STACK 512 58#define MAX_BPF_STACK 512
59 59
60#define BPF_TAG_SIZE 8
61
60/* Helper macros for filter block array initializers. */ 62/* Helper macros for filter block array initializers. */
61 63
62/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ 64/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
@@ -408,7 +410,7 @@ struct bpf_prog {
408 kmemcheck_bitfield_end(meta); 410 kmemcheck_bitfield_end(meta);
409 enum bpf_prog_type type; /* Type of BPF program */ 411 enum bpf_prog_type type; /* Type of BPF program */
410 u32 len; /* Number of filter blocks */ 412 u32 len; /* Number of filter blocks */
411 u32 digest[SHA_DIGEST_WORDS]; /* Program digest */ 413 u8 tag[BPF_TAG_SIZE];
412 struct bpf_prog_aux *aux; /* Auxiliary fields */ 414 struct bpf_prog_aux *aux; /* Auxiliary fields */
413 struct sock_fprog_kern *orig_prog; /* Original BPF program */ 415 struct sock_fprog_kern *orig_prog; /* Original BPF program */
414 unsigned int (*bpf_func)(const void *ctx, 416 unsigned int (*bpf_func)(const void *ctx,
@@ -519,7 +521,7 @@ static inline u32 bpf_prog_insn_size(const struct bpf_prog *prog)
519 return prog->len * sizeof(struct bpf_insn); 521 return prog->len * sizeof(struct bpf_insn);
520} 522}
521 523
522static inline u32 bpf_prog_digest_scratch_size(const struct bpf_prog *prog) 524static inline u32 bpf_prog_tag_scratch_size(const struct bpf_prog *prog)
523{ 525{
524 return round_up(bpf_prog_insn_size(prog) + 526 return round_up(bpf_prog_insn_size(prog) +
525 sizeof(__be64) + 1, SHA_MESSAGE_BYTES); 527 sizeof(__be64) + 1, SHA_MESSAGE_BYTES);
diff --git a/include/uapi/linux/pkt_cls.h b/include/uapi/linux/pkt_cls.h
index cb4bcdc58543..a4dcd88ec271 100644
--- a/include/uapi/linux/pkt_cls.h
+++ b/include/uapi/linux/pkt_cls.h
@@ -397,7 +397,7 @@ enum {
397 TCA_BPF_NAME, 397 TCA_BPF_NAME,
398 TCA_BPF_FLAGS, 398 TCA_BPF_FLAGS,
399 TCA_BPF_FLAGS_GEN, 399 TCA_BPF_FLAGS_GEN,
400 TCA_BPF_DIGEST, 400 TCA_BPF_TAG,
401 __TCA_BPF_MAX, 401 __TCA_BPF_MAX,
402}; 402};
403 403
diff --git a/include/uapi/linux/tc_act/tc_bpf.h b/include/uapi/linux/tc_act/tc_bpf.h
index a6b88a6f7f71..975b50dc8d1d 100644
--- a/include/uapi/linux/tc_act/tc_bpf.h
+++ b/include/uapi/linux/tc_act/tc_bpf.h
@@ -27,7 +27,7 @@ enum {
27 TCA_ACT_BPF_FD, 27 TCA_ACT_BPF_FD,
28 TCA_ACT_BPF_NAME, 28 TCA_ACT_BPF_NAME,
29 TCA_ACT_BPF_PAD, 29 TCA_ACT_BPF_PAD,
30 TCA_ACT_BPF_DIGEST, 30 TCA_ACT_BPF_TAG,
31 __TCA_ACT_BPF_MAX, 31 __TCA_ACT_BPF_MAX,
32}; 32};
33#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1) 33#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 1eb4f1303756..503d4211988a 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -146,10 +146,11 @@ void __bpf_prog_free(struct bpf_prog *fp)
146 vfree(fp); 146 vfree(fp);
147} 147}
148 148
149int bpf_prog_calc_digest(struct bpf_prog *fp) 149int bpf_prog_calc_tag(struct bpf_prog *fp)
150{ 150{
151 const u32 bits_offset = SHA_MESSAGE_BYTES - sizeof(__be64); 151 const u32 bits_offset = SHA_MESSAGE_BYTES - sizeof(__be64);
152 u32 raw_size = bpf_prog_digest_scratch_size(fp); 152 u32 raw_size = bpf_prog_tag_scratch_size(fp);
153 u32 digest[SHA_DIGEST_WORDS];
153 u32 ws[SHA_WORKSPACE_WORDS]; 154 u32 ws[SHA_WORKSPACE_WORDS];
154 u32 i, bsize, psize, blocks; 155 u32 i, bsize, psize, blocks;
155 struct bpf_insn *dst; 156 struct bpf_insn *dst;
@@ -162,7 +163,7 @@ int bpf_prog_calc_digest(struct bpf_prog *fp)
162 if (!raw) 163 if (!raw)
163 return -ENOMEM; 164 return -ENOMEM;
164 165
165 sha_init(fp->digest); 166 sha_init(digest);
166 memset(ws, 0, sizeof(ws)); 167 memset(ws, 0, sizeof(ws));
167 168
168 /* We need to take out the map fd for the digest calculation 169 /* 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)
204 *bits = cpu_to_be64((psize - 1) << 3); 205 *bits = cpu_to_be64((psize - 1) << 3);
205 206
206 while (blocks--) { 207 while (blocks--) {
207 sha_transform(fp->digest, todo, ws); 208 sha_transform(digest, todo, ws);
208 todo += SHA_MESSAGE_BYTES; 209 todo += SHA_MESSAGE_BYTES;
209 } 210 }
210 211
211 result = (__force __be32 *)fp->digest; 212 result = (__force __be32 *)digest;
212 for (i = 0; i < SHA_DIGEST_WORDS; i++) 213 for (i = 0; i < SHA_DIGEST_WORDS; i++)
213 result[i] = cpu_to_be32(fp->digest[i]); 214 result[i] = cpu_to_be32(digest[i]);
215 memcpy(fp->tag, result, sizeof(fp->tag));
214 216
215 vfree(raw); 217 vfree(raw);
216 return 0; 218 return 0;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index e89acea22ecf..1d6b29e4e2c3 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -688,17 +688,17 @@ static int bpf_prog_release(struct inode *inode, struct file *filp)
688static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp) 688static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
689{ 689{
690 const struct bpf_prog *prog = filp->private_data; 690 const struct bpf_prog *prog = filp->private_data;
691 char prog_digest[sizeof(prog->digest) * 2 + 1] = { }; 691 char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
692 692
693 bin2hex(prog_digest, prog->digest, sizeof(prog->digest)); 693 bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
694 seq_printf(m, 694 seq_printf(m,
695 "prog_type:\t%u\n" 695 "prog_type:\t%u\n"
696 "prog_jited:\t%u\n" 696 "prog_jited:\t%u\n"
697 "prog_digest:\t%s\n" 697 "prog_tag:\t%s\n"
698 "memlock:\t%llu\n", 698 "memlock:\t%llu\n",
699 prog->type, 699 prog->type,
700 prog->jited, 700 prog->jited,
701 prog_digest, 701 prog_tag,
702 prog->pages * 1ULL << PAGE_SHIFT); 702 prog->pages * 1ULL << PAGE_SHIFT);
703} 703}
704#endif 704#endif
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 83ed2f8f6f22..cdc43b899f28 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2936,7 +2936,7 @@ static int replace_map_fd_with_map_ptr(struct bpf_verifier_env *env)
2936 int insn_cnt = env->prog->len; 2936 int insn_cnt = env->prog->len;
2937 int i, j, err; 2937 int i, j, err;
2938 2938
2939 err = bpf_prog_calc_digest(env->prog); 2939 err = bpf_prog_calc_tag(env->prog);
2940 if (err) 2940 if (err)
2941 return err; 2941 return err;
2942 2942
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 1c60317f0121..520baa41cba3 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -123,12 +123,11 @@ static int tcf_bpf_dump_ebpf_info(const struct tcf_bpf *prog,
123 nla_put_string(skb, TCA_ACT_BPF_NAME, prog->bpf_name)) 123 nla_put_string(skb, TCA_ACT_BPF_NAME, prog->bpf_name))
124 return -EMSGSIZE; 124 return -EMSGSIZE;
125 125
126 nla = nla_reserve(skb, TCA_ACT_BPF_DIGEST, 126 nla = nla_reserve(skb, TCA_ACT_BPF_TAG, sizeof(prog->filter->tag));
127 sizeof(prog->filter->digest));
128 if (nla == NULL) 127 if (nla == NULL)
129 return -EMSGSIZE; 128 return -EMSGSIZE;
130 129
131 memcpy(nla_data(nla), prog->filter->digest, nla_len(nla)); 130 memcpy(nla_data(nla), prog->filter->tag, nla_len(nla));
132 131
133 return 0; 132 return 0;
134} 133}
diff --git a/net/sched/cls_bpf.c b/net/sched/cls_bpf.c
index adc776048d1a..d9c97018317d 100644
--- a/net/sched/cls_bpf.c
+++ b/net/sched/cls_bpf.c
@@ -555,11 +555,11 @@ static int cls_bpf_dump_ebpf_info(const struct cls_bpf_prog *prog,
555 nla_put_string(skb, TCA_BPF_NAME, prog->bpf_name)) 555 nla_put_string(skb, TCA_BPF_NAME, prog->bpf_name))
556 return -EMSGSIZE; 556 return -EMSGSIZE;
557 557
558 nla = nla_reserve(skb, TCA_BPF_DIGEST, sizeof(prog->filter->digest)); 558 nla = nla_reserve(skb, TCA_BPF_TAG, sizeof(prog->filter->tag));
559 if (nla == NULL) 559 if (nla == NULL)
560 return -EMSGSIZE; 560 return -EMSGSIZE;
561 561
562 memcpy(nla_data(nla), prog->filter->digest, nla_len(nla)); 562 memcpy(nla_data(nla), prog->filter->tag, nla_len(nla));
563 563
564 return 0; 564 return 0;
565} 565}