Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 302d6637 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller
Browse files

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: default avatarJiri Pirko <jpirko@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fca231b2
Loading
Loading
Loading
Loading
+3 −0
Original line number Original line Diff line number Diff line
@@ -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 int sk_filter(struct sock *sk, struct sk_buff *skb);
extern unsigned int sk_run_filter(const struct sk_buff *skb,
extern unsigned int sk_run_filter(const struct sk_buff *skb,
				  const struct sock_filter *filter);
				  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_attach_filter(struct sock_fprog *fprog, struct sock *sk);
extern int sk_detach_filter(struct sock *sk);
extern int sk_detach_filter(struct sock *sk);
extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
extern int sk_chk_filter(struct sock_filter *filter, unsigned int flen);
+62 −4
Original line number Original line Diff line number Diff line
@@ -587,6 +587,67 @@ void sk_filter_release_rcu(struct rcu_head *rcu)
}
}
EXPORT_SYMBOL(sk_filter_release_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
 *	sk_attach_filter - attach a socket filter
 *	@fprog: the filter program
 *	@fprog: the filter program
@@ -617,16 +678,13 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)


	atomic_set(&fp->refcnt, 1);
	atomic_set(&fp->refcnt, 1);
	fp->len = fprog->len;
	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) {
	if (err) {
		sk_filter_uncharge(sk, fp);
		sk_filter_uncharge(sk, fp);
		return err;
		return err;
	}
	}


	bpf_jit_compile(fp);

	old_fp = rcu_dereference_protected(sk->sk_filter,
	old_fp = rcu_dereference_protected(sk->sk_filter,
					   sock_owned_by_user(sk));
					   sock_owned_by_user(sk));
	rcu_assign_pointer(sk->sk_filter, fp);
	rcu_assign_pointer(sk->sk_filter, fp);