net: filter: keep original BPF program around

In order to open up the possibility to internally transform a BPF program
into an alternative and possibly non-trivial reversible representation, we
need to keep the original BPF program around, so that it can be passed back
to user space w/o the need of a complex decoder.

The reason for that use case resides in commit a8fc927780 ("sk-filter:
Add ability to get socket filter program (v2)"), that is, the ability
to retrieve the currently attached BPF filter from a given socket used
mainly by the checkpoint-restore project, for example.

Therefore, we add two helpers sk_{store,release}_orig_filter for taking
care of that. In the sk_unattached_filter_create() case, there's no such
possibility/requirement to retrieve a loaded BPF program. Therefore, we
can spare us the work in that case.

This approach will simplify and slightly speed up both, sk_get_filter()
and sock_diag_put_filterinfo() handlers as we won't need to successively
decode filters anymore through sk_decode_filter(). As we still need
sk_decode_filter() later on, we're keeping it around.

Joint work with Alexei Starovoitov.

Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Daniel Borkmann 2014-03-28 18:58:19 +01:00 committed by David S. Miller
parent f8bbbfc3b9
commit a3ea269b8b
3 changed files with 93 additions and 31 deletions

View file

@ -52,9 +52,10 @@ EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
struct sk_buff *skb, int attrtype)
{
struct nlattr *attr;
struct sock_fprog_kern *fprog;
struct sk_filter *filter;
unsigned int len;
struct nlattr *attr;
unsigned int flen;
int err = 0;
if (!ns_capable(user_ns, CAP_NET_ADMIN)) {
@ -63,24 +64,20 @@ int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
}
rcu_read_lock();
filter = rcu_dereference(sk->sk_filter);
len = filter ? filter->len * sizeof(struct sock_filter) : 0;
if (!filter)
goto out;
attr = nla_reserve(skb, attrtype, len);
fprog = filter->orig_prog;
flen = sk_filter_proglen(fprog);
attr = nla_reserve(skb, attrtype, flen);
if (attr == NULL) {
err = -EMSGSIZE;
goto out;
}
if (filter) {
struct sock_filter *fb = (struct sock_filter *)nla_data(attr);
int i;
for (i = 0; i < filter->len; i++, fb++)
sk_decode_filter(&filter->insns[i], fb);
}
memcpy(nla_data(attr), fprog->filter, flen);
out:
rcu_read_unlock();
return err;