aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/filter.h15
-rw-r--r--net/core/filter.c86
-rw-r--r--net/core/sock_diag.c23
3 files changed, 93 insertions, 31 deletions
diff --git a/include/linux/filter.h b/include/linux/filter.h
index e65e23087367..93a9792e27bc 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -19,14 +19,19 @@ struct compat_sock_fprog {
19}; 19};
20#endif 20#endif
21 21
22struct sock_fprog_kern {
23 u16 len;
24 struct sock_filter *filter;
25};
26
22struct sk_buff; 27struct sk_buff;
23struct sock; 28struct sock;
24 29
25struct sk_filter 30struct sk_filter {
26{
27 atomic_t refcnt; 31 atomic_t refcnt;
28 u32 jited:1, /* Is our filter JIT'ed? */ 32 u32 jited:1, /* Is our filter JIT'ed? */
29 len:31; /* Number of filter blocks */ 33 len:31; /* Number of filter blocks */
34 struct sock_fprog_kern *orig_prog; /* Original BPF program */
30 struct rcu_head rcu; 35 struct rcu_head rcu;
31 unsigned int (*bpf_func)(const struct sk_buff *skb, 36 unsigned int (*bpf_func)(const struct sk_buff *skb,
32 const struct sock_filter *filter); 37 const struct sock_filter *filter);
@@ -42,14 +47,20 @@ static inline unsigned int sk_filter_size(unsigned int proglen)
42 offsetof(struct sk_filter, insns[proglen])); 47 offsetof(struct sk_filter, insns[proglen]));
43} 48}
44 49
50#define sk_filter_proglen(fprog) \
51 (fprog->len * sizeof(fprog->filter[0]))
52
45extern int sk_filter(struct sock *sk, struct sk_buff *skb); 53extern int sk_filter(struct sock *sk, struct sk_buff *skb);
46extern unsigned int sk_run_filter(const struct sk_buff *skb, 54extern unsigned int sk_run_filter(const struct sk_buff *skb,
47 const struct sock_filter *filter); 55 const struct sock_filter *filter);
56
48extern int sk_unattached_filter_create(struct sk_filter **pfp, 57extern int sk_unattached_filter_create(struct sk_filter **pfp,
49 struct sock_fprog *fprog); 58 struct sock_fprog *fprog);
50extern void sk_unattached_filter_destroy(struct sk_filter *fp); 59extern void sk_unattached_filter_destroy(struct sk_filter *fp);
60
51extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); 61extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
52extern int sk_detach_filter(struct sock *sk); 62extern int sk_detach_filter(struct sock *sk);
63
53extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen); 64extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
54extern int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned len); 65extern int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, unsigned len);
55extern void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to); 66extern void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to);
diff --git a/net/core/filter.c b/net/core/filter.c
index bb3c76458ca9..9730e7fe4770 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -629,6 +629,37 @@ int sk_chk_filter(struct sock_filter *filter, unsigned int flen)
629} 629}
630EXPORT_SYMBOL(sk_chk_filter); 630EXPORT_SYMBOL(sk_chk_filter);
631 631
632static int sk_store_orig_filter(struct sk_filter *fp,
633 const struct sock_fprog *fprog)
634{
635 unsigned int fsize = sk_filter_proglen(fprog);
636 struct sock_fprog_kern *fkprog;
637
638 fp->orig_prog = kmalloc(sizeof(*fkprog), GFP_KERNEL);
639 if (!fp->orig_prog)
640 return -ENOMEM;
641
642 fkprog = fp->orig_prog;
643 fkprog->len = fprog->len;
644 fkprog->filter = kmemdup(fp->insns, fsize, GFP_KERNEL);
645 if (!fkprog->filter) {
646 kfree(fp->orig_prog);
647 return -ENOMEM;
648 }
649
650 return 0;
651}
652
653static void sk_release_orig_filter(struct sk_filter *fp)
654{
655 struct sock_fprog_kern *fprog = fp->orig_prog;
656
657 if (fprog) {
658 kfree(fprog->filter);
659 kfree(fprog);
660 }
661}
662
632/** 663/**
633 * sk_filter_release_rcu - Release a socket filter by rcu_head 664 * sk_filter_release_rcu - Release a socket filter by rcu_head
634 * @rcu: rcu_head that contains the sk_filter to free 665 * @rcu: rcu_head that contains the sk_filter to free
@@ -637,6 +668,7 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
637{ 668{
638 struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); 669 struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
639 670
671 sk_release_orig_filter(fp);
640 bpf_jit_free(fp); 672 bpf_jit_free(fp);
641} 673}
642EXPORT_SYMBOL(sk_filter_release_rcu); 674EXPORT_SYMBOL(sk_filter_release_rcu);
@@ -669,8 +701,8 @@ static int __sk_prepare_filter(struct sk_filter *fp)
669int sk_unattached_filter_create(struct sk_filter **pfp, 701int sk_unattached_filter_create(struct sk_filter **pfp,
670 struct sock_fprog *fprog) 702 struct sock_fprog *fprog)
671{ 703{
704 unsigned int fsize = sk_filter_proglen(fprog);
672 struct sk_filter *fp; 705 struct sk_filter *fp;
673 unsigned int fsize = sizeof(struct sock_filter) * fprog->len;
674 int err; 706 int err;
675 707
676 /* Make sure new filter is there and in the right amounts. */ 708 /* Make sure new filter is there and in the right amounts. */
@@ -680,10 +712,16 @@ int sk_unattached_filter_create(struct sk_filter **pfp,
680 fp = kmalloc(sk_filter_size(fprog->len), GFP_KERNEL); 712 fp = kmalloc(sk_filter_size(fprog->len), GFP_KERNEL);
681 if (!fp) 713 if (!fp)
682 return -ENOMEM; 714 return -ENOMEM;
715
683 memcpy(fp->insns, fprog->filter, fsize); 716 memcpy(fp->insns, fprog->filter, fsize);
684 717
685 atomic_set(&fp->refcnt, 1); 718 atomic_set(&fp->refcnt, 1);
686 fp->len = fprog->len; 719 fp->len = fprog->len;
720 /* Since unattached filters are not copied back to user
721 * space through sk_get_filter(), we do not need to hold
722 * a copy here, and can spare us the work.
723 */
724 fp->orig_prog = NULL;
687 725
688 err = __sk_prepare_filter(fp); 726 err = __sk_prepare_filter(fp);
689 if (err) 727 if (err)
@@ -716,7 +754,7 @@ EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy);
716int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) 754int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
717{ 755{
718 struct sk_filter *fp, *old_fp; 756 struct sk_filter *fp, *old_fp;
719 unsigned int fsize = sizeof(struct sock_filter) * fprog->len; 757 unsigned int fsize = sk_filter_proglen(fprog);
720 unsigned int sk_fsize = sk_filter_size(fprog->len); 758 unsigned int sk_fsize = sk_filter_size(fprog->len);
721 int err; 759 int err;
722 760
@@ -730,6 +768,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
730 fp = sock_kmalloc(sk, sk_fsize, GFP_KERNEL); 768 fp = sock_kmalloc(sk, sk_fsize, GFP_KERNEL);
731 if (!fp) 769 if (!fp)
732 return -ENOMEM; 770 return -ENOMEM;
771
733 if (copy_from_user(fp->insns, fprog->filter, fsize)) { 772 if (copy_from_user(fp->insns, fprog->filter, fsize)) {
734 sock_kfree_s(sk, fp, sk_fsize); 773 sock_kfree_s(sk, fp, sk_fsize);
735 return -EFAULT; 774 return -EFAULT;
@@ -738,6 +777,12 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
738 atomic_set(&fp->refcnt, 1); 777 atomic_set(&fp->refcnt, 1);
739 fp->len = fprog->len; 778 fp->len = fprog->len;
740 779
780 err = sk_store_orig_filter(fp, fprog);
781 if (err) {
782 sk_filter_uncharge(sk, fp);
783 return -ENOMEM;
784 }
785
741 err = __sk_prepare_filter(fp); 786 err = __sk_prepare_filter(fp);
742 if (err) { 787 if (err) {
743 sk_filter_uncharge(sk, fp); 788 sk_filter_uncharge(sk, fp);
@@ -750,6 +795,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
750 795
751 if (old_fp) 796 if (old_fp)
752 sk_filter_uncharge(sk, old_fp); 797 sk_filter_uncharge(sk, old_fp);
798
753 return 0; 799 return 0;
754} 800}
755EXPORT_SYMBOL_GPL(sk_attach_filter); 801EXPORT_SYMBOL_GPL(sk_attach_filter);
@@ -769,6 +815,7 @@ int sk_detach_filter(struct sock *sk)
769 sk_filter_uncharge(sk, filter); 815 sk_filter_uncharge(sk, filter);
770 ret = 0; 816 ret = 0;
771 } 817 }
818
772 return ret; 819 return ret;
773} 820}
774EXPORT_SYMBOL_GPL(sk_detach_filter); 821EXPORT_SYMBOL_GPL(sk_detach_filter);
@@ -851,34 +898,41 @@ void sk_decode_filter(struct sock_filter *filt, struct sock_filter *to)
851 to->