diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2013-04-25 02:53:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-04-29 13:21:30 -0400 |
commit | e8d9612c181b1a68ba5f71384629343466f1bd13 (patch) | |
tree | 16093300e9da78c1c3e272283ae4886d7b3984e8 | |
parent | 76d0eeb1a1579453cfd7c4da22004d4b34187ab4 (diff) |
sock_diag: allow to dump bpf filters
This patch allows to dump BPF filters attached to a socket with
SO_ATTACH_FILTER.
Note that we check CAP_SYS_ADMIN before allowing to dump this info.
For now, only AF_PACKET sockets use this feature.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/sock_diag.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/packet_diag.h | 2 | ||||
-rw-r--r-- | net/core/sock_diag.c | 33 | ||||
-rw-r--r-- | net/packet/diag.c | 4 |
4 files changed, 42 insertions, 0 deletions
diff --git a/include/linux/sock_diag.h b/include/linux/sock_diag.h index e8d702e0fd89..54f91d35e5fd 100644 --- a/include/linux/sock_diag.h +++ b/include/linux/sock_diag.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef __SOCK_DIAG_H__ | 1 | #ifndef __SOCK_DIAG_H__ |
2 | #define __SOCK_DIAG_H__ | 2 | #define __SOCK_DIAG_H__ |
3 | 3 | ||
4 | #include <linux/user_namespace.h> | ||
4 | #include <uapi/linux/sock_diag.h> | 5 | #include <uapi/linux/sock_diag.h> |
5 | 6 | ||
6 | struct sk_buff; | 7 | struct sk_buff; |
@@ -22,5 +23,7 @@ int sock_diag_check_cookie(void *sk, __u32 *cookie); | |||
22 | void sock_diag_save_cookie(void *sk, __u32 *cookie); | 23 | void sock_diag_save_cookie(void *sk, __u32 *cookie); |
23 | 24 | ||
24 | int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr); | 25 | int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr); |
26 | int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk, | ||
27 | struct sk_buff *skb, int attrtype); | ||
25 | 28 | ||
26 | #endif | 29 | #endif |
diff --git a/include/uapi/linux/packet_diag.h b/include/uapi/linux/packet_diag.h index c0802c18c8ad..b2cc0cd9c4d9 100644 --- a/include/uapi/linux/packet_diag.h +++ b/include/uapi/linux/packet_diag.h | |||
@@ -17,6 +17,7 @@ struct packet_diag_req { | |||
17 | #define PACKET_SHOW_RING_CFG 0x00000004 /* Rings configuration parameters */ | 17 | #define PACKET_SHOW_RING_CFG 0x00000004 /* Rings configuration parameters */ |
18 | #define PACKET_SHOW_FANOUT 0x00000008 | 18 | #define PACKET_SHOW_FANOUT 0x00000008 |
19 | #define PACKET_SHOW_MEMINFO 0x00000010 | 19 | #define PACKET_SHOW_MEMINFO 0x00000010 |
20 | #define PACKET_SHOW_FILTER 0x00000020 | ||
20 | 21 | ||
21 | struct packet_diag_msg { | 22 | struct packet_diag_msg { |
22 | __u8 pdiag_family; | 23 | __u8 pdiag_family; |
@@ -35,6 +36,7 @@ enum { | |||
35 | PACKET_DIAG_FANOUT, | 36 | PACKET_DIAG_FANOUT, |
36 | PACKET_DIAG_UID, | 37 | PACKET_DIAG_UID, |
37 | PACKET_DIAG_MEMINFO, | 38 | PACKET_DIAG_MEMINFO, |
39 | PACKET_DIAG_FILTER, | ||
38 | 40 | ||
39 | __PACKET_DIAG_MAX, | 41 | __PACKET_DIAG_MAX, |
40 | }; | 42 | }; |
diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index a29e90cf36b7..d5bef0b0f639 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c | |||
@@ -49,6 +49,39 @@ int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype) | |||
49 | } | 49 | } |
50 | EXPORT_SYMBOL_GPL(sock_diag_put_meminfo); | 50 | EXPORT_SYMBOL_GPL(sock_diag_put_meminfo); |
51 | 51 | ||
52 | int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk, | ||
53 | struct sk_buff *skb, int attrtype) | ||
54 | { | ||
55 | struct nlattr *attr; | ||
56 | struct sk_filter *filter; | ||
57 | unsigned int len; | ||
58 | int err = 0; | ||
59 | |||
60 | if (!ns_capable(user_ns, CAP_NET_ADMIN)) { | ||
61 | nla_reserve(skb, attrtype, 0); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | rcu_read_lock(); | ||
66 | |||
67 | filter = rcu_dereference(sk->sk_filter); | ||
68 | len = filter ? filter->len * sizeof(struct sock_filter) : 0; | ||
69 | |||
70 | attr = nla_reserve(skb, attrtype, len); | ||
71 | if (attr == NULL) { | ||
72 | err = -EMSGSIZE; | ||
73 | goto out; | ||
74 | } | ||
75 | |||
76 | if (filter) | ||
77 | memcpy(nla_data(attr), filter->insns, len); | ||
78 | |||
79 | out: | ||
80 | rcu_read_unlock(); | ||
81 | return err; | ||
82 | } | ||
83 | EXPORT_SYMBOL(sock_diag_put_filterinfo); | ||
84 | |||
52 | void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) | 85 | void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) |
53 | { | 86 | { |
54 | mutex_lock(&sock_diag_table_mutex); | 87 | mutex_lock(&sock_diag_table_mutex); |
diff --git a/net/packet/diag.c b/net/packet/diag.c index 822fe9b33a49..a9584a2f6d69 100644 --- a/net/packet/diag.c +++ b/net/packet/diag.c | |||
@@ -170,6 +170,10 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, | |||
170 | sock_diag_put_meminfo(sk, skb, PACKET_DIAG_MEMINFO)) | 170 | sock_diag_put_meminfo(sk, skb, PACKET_DIAG_MEMINFO)) |
171 | goto out_nlmsg_trim; | 171 | goto out_nlmsg_trim; |
172 | 172 | ||
173 | if ((req->pdiag_show & PACKET_SHOW_FILTER) && | ||
174 | sock_diag_put_filterinfo(user_ns, sk, skb, PACKET_DIAG_FILTER)) | ||
175 | goto out_nlmsg_trim; | ||
176 | |||
173 | return nlmsg_end(skb, nlh); | 177 | return nlmsg_end(skb, nlh); |
174 | 178 | ||
175 | out_nlmsg_trim: | 179 | out_nlmsg_trim: |