diff options
author | Alexei Starovoitov <ast@plumgrid.com> | 2014-05-13 22:50:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-15 16:31:30 -0400 |
commit | 8f577cadf7181243d336be9aba40c1bcc02c4c54 (patch) | |
tree | 67daf2164c9c5b633160489d637b8ecc84b62881 /kernel/seccomp.c | |
parent | 622582786c9e041d0bd52bde201787adeab249f8 (diff) |
seccomp: JIT compile seccomp filter
Take advantage of internal BPF JIT
05-sim-long_jumps.c of libseccomp was used as micro-benchmark:
seccomp_rule_add_exact(ctx,...
seccomp_rule_add_exact(ctx,...
rc = seccomp_load(ctx);
for (i = 0; i < 10000000; i++)
syscall(...);
$ sudo sysctl net.core.bpf_jit_enable=1
$ time ./bench
real 0m2.769s
user 0m1.136s
sys 0m1.624s
$ sudo sysctl net.core.bpf_jit_enable=0
$ time ./bench
real 0m5.825s
user 0m1.268s
sys 0m4.548s
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/seccomp.c')
-rw-r--r-- | kernel/seccomp.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/kernel/seccomp.c b/kernel/seccomp.c index b35c21503a36..7e02d624cc50 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c | |||
@@ -54,8 +54,7 @@ | |||
54 | struct seccomp_filter { | 54 | struct seccomp_filter { |
55 | atomic_t usage; | 55 | atomic_t usage; |
56 | struct seccomp_filter *prev; | 56 | struct seccomp_filter *prev; |
57 | unsigned short len; /* Instruction count */ | 57 | struct sk_filter *prog; |
58 | struct sock_filter_int insnsi[]; | ||
59 | }; | 58 | }; |
60 | 59 | ||
61 | /* Limit any path through the tree to 256KB worth of instructions. */ | 60 | /* Limit any path through the tree to 256KB worth of instructions. */ |
@@ -189,7 +188,8 @@ static u32 seccomp_run_filters(int syscall) | |||
189 | * value always takes priority (ignoring the DATA). | 188 | * value always takes priority (ignoring the DATA). |
190 | */ | 189 | */ |
191 | for (f = current->seccomp.filter; f; f = f->prev) { | 190 | for (f = current->seccomp.filter; f; f = f->prev) { |
192 | u32 cur_ret = sk_run_filter_int_seccomp(&sd, f->insnsi); | 191 | u32 cur_ret = SK_RUN_FILTER(f->prog, (void *)&sd); |
192 | |||
193 | if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) | 193 | if ((cur_ret & SECCOMP_RET_ACTION) < (ret & SECCOMP_RET_ACTION)) |
194 | ret = cur_ret; | 194 | ret = cur_ret; |
195 | } | 195 | } |
@@ -215,7 +215,7 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) | |||
215 | return -EINVAL; | 215 | return -EINVAL; |
216 | 216 | ||
217 | for (filter = current->seccomp.filter; filter; filter = filter->prev) | 217 | for (filter = current->seccomp.filter; filter; filter = filter->prev) |
218 | total_insns += filter->len + 4; /* include a 4 instr penalty */ | 218 | total_insns += filter->prog->len + 4; /* include a 4 instr penalty */ |
219 | if (total_insns > MAX_INSNS_PER_PATH) | 219 | if (total_insns > MAX_INSNS_PER_PATH) |
220 | return -ENOMEM; | 220 | return -ENOMEM; |
221 | 221 | ||
@@ -256,19 +256,27 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) | |||
256 | 256 | ||
257 | /* Allocate a new seccomp_filter */ | 257 | /* Allocate a new seccomp_filter */ |
258 | ret = -ENOMEM; | 258 | ret = -ENOMEM; |
259 | filter = kzalloc(sizeof(struct seccomp_filter) + | 259 | filter = kzalloc(sizeof(struct seccomp_filter), |
260 | sizeof(struct sock_filter_int) * new_len, | ||
261 | GFP_KERNEL|__GFP_NOWARN); | 260 | GFP_KERNEL|__GFP_NOWARN); |
262 | if (!filter) | 261 | if (!filter) |
263 | goto free_prog; | 262 | goto free_prog; |
264 | 263 | ||
265 | ret = sk_convert_filter(fp, fprog->len, filter->insnsi, &new_len); | 264 | filter->prog = kzalloc(sk_filter_size(new_len), |
266 | if (ret) | 265 | GFP_KERNEL|__GFP_NOWARN); |
266 | if (!filter->prog) | ||
267 | goto free_filter; | 267 | goto free_filter; |
268 | |||
269 | ret = sk_convert_filter(fp, fprog->len, filter->prog->insnsi, &new_len); | ||
270 | if (ret) | ||
271 | goto free_filter_prog; | ||
268 | kfree(fp); | 272 | kfree(fp); |
269 | 273 | ||
270 | atomic_set(&filter->usage, 1); | 274 | atomic_set(&filter->usage, 1); |
271 | filter->len = new_len; | 275 | filter->prog->len = new_len; |
276 | filter->prog->bpf_func = (void *)sk_run_filter_int_seccomp; | ||
277 | |||
278 | /* JIT internal BPF into native HW instructions */ | ||
279 | bpf_int_jit_compile(filter->prog); | ||
272 | 280 | ||
273 | /* | 281 | /* |
274 | * If there is an existing filter, make it the prev and don't drop its | 282 | * If there is an existing filter, make it the prev and don't drop its |
@@ -278,6 +286,8 @@ static long seccomp_attach_filter(struct sock_fprog *fprog) | |||
278 | current->seccomp.filter = filter; | 286 | current->seccomp.filter = filter; |
279 | return 0; | 287 | return 0; |
280 | 288 | ||
289 | free_filter_prog: | ||
290 | kfree(filter->prog); | ||
281 | free_filter: | 291 | free_filter: |
282 | kfree(filter); | 292 | kfree(filter); |
283 | free_prog: | 293 | free_prog: |
@@ -330,6 +340,7 @@ void put_seccomp_filter(struct task_struct *tsk) | |||
330 | while (orig && atomic_dec_and_test(&orig->usage)) { | 340 | while (orig && atomic_dec_and_test(&orig->usage)) { |
331 | struct seccomp_filter *freeme = orig; | 341 | struct seccomp_filter *freeme = orig; |
332 | orig = orig->prev; | 342 | orig = orig->prev; |
343 | bpf_jit_free(freeme->prog); | ||
333 | kfree(freeme); | 344 | kfree(freeme); |
334 | } | 345 | } |
335 | } | 346 | } |