summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2013-04-25 06:53:54 +0000
committerDavid S. Miller <davem@davemloft.net>2013-04-29 13:21:30 -0400
commite8d9612c181b1a68ba5f71384629343466f1bd13 (patch)
tree16093300e9da78c1c3e272283ae4886d7b3984e8
parent76d0eeb1a1579453cfd7c4da22004d4b34187ab4 (diff)
downloadlinux-e8d9612c181b1a68ba5f71384629343466f1bd13.tar.bz2
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.h3
-rw-r--r--include/uapi/linux/packet_diag.h2
-rw-r--r--net/core/sock_diag.c33
-rw-r--r--net/packet/diag.c4
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 @@
#ifndef __SOCK_DIAG_H__
#define __SOCK_DIAG_H__
+#include <linux/user_namespace.h>
#include <uapi/linux/sock_diag.h>
struct sk_buff;
@@ -22,5 +23,7 @@ int sock_diag_check_cookie(void *sk, __u32 *cookie);
void sock_diag_save_cookie(void *sk, __u32 *cookie);
int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr);
+int sock_diag_put_filterinfo(struct user_namespace *user_ns, struct sock *sk,
+ struct sk_buff *skb, int attrtype);
#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 {
#define PACKET_SHOW_RING_CFG 0x00000004 /* Rings configuration parameters */
#define PACKET_SHOW_FANOUT 0x00000008
#define PACKET_SHOW_MEMINFO 0x00000010
+#define PACKET_SHOW_FILTER 0x00000020
struct packet_diag_msg {
__u8 pdiag_family;
@@ -35,6 +36,7 @@ enum {
PACKET_DIAG_FANOUT,
PACKET_DIAG_UID,
PACKET_DIAG_MEMINFO,
+ PACKET_DIAG_FILTER,
__PACKET_DIAG_MAX,
};
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)
}
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 sk_filter *filter;
+ unsigned int len;
+ int err = 0;
+
+ if (!ns_capable(user_ns, CAP_NET_ADMIN)) {
+ nla_reserve(skb, attrtype, 0);
+ return 0;
+ }
+
+ rcu_read_lock();
+
+ filter = rcu_dereference(sk->sk_filter);
+ len = filter ? filter->len * sizeof(struct sock_filter) : 0;
+
+ attr = nla_reserve(skb, attrtype, len);
+ if (attr == NULL) {
+ err = -EMSGSIZE;
+ goto out;
+ }
+
+ if (filter)
+ memcpy(nla_data(attr), filter->insns, len);
+
+out:
+ rcu_read_unlock();
+ return err;
+}
+EXPORT_SYMBOL(sock_diag_put_filterinfo);
+
void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
{
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,
sock_diag_put_meminfo(sk, skb, PACKET_DIAG_MEMINFO))
goto out_nlmsg_trim;
+ if ((req->pdiag_show & PACKET_SHOW_FILTER) &&
+ sock_diag_put_filterinfo(user_ns, sk, skb, PACKET_DIAG_FILTER))
+ goto out_nlmsg_trim;
+
return nlmsg_end(skb, nlh);
out_nlmsg_trim: