aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/sock_diag.c
diff options
context:
space:
mode:
authorDaniel Borkmann <dborkman@redhat.com>2014-03-28 13:58:19 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-31 00:45:09 -0400
commita3ea269b8bcdbb0c5fa2fd449a436e7987446975 (patch)
tree9e118e381c14f9a065cc4136be2a9bf6e5257dfb /net/core/sock_diag.c
parentf8bbbfc3b97f4c7a6c7c23185e520b22bfc3a21d (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.c23
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);
52int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk, 52int 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
84out: 81out:
85 rcu_read_unlock(); 82 rcu_read_unlock();
86 return err; 83 return err;