diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2014-03-28 13:58:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-31 00:45:09 -0400 |
commit | a3ea269b8bcdbb0c5fa2fd449a436e7987446975 (patch) | |
tree | 9e118e381c14f9a065cc4136be2a9bf6e5257dfb /net/core/sock_diag.c | |
parent | f8bbbfc3b97f4c7a6c7c23185e520b22bfc3a21d (diff) |
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 a8fc92778080 ("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>
Diffstat (limited to 'net/core/sock_diag.c')
-rw-r--r-- | net/core/sock_diag.c | 23 |
1 files changed, 10 insertions, 13 deletions
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index a0e9cf6379de..d7af18859322 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c | |||
@@ -52,9 +52,10 @@ EXPORT_SYMBOL_GPL(sock_diag_put_meminfo); | |||
52 | int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk, | 52 | int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk, |
53 | struct sk_buff *skb, int attrtype) | 53 | struct sk_buff *skb, int attrtype) |
54 | { | 54 | { |
55 | struct nlattr *attr; | 55 | struct sock_fprog_kern *fprog; |
56 | struct sk_filter *filter; | 56 | struct sk_filter *filter; |
57 | unsigned int len; | 57 | struct nlattr *attr; |
58 | unsigned int flen; | ||
58 | int err = 0; | 59 | int err = 0; |
59 | 60 | ||
60 | if (!ns_capable(user_ns, CAP_NET_ADMIN)) { | 61 | 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, | |||
63 | } | 64 | } |
64 | 65 | ||
65 | rcu_read_lock(); | 66 | rcu_read_lock(); |
66 | |||
67 | filter = rcu_dereference(sk->sk_filter); | 67 | filter = rcu_dereference(sk->sk_filter); |
68 | len = filter ? filter->len * sizeof(struct sock_filter) : 0; | 68 | if (!filter) |
69 | goto out; | ||
69 | 70 | ||
70 | attr = nla_reserve(skb, attrtype, len); | 71 | fprog = filter->orig_prog; |
72 | flen = sk_filter_proglen(fprog); | ||
73 | |||
74 | attr = nla_reserve(skb, attrtype, flen); | ||
71 | if (attr == NULL) { | 75 | if (attr == NULL) { |
72 | err = -EMSGSIZE; | 76 | err = -EMSGSIZE; |
73 | goto out; | 77 | goto out; |
74 | } | 78 | } |
75 | 79 | ||
76 | if (filter) { | 80 | memcpy(nla_data(attr), fprog->filter, flen); |
77 | struct sock_filter *fb = (struct sock_filter *)nla_data(attr); | ||
78 | int i; | ||
79 | |||
80 | for (i = 0; i < filter->len; i++, fb++) | ||
81 | sk_decode_filter(&filter->insns[i], fb); | ||
82 | } | ||
83 | |||
84 | out: | 81 | out: |
85 | rcu_read_unlock(); | 82 | rcu_read_unlock(); |
86 | return err; | 83 | return err; |