summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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: