net: diag: Add the ability to destroy a socket.
authorLorenzo Colitti <lorenzo@google.com>
Wed, 16 Dec 2015 03:30:03 +0000 (12:30 +0900)
committerLorenzo Colitti <lorenzo@google.com>
Thu, 25 Feb 2016 00:01:21 +0000 (09:01 +0900)
This patch adds a SOCK_DESTROY operation, a destroy function
pointer to sock_diag_handler, and a diag_destroy function
pointer.  It does not include any implementation code.

[backport of net-next 64be0aed59ad519d6f2160868734f7e278290ac1]

Change-Id: Ic5327ff14b39dd268083ee4c1dc2c934b2820df5
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/sock_diag.h
include/net/sock.h
include/uapi/linux/sock_diag.h
net/core/sock_diag.c

index fddebc6174697a311be8aa06d1e30ed90135d41b..4018b48f2b3b4f115802fba8b67fcc3cd113c773 100644 (file)
@@ -15,6 +15,7 @@ struct sock_diag_handler {
        __u8 family;
        int (*dump)(struct sk_buff *skb, struct nlmsghdr *nlh);
        int (*get_info)(struct sk_buff *skb, struct sock *sk);
+       int (*destroy)(struct sk_buff *skb, struct nlmsghdr *nlh);
 };
 
 int sock_diag_register(const struct sock_diag_handler *h);
@@ -68,4 +69,5 @@ bool sock_diag_has_destroy_listeners(const struct sock *sk)
 }
 void sock_diag_broadcast_destroy(struct sock *sk);
 
+int sock_diag_destroy(struct sock *sk, int err);
 #endif
index 14d3c07340079b7a3e9de54ee635011589247ffd..2d663ee8494daa5b3d8968542bc014472d361187 100644 (file)
@@ -1067,6 +1067,7 @@ struct proto {
        void                    (*destroy_cgroup)(struct mem_cgroup *memcg);
        struct cg_proto         *(*proto_cgroup)(struct mem_cgroup *memcg);
 #endif
+       int                     (*diag_destroy)(struct sock *sk, int err);
 };
 
 int proto_register(struct proto *prot, int alloc_slab);
index 49230d36f9ce783011bd23edb19ba8be0fb751f1..84e66ed670be13611f2a20e9d77ef3b34dfe6ed8 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 
 #define SOCK_DIAG_BY_FAMILY 20
+#define SOCK_DESTROY_BACKPORT 21
 
 struct sock_diag_req {
        __u8    sdiag_family;
index 0c1d58d43f67c46c7a11081d0ecdd30cb5878529..3963c3872c69b806afe6788ec1a4e588adc9cb6e 100644 (file)
@@ -214,7 +214,7 @@ void sock_diag_unregister(const struct sock_diag_handler *hnld)
 }
 EXPORT_SYMBOL_GPL(sock_diag_unregister);
 
-static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
        int err;
        struct sock_diag_req *req = nlmsg_data(nlh);
@@ -234,8 +234,12 @@ static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
        hndl = sock_diag_handlers[req->sdiag_family];
        if (hndl == NULL)
                err = -ENOENT;
-       else
+       else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY)
                err = hndl->dump(skb, nlh);
+       else if (nlh->nlmsg_type == SOCK_DESTROY_BACKPORT && hndl->destroy)
+               err = hndl->destroy(skb, nlh);
+       else
+               err = -EOPNOTSUPP;
        mutex_unlock(&sock_diag_table_mutex);
 
        return err;
@@ -261,7 +265,8 @@ static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 
                return ret;
        case SOCK_DIAG_BY_FAMILY:
-               return __sock_diag_rcv_msg(skb, nlh);
+       case SOCK_DESTROY_BACKPORT:
+               return __sock_diag_cmd(skb, nlh);
        default:
                return -EINVAL;
        }
@@ -295,6 +300,18 @@ static int sock_diag_bind(struct net *net, int group)
        return 0;
 }
 
+int sock_diag_destroy(struct sock *sk, int err)
+{
+       if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (!sk->sk_prot->diag_destroy)
+               return -EOPNOTSUPP;
+
+       return sk->sk_prot->diag_destroy(sk, err);
+}
+EXPORT_SYMBOL_GPL(sock_diag_destroy);
+
 static int __net_init diag_net_init(struct net *net)
 {
        struct netlink_kernel_cfg cfg = {