121 lines
3.5 KiB
Diff
121 lines
3.5 KiB
Diff
|
From: Jiri Pirko <jpirko@redhat.com>
|
||
|
Date: Sat, 31 Mar 2012 11:01:19 +0000
|
||
|
Subject: filter: Allow to create sk-unattached filters
|
||
|
|
||
|
commit 302d663740cfaf2c364df6bb61cd339014ed714c upstream.
|
||
|
|
||
|
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>
|
||
|
---
|
||
|
include/linux/filter.h | 3 +++
|
||
|
net/core/filter.c | 66 +++++++++++++++++++++++++++++++++++++++++++++---
|
||
|
2 files changed, 65 insertions(+), 4 deletions(-)
|
||
|
|
||
|
diff --git a/include/linux/filter.h b/include/linux/filter.h
|
||
|
index 8eeb205..92dd993 100644
|
||
|
--- a/include/linux/filter.h
|
||
|
+++ b/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/net/core/filter.c b/net/core/filter.c
|
||
|
index 5dea452..cfbea88 100644
|
||
|
--- a/net/core/filter.c
|
||
|
+++ b/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);
|