From 1b2da00d7f00ab6e9b33120f1a9e7aa426358bec Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 31 Mar 2012 11:01:19 +0000 Subject: [PATCH] --- yaml --- r: 300441 b: refs/heads/master c: 302d663740cfaf2c364df6bb61cd339014ed714c h: refs/heads/master i: 300439: bdef6498e7a46b7d8314189a0deffcc5efab44a8 v: v3 --- [refs] | 2 +- trunk/include/linux/filter.h | 3 ++ trunk/net/core/filter.c | 66 +++++++++++++++++++++++++++++++++--- 3 files changed, 66 insertions(+), 5 deletions(-) diff --git a/[refs] b/[refs] index 02ddcce2c2ca..edfd3c47db60 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: fca231b2771cfd4e4f89445cf5c8dd81409b5b3c +refs/heads/master: 302d663740cfaf2c364df6bb61cd339014ed714c diff --git a/trunk/include/linux/filter.h b/trunk/include/linux/filter.h index 8eeb205f298b..92dd9933c43d 100644 --- a/trunk/include/linux/filter.h +++ b/trunk/include/linux/filter.h @@ -153,6 +153,9 @@ static inline unsigned int sk_filter_len(const struct sk_filter *fp) extern int sk_filter(struct sock *sk, struct sk_buff *skb); extern unsigned int sk_run_filter(const struct sk_buff *skb, const struct sock_filter *filter); +extern int sk_unattached_filter_create(struct sk_filter **pfp, + struct sock_fprog *fprog); +extern void sk_unattached_filter_destroy(struct sk_filter *fp); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); extern int sk_detach_filter(struct sock *sk); extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen); diff --git a/trunk/net/core/filter.c b/trunk/net/core/filter.c index 5dea45279215..cfbea889a0eb 100644 --- a/trunk/net/core/filter.c +++ b/trunk/net/core/filter.c @@ -587,6 +587,67 @@ void sk_filter_release_rcu(struct rcu_head *rcu) } EXPORT_SYMBOL(sk_filter_release_rcu); +static int __sk_prepare_filter(struct sk_filter *fp) +{ + int err; + + fp->bpf_func = sk_run_filter; + + err = sk_chk_filter(fp->insns, fp->len); + if (err) + return err; + + bpf_jit_compile(fp); + return 0; +} + +/** + * sk_unattached_filter_create - create an unattached filter + * @fprog: the filter program + * @sk: the socket to use + * + * Create a filter independent ofr any socket. We first run some + * sanity checks on it to make sure it does not explode on us later. + * If an error occurs or there is insufficient memory for the filter + * a negative errno code is returned. On success the return is zero. + */ +int sk_unattached_filter_create(struct sk_filter **pfp, + struct sock_fprog *fprog) +{ + struct sk_filter *fp; + unsigned int fsize = sizeof(struct sock_filter) * fprog->len; + int err; + + /* Make sure new filter is there and in the right amounts. */ + if (fprog->filter == NULL) + return -EINVAL; + + fp = kmalloc(fsize + sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; + memcpy(fp->insns, fprog->filter, fsize); + + atomic_set(&fp->refcnt, 1); + fp->len = fprog->len; + + err = __sk_prepare_filter(fp); + if (err) + goto free_mem; + + *pfp = fp; + return 0; +free_mem: + kfree(fp); + return err; +} +EXPORT_SYMBOL_GPL(sk_unattached_filter_create); + +void sk_unattached_filter_destroy(struct sk_filter *fp) +{ + sk_filter_release(fp); +} +EXPORT_SYMBOL_GPL(sk_unattached_filter_destroy); + /** * sk_attach_filter - attach a socket filter * @fprog: the filter program @@ -617,16 +678,13 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) atomic_set(&fp->refcnt, 1); fp->len = fprog->len; - fp->bpf_func = sk_run_filter; - err = sk_chk_filter(fp->insns, fp->len); + err = __sk_prepare_filter(fp); if (err) { sk_filter_uncharge(sk, fp); return err; } - bpf_jit_compile(fp); - old_fp = rcu_dereference_protected(sk->sk_filter, sock_owned_by_user(sk)); rcu_assign_pointer(sk->sk_filter, fp);