diff options
author | Jiri Olsa <jolsa@kernel.org> | 2018-03-23 06:41:28 -0400 |
---|---|---|
committer | Daniel Borkmann <daniel@iogearbox.net> | 2018-03-23 12:38:57 -0400 |
commit | abe0884011f1a569bc1254b70c41525b755e8037 (patch) | |
tree | 1fde4260003a96f264a8daaac78df085958af838 | |
parent | ae06c70b135886d7d6252f3090146f01a3f3b80c (diff) |
bpf: Remove struct bpf_verifier_env argument from print_bpf_insn
We use print_bpf_insn in user space (bpftool and soon perf),
so it'd be nice to keep it generic and strip it off the kernel
struct bpf_verifier_env argument.
This argument can be safely removed, because its users can
use the struct bpf_insn_cbs::private_data to pass it.
By changing the argument type we can no longer have clean
'verbose' alias to 'bpf_verifier_log_write' in verifier.c.
Instead we're adding the 'verbose' cb_print callback and
removing the alias.
This way we have new cb_print callback in place, and all
the 'verbose(env, ...) calls in verifier.c will cleanly
cast to 'verbose(void *, ...)' so no other change is
needed.
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r-- | kernel/bpf/disasm.c | 52 | ||||
-rw-r--r-- | kernel/bpf/disasm.h | 5 | ||||
-rw-r--r-- | kernel/bpf/verifier.c | 44 |
3 files changed, 54 insertions, 47 deletions
diff --git a/kernel/bpf/disasm.c b/kernel/bpf/disasm.c index 8740406df2cd..d6b76377cb6e 100644 --- a/kernel/bpf/disasm.c +++ b/kernel/bpf/disasm.c | |||
@@ -113,16 +113,16 @@ static const char *const bpf_jmp_string[16] = { | |||
113 | }; | 113 | }; |
114 | 114 | ||
115 | static void print_bpf_end_insn(bpf_insn_print_t verbose, | 115 | static void print_bpf_end_insn(bpf_insn_print_t verbose, |
116 | struct bpf_verifier_env *env, | 116 | void *private_data, |
117 | const struct bpf_insn *insn) | 117 | const struct bpf_insn *insn) |
118 | { | 118 | { |
119 | verbose(env, "(%02x) r%d = %s%d r%d\n", insn->code, insn->dst_reg, | 119 | verbose(private_data, "(%02x) r%d = %s%d r%d\n", |
120 | insn->code, insn->dst_reg, | ||
120 | BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le", | 121 | BPF_SRC(insn->code) == BPF_TO_BE ? "be" : "le", |
121 | insn->imm, insn->dst_reg); | 122 | insn->imm, insn->dst_reg); |
122 | } | 123 | } |
123 | 124 | ||
124 | void print_bpf_insn(const struct bpf_insn_cbs *cbs, | 125 | void print_bpf_insn(const struct bpf_insn_cbs *cbs, |
125 | struct bpf_verifier_env *env, | ||
126 | const struct bpf_insn *insn, | 126 | const struct bpf_insn *insn, |
127 | bool allow_ptr_leaks) | 127 | bool allow_ptr_leaks) |
128 | { | 128 | { |
@@ -132,23 +132,23 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs, | |||
132 | if (class == BPF_ALU || class == BPF_ALU64) { | 132 | if (class == BPF_ALU || class == BPF_ALU64) { |
133 | if (BPF_OP(insn->code) == BPF_END) { | 133 | if (BPF_OP(insn->code) == BPF_END) { |
134 | if (class == BPF_ALU64) | 134 | if (class == BPF_ALU64) |
135 | verbose(env, "BUG_alu64_%02x\n", insn->code); | 135 | verbose(cbs->private_data, "BUG_alu64_%02x\n", insn->code); |
136 | else | 136 | else |
137 | print_bpf_end_insn(verbose, env, insn); | 137 | print_bpf_end_insn(verbose, cbs->private_data, insn); |
138 | } else if (BPF_OP(insn->code) == BPF_NEG) { | 138 | } else if (BPF_OP(insn->code) == BPF_NEG) { |
139 | verbose(env, "(%02x) r%d = %s-r%d\n", | 139 | verbose(cbs->private_data, "(%02x) r%d = %s-r%d\n", |
140 | insn->code, insn->dst_reg, | 140 | insn->code, insn->dst_reg, |
141 | class == BPF_ALU ? "(u32) " : "", | 141 | class == BPF_ALU ? "(u32) " : "", |
142 | insn->dst_reg); | 142 | insn->dst_reg); |
143 | } else if (BPF_SRC(insn->code) == BPF_X) { | 143 | } else if (BPF_SRC(insn->code) == BPF_X) { |
144 | verbose(env, "(%02x) %sr%d %s %sr%d\n", | 144 | verbose(cbs->private_data, "(%02x) %sr%d %s %sr%d\n", |
145 | insn->code, class == BPF_ALU ? "(u32) " : "", | 145 | insn->code, class == BPF_ALU ? "(u32) " : "", |
146 | insn->dst_reg, | 146 | insn->dst_reg, |
147 | bpf_alu_string[BPF_OP(insn->code) >> 4], | 147 | bpf_alu_string[BPF_OP(insn->code) >> 4], |
148 | class == BPF_ALU ? "(u32) " : "", | 148 | class == BPF_ALU ? "(u32) " : "", |
149 | insn->src_reg); | 149 | insn->src_reg); |
150 | } else { | 150 | } else { |
151 | verbose(env, "(%02x) %sr%d %s %s%d\n", | 151 | verbose(cbs->private_data, "(%02x) %sr%d %s %s%d\n", |
152 | insn->code, class == BPF_ALU ? "(u32) " : "", | 152 | insn->code, class == BPF_ALU ? "(u32) " : "", |
153 | insn->dst_reg, | 153 | insn->dst_reg, |
154 | bpf_alu_string[BPF_OP(insn->code) >> 4], | 154 | bpf_alu_string[BPF_OP(insn->code) >> 4], |
@@ -157,46 +157,46 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs, | |||
157 | } | 157 | } |
158 | } else if (class == BPF_STX) { | 158 | } else if (class == BPF_STX) { |
159 | if (BPF_MODE(insn->code) == BPF_MEM) | 159 | if (BPF_MODE(insn->code) == BPF_MEM) |
160 | verbose(env, "(%02x) *(%s *)(r%d %+d) = r%d\n", | 160 | verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = r%d\n", |
161 | insn->code, | 161 | insn->code, |
162 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], | 162 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], |
163 | insn->dst_reg, | 163 | insn->dst_reg, |
164 | insn->off, insn->src_reg); | 164 | insn->off, insn->src_reg); |
165 | else if (BPF_MODE(insn->code) == BPF_XADD) | 165 | else if (BPF_MODE(insn->code) == BPF_XADD) |
166 | verbose(env, "(%02x) lock *(%s *)(r%d %+d) += r%d\n", | 166 | verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) += r%d\n", |
167 | insn->code, | 167 | insn->code, |
168 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], | 168 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], |
169 | insn->dst_reg, insn->off, | 169 | insn->dst_reg, insn->off, |
170 | insn->src_reg); | 170 | insn->src_reg); |
171 | else | 171 | else |
172 | verbose(env, "BUG_%02x\n", insn->code); | 172 | verbose(cbs->private_data, "BUG_%02x\n", insn->code); |
173 | } else if (class == BPF_ST) { | 173 | } else if (class == BPF_ST) { |
174 | if (BPF_MODE(insn->code) != BPF_MEM) { | 174 | if (BPF_MODE(insn->code) != BPF_MEM) { |
175 | verbose(env, "BUG_st_%02x\n", insn->code); | 175 | verbose(cbs->private_data, "BUG_st_%02x\n", insn->code); |
176 | return; | 176 | return; |
177 | } | 177 | } |
178 | verbose(env, "(%02x) *(%s *)(r%d %+d) = %d\n", | 178 | verbose(cbs->private_data, "(%02x) *(%s *)(r%d %+d) = %d\n", |
179 | insn->code, | 179 | insn->code, |
180 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], | 180 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], |
181 | insn->dst_reg, | 181 | insn->dst_reg, |
182 | insn->off, insn->imm); | 182 | insn->off, insn->imm); |
183 | } else if (class == BPF_LDX) { | 183 | } else if (class == BPF_LDX) { |
184 | if (BPF_MODE(insn->code) != BPF_MEM) { | 184 | if (BPF_MODE(insn->code) != BPF_MEM) { |
185 | verbose(env, "BUG_ldx_%02x\n", insn->code); | 185 | verbose(cbs->private_data, "BUG_ldx_%02x\n", insn->code); |
186 | return; | 186 | return; |
187 | } | 187 | } |
188 | verbose(env, "(%02x) r%d = *(%s *)(r%d %+d)\n", | 188 | verbose(cbs->private_data, "(%02x) r%d = *(%s *)(r%d %+d)\n", |
189 | insn->code, insn->dst_reg, | 189 | insn->code, insn->dst_reg, |
190 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], | 190 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], |
191 | insn->src_reg, insn->off); | 191 | insn->src_reg, insn->off); |
192 | } else if (class == BPF_LD) { | 192 | } else if (class == BPF_LD) { |
193 | if (BPF_MODE(insn->code) == BPF_ABS) { | 193 | if (BPF_MODE(insn->code) == BPF_ABS) { |
194 | verbose(env, "(%02x) r0 = *(%s *)skb[%d]\n", | 194 | verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[%d]\n", |
195 | insn->code, | 195 | insn->code, |
196 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], | 196 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], |
197 | insn->imm); | 197 | insn->imm); |
198 | } else if (BPF_MODE(insn->code) == BPF_IND) { | 198 | } else if (BPF_MODE(insn->code) == BPF_IND) { |
199 | verbose(env, "(%02x) r0 = *(%s *)skb[r%d + %d]\n", | 199 | verbose(cbs->private_data, "(%02x) r0 = *(%s *)skb[r%d + %d]\n", |
200 | insn->code, | 200 | insn->code, |
201 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], | 201 | bpf_ldst_string[BPF_SIZE(insn->code) >> 3], |
202 | insn->src_reg, insn->imm); | 202 | insn->src_reg, insn->imm); |
@@ -212,12 +212,12 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs, | |||
212 | if (map_ptr && !allow_ptr_leaks) | 212 | if (map_ptr && !allow_ptr_leaks) |
213 | imm = 0; | 213 | imm = 0; |
214 | 214 | ||
215 | verbose(env, "(%02x) r%d = %s\n", | 215 | verbose(cbs->private_data, "(%02x) r%d = %s\n", |
216 | insn->code, insn->dst_reg, | 216 | insn->code, insn->dst_reg, |
217 | __func_imm_name(cbs, insn, imm, | 217 | __func_imm_name(cbs, insn, imm, |
218 | tmp, sizeof(tmp))); | 218 | tmp, sizeof(tmp))); |
219 | } else { | 219 | } else { |
220 | verbose(env, "BUG_ld_%02x\n", insn->code); | 220 | verbose(cbs->private_data, "BUG_ld_%02x\n", insn->code); |
221 | return; | 221 | return; |
222 | } | 222 | } |
223 | } else if (class == BPF_JMP) { | 223 | } else if (class == BPF_JMP) { |
@@ -227,35 +227,35 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs, | |||
227 | char tmp[64]; | 227 | char tmp[64]; |
228 | 228 | ||
229 | if (insn->src_reg == BPF_PSEUDO_CALL) { | 229 | if (insn->src_reg == BPF_PSEUDO_CALL) { |
230 | verbose(env, "(%02x) call pc%s\n", | 230 | verbose(cbs->private_data, "(%02x) call pc%s\n", |
231 | insn->code, | 231 | insn->code, |
232 | __func_get_name(cbs, insn, | 232 | __func_get_name(cbs, insn, |
233 | tmp, sizeof(tmp))); | 233 | tmp, sizeof(tmp))); |
234 | } else { | 234 | } else { |
235 | strcpy(tmp, "unknown"); | 235 | strcpy(tmp, "unknown"); |
236 | verbose(env, "(%02x) call %s#%d\n", insn->code, | 236 | verbose(cbs->private_data, "(%02x) call %s#%d\n", insn->code, |
237 | __func_get_name(cbs, insn, | 237 | __func_get_name(cbs, insn, |
238 | tmp, sizeof(tmp)), | 238 | tmp, sizeof(tmp)), |
239 | insn->imm); | 239 | insn->imm); |
240 | } | 240 | } |
241 | } else if (insn->code == (BPF_JMP | BPF_JA)) { | 241 | } else if (insn->code == (BPF_JMP | BPF_JA)) { |
242 | verbose(env, "(%02x) goto pc%+d\n", | 242 | verbose(cbs->private_data, "(%02x) goto pc%+d\n", |
243 | insn->code, insn->off); | 243 | insn->code, insn->off); |
244 | } else if (insn->code == (BPF_JMP | BPF_EXIT)) { | 244 | } else if (insn->code == (BPF_JMP | BPF_EXIT)) { |
245 | verbose(env, "(%02x) exit\n", insn->code); | 245 | verbose(cbs->private_data, "(%02x) exit\n", insn->code); |
246 | } else if (BPF_SRC(insn->code) == BPF_X) { | 246 | } else if (BPF_SRC(insn->code) == BPF_X) { |
247 | verbose(env, "(%02x) if r%d %s r%d goto pc%+d\n", | 247 | verbose(cbs->private_data, "(%02x) if r%d %s r%d goto pc%+d\n", |
248 | insn->code, insn->dst_reg, | 248 | insn->code, insn->dst_reg, |
249 | bpf_jmp_string[BPF_OP(insn->code) >> 4], | 249 | bpf_jmp_string[BPF_OP(insn->code) >> 4], |
250 | insn->src_reg, insn->off); | 250 | insn->src_reg, insn->off); |
251 | } else { | 251 | } else { |
252 | verbose(env, "(%02x) if r%d %s 0x%x goto pc%+d\n", | 252 | verbose(cbs->private_data, "(%02x) if r%d %s 0x%x goto pc%+d\n", |
253 | insn->code, insn->dst_reg, | 253 | insn->code, insn->dst_reg, |
254 | bpf_jmp_string[BPF_OP(insn->code) >> 4], | 254 | bpf_jmp_string[BPF_OP(insn->code) >> 4], |
255 | insn->imm, insn->off); | 255 | insn->imm, insn->off); |
256 | } | 256 | } |
257 | } else { | 257 | } else { |
258 | verbose(env, "(%02x) %s\n", | 258 | verbose(cbs->private_data, "(%02x) %s\n", |
259 | insn->code, bpf_class_string[class]); | 259 | insn->code, bpf_class_string[class]); |
260 | } | 260 | } |
261 | } | 261 | } |
diff --git a/kernel/bpf/disasm.h b/kernel/bpf/disasm.h index 266fe8ee542b..e1324a834a24 100644 --- a/kernel/bpf/disasm.h +++ b/kernel/bpf/disasm.h | |||
@@ -22,14 +22,12 @@ | |||
22 | #include <string.h> | 22 | #include <string.h> |
23 | #endif | 23 | #endif |
24 | 24 | ||
25 | struct bpf_verifier_env; | ||
26 | |||
27 | extern const char *const bpf_alu_string[16]; | 25 | extern const char *const bpf_alu_string[16]; |
28 | extern const char *const bpf_class_string[8]; | 26 | extern const char *const bpf_class_string[8]; |
29 | 27 | ||
30 | const char *func_id_name(int id); | 28 | const char *func_id_name(int id); |
31 | 29 | ||
32 | typedef __printf(2, 3) void (*bpf_insn_print_t)(struct bpf_verifier_env *env, | 30 | typedef __printf(2, 3) void (*bpf_insn_print_t)(void *private_data, |
33 | const char *, ...); | 31 | const char *, ...); |
34 | typedef const char *(*bpf_insn_revmap_call_t)(void *private_data, | 32 | typedef const char *(*bpf_insn_revmap_call_t)(void *private_data, |
35 | const struct bpf_insn *insn); | 33 | const struct bpf_insn *insn); |
@@ -45,7 +43,6 @@ struct bpf_insn_cbs { | |||
45 | }; | 43 | }; |
46 | 44 | ||
47 | void print_bpf_insn(const struct bpf_insn_cbs *cbs, | 45 | void print_bpf_insn(const struct bpf_insn_cbs *cbs, |
48 | struct bpf_verifier_env *env, | ||
49 | const struct bpf_insn *insn, | 46 | const struct bpf_insn *insn, |
50 | bool allow_ptr_leaks); | 47 | bool allow_ptr_leaks); |
51 | #endif | 48 | #endif |
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index e9f7c20691c1..e93a6e48641b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c | |||
@@ -168,23 +168,16 @@ struct bpf_call_arg_meta { | |||
168 | 168 | ||
169 | static DEFINE_MUTEX(bpf_verifier_lock); | 169 | static DEFINE_MUTEX(bpf_verifier_lock); |
170 | 170 | ||
171 | /* log_level controls verbosity level of eBPF verifier. | 171 | static void log_write(struct bpf_verifier_env *env, const char *fmt, |
172 | * bpf_verifier_log_write() is used to dump the verification trace to the log, | 172 | va_list args) |
173 | * so the user can figure out what's wrong with the program | ||
174 | */ | ||
175 | __printf(2, 3) void bpf_verifier_log_write(struct bpf_verifier_env *env, | ||
176 | const char *fmt, ...) | ||
177 | { | 173 | { |
178 | struct bpf_verifer_log *log = &env->log; | 174 | struct bpf_verifer_log *log = &env->log; |
179 | unsigned int n; | 175 | unsigned int n; |
180 | va_list args; | ||
181 | 176 | ||
182 | if (!log->level || !log->ubuf || bpf_verifier_log_full(log)) | 177 | if (!log->level || !log->ubuf || bpf_verifier_log_full(log)) |
183 | return; | 178 | return; |
184 | 179 | ||
185 | va_start(args, fmt); | ||
186 | n = vscnprintf(log->kbuf, BPF_VERIFIER_TMP_LOG_SIZE, fmt, args); | 180 | n = vscnprintf(log->kbuf, BPF_VERIFIER_TMP_LOG_SIZE, fmt, args); |
187 | va_end(args); | ||
188 | 181 | ||
189 | WARN_ONCE(n >= BPF_VERIFIER_TMP_LOG_SIZE - 1, | 182 | WARN_ONCE(n >= BPF_VERIFIER_TMP_LOG_SIZE - 1, |
190 | "verifier log line truncated - local buffer too short\n"); | 183 | "verifier log line truncated - local buffer too short\n"); |
@@ -197,14 +190,30 @@ __printf(2, 3) void bpf_verifier_log_write(struct bpf_verifier_env *env, | |||
197 | else | 190 | else |
198 | log->ubuf = NULL; | 191 | log->ubuf = NULL; |
199 | } | 192 | } |
200 | EXPORT_SYMBOL_GPL(bpf_verifier_log_write); | 193 | |
201 | /* Historically bpf_verifier_log_write was called verbose, but the name was too | 194 | /* log_level controls verbosity level of eBPF verifier. |
202 | * generic for symbol export. The function was renamed, but not the calls in | 195 | * bpf_verifier_log_write() is used to dump the verification trace to the log, |
203 | * the verifier to avoid complicating backports. Hence the alias below. | 196 | * so the user can figure out what's wrong with the program |
204 | */ | 197 | */ |
205 | static __printf(2, 3) void verbose(struct bpf_verifier_env *env, | 198 | __printf(2, 3) void bpf_verifier_log_write(struct bpf_verifier_env *env, |
206 | const char *fmt, ...) | 199 | const char *fmt, ...) |
207 | __attribute__((alias("bpf_verifier_log_write"))); | 200 | { |
201 | va_list args; | ||
202 | |||
203 | va_start(args, fmt); | ||
204 | log_write(env, fmt, args); | ||
205 | va_end(args); | ||
206 | } | ||
207 | EXPORT_SYMBOL_GPL(bpf_verifier_log_write); | ||
208 | |||
209 | __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...) | ||
210 | { | ||
211 | va_list args; | ||
212 | |||
213 | va_start(args, fmt); | ||
214 | log_write(private_data, fmt, args); | ||
215 | va_end(args); | ||
216 | } | ||
208 | 217 | ||
209 | static bool type_is_pkt_pointer(enum bpf_reg_type type) | 218 | static bool type_is_pkt_pointer(enum bpf_reg_type type) |
210 | { | 219 | { |
@@ -4600,10 +4609,11 @@ static int do_check(struct bpf_verifier_env *env) | |||
4600 | if (env->log.level) { | 4609 | if (env->log.level) { |
4601 | const struct bpf_insn_cbs cbs = { | 4610 | const struct bpf_insn_cbs cbs = { |
4602 | .cb_print = verbose, | 4611 | .cb_print = verbose, |
4612 | .private_data = env, | ||
4603 | }; | 4613 | }; |
4604 | 4614 | ||
4605 | verbose(env, "%d: ", insn_idx); | 4615 | verbose(env, "%d: ", insn_idx); |
4606 | print_bpf_insn(&cbs, env, insn, env->allow_ptr_leaks); | 4616 | print_bpf_insn(&cbs, insn, env->allow_ptr_leaks); |
4607 | } | 4617 | } |
4608 | 4618 | ||
4609 | if (bpf_prog_is_dev_bound(env->prog->aux)) { | 4619 | if (bpf_prog_is_dev_bound(env->prog->aux)) { |