diff options
author | Jiri Pirko <jpirko@redhat.com> | 2012-03-31 07:01:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-03 18:36:20 -0400 |
commit | 302d663740cfaf2c364df6bb61cd339014ed714c (patch) | |
tree | 85e3ea387a72e08b91b325850af062f430ce1260 /net/core | |
parent | fca231b2771cfd4e4f89445cf5c8dd81409b5b3c (diff) |
filter: Allow to create sk-unattached filters
Today, BPF filters are bind to sockets. Since BPF machine becomes handy
for other purposes, this patch allows to create unattached filter.
Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/filter.c | 66 |
1 files changed, 62 insertions, 4 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 5dea45279215..cfbea889a0eb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -587,6 +587,67 @@ void sk_filter_release_rcu(struct rcu_head *rcu) | |||
587 | } | 587 | } |
588 | EXPORT_SYMBOL(sk_filter_release_rcu); | 588 | EXPORT_SYMBOL(sk_filter_release_rcu); |
589 | 589 | ||
590 | static int __sk_prepare_filter(struct sk_filter *fp) | ||
591 | { | ||
592 | int err; | ||
593 | |||
594 | fp->bpf_func = sk_run_filter; | ||
595 | |||
596 | err = sk_chk_filter(fp->insns, fp->len); | ||
597 | if (err) | ||
598 | return err; | ||
599 | |||
600 | bpf_jit_compile(fp); | ||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | /** | ||
605 | * sk_unattached_filter_create - create an unattached filter | ||
606 | * @fprog: the filter program | ||
607 | * @sk: the socket to use | ||
608 | * | ||
609 | * Create a filter independent ofr any socket. We first run some | ||
610 | * sanity checks on it to make sure it does not explode on us later. | ||
611 | * If an error occurs or there is insufficient memory for the filter | ||
612 | * a negative errno code is returned. On success the return is zero. | ||
613 | */ | ||
614 | int sk_unattached_filter_create(struct sk_filter **pfp, | ||
615 | struct sock_fprog *fprog) | ||
616 | { | ||
617 | struct sk_filter *fp; | ||
618 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; | ||
619 | int err; | ||
620 | |||
621 | /* Make sure new filter is there and in the right amounts. */ | ||
622 | if (fprog->filter == NULL) | ||
623 | return -EINVAL; | ||
624 | |||
625 | fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL); | ||
626 | if (!fp) | ||
627 | return -ENOMEM; | ||
628 | memcpy(fp->insns, fprog->filter, fsize); | ||
629 | |||
630 | atomic_set(&fp->refcnt, 1); | ||
631 | fp->len = fprog->len; | ||
632 | |||
633 | err = __sk_prepare_filter(fp); | ||
634 | if (err) | ||
635 | goto free_mem; | ||
636 | |||
637 | *pfp = fp; | ||
638 | return 0; | ||
639 | free_mem: | ||
640 | kfree(fp); | ||
641 | return err; | ||
642 | } | ||
643 | EXPORT_SYMBOL_GPL(sk_unattached_filter_create); | ||
644 | |||
645 | void sk_unattached_filter_destroy(struct sk_filter *fp) | ||
646 | { | ||
647 | sk_filter_release(fp); | ||
648 | } | ||
649 | EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); | ||
650 | |||
590 | /** | 651 | /** |
591 | * sk_attach_filter - attach a socket filter | 652 | * sk_attach_filter - attach a socket filter |
592 | * @fprog: the filter program | 653 | * @fprog: the filter program |
@@ -617,16 +678,13 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
617 | 678 | ||
618 | atomic_set(&fp->refcnt, 1); | 679 | atomic_set(&fp->refcnt, 1); |
619 | fp->len = fprog->len; | 680 | fp->len = fprog->len; |
620 | fp->bpf_func = sk_run_filter; | ||
621 | 681 | ||
622 | err = sk_chk_filter(fp->insns, fp->len); | 682 | err = __sk_prepare_filter(fp); |
623 | if (err) { | 683 | if (err) { |
624 | sk_filter_uncharge(sk, fp); | 684 | sk_filter_uncharge(sk, fp); |
625 | return err; | 685 | return err; |
626 | } | 686 | } |
627 | 687 | ||
628 | bpf_jit_compile(fp); | ||
629 | |||
630 | old_fp = rcu_dereference_protected(sk->sk_filter, | 688 | old_fp = rcu_dereference_protected(sk->sk_filter, |
631 | sock_owned_by_user(sk)); | 689 | sock_owned_by_user(sk)); |
632 | rcu_assign_pointer(sk->sk_filter, fp); | 690 | rcu_assign_pointer(sk->sk_filter, fp); |