1 /* 2 * vsock sock_diag(7) module 3 * 4 * Copyright (C) 2017 Red Hat, Inc. 5 * Author: Stefan Hajnoczi <stefanha@redhat.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation version 2 and no later version. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 */ 16 17 #include <linux/module.h> 18 #include <linux/sock_diag.h> 19 #include <linux/vm_sockets_diag.h> 20 #include <net/af_vsock.h> 21 22 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, 23 u32 portid, u32 seq, u32 flags) 24 { 25 struct vsock_sock *vsk = vsock_sk(sk); 26 struct vsock_diag_msg *rep; 27 struct nlmsghdr *nlh; 28 29 nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep), 30 flags); 31 if (!nlh) 32 return -EMSGSIZE; 33 34 rep = nlmsg_data(nlh); 35 rep->vdiag_family = AF_VSOCK; 36 37 /* Lock order dictates that sk_lock is acquired before 38 * vsock_table_lock, so we cannot lock here. Simply don't take 39 * sk_lock; sk is guaranteed to stay alive since vsock_table_lock is 40 * held. 41 */ 42 rep->vdiag_type = sk->sk_type; 43 rep->vdiag_state = sk->sk_state; 44 rep->vdiag_shutdown = sk->sk_shutdown; 45 rep->vdiag_src_cid = vsk->local_addr.svm_cid; 46 rep->vdiag_src_port = vsk->local_addr.svm_port; 47 rep->vdiag_dst_cid = vsk->remote_addr.svm_cid; 48 rep->vdiag_dst_port = vsk->remote_addr.svm_port; 49 rep->vdiag_ino = sock_i_ino(sk); 50 51 sock_diag_save_cookie(sk, rep->vdiag_cookie); 52 53 return 0; 54 } 55 56 static int vsock_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) 57 { 58 struct vsock_diag_req *req; 59 struct vsock_sock *vsk; 60 unsigned int bucket; 61 unsigned int last_i; 62 unsigned int table; 63 struct net *net; 64 unsigned int i; 65 66 req = nlmsg_data(cb->nlh); 67 net = sock_net(skb->sk); 68 69 /* State saved between calls: */ 70 table = cb->args[0]; 71 bucket = cb->args[1]; 72 i = last_i = cb->args[2]; 73 74 /* TODO VMCI pending sockets? */ 75 76 spin_lock_bh(&vsock_table_lock); 77 78 /* Bind table (locally created sockets) */ 79 if (table == 0) { 80 while (bucket < ARRAY_SIZE(vsock_bind_table)) { 81 struct list_head *head = &vsock_bind_table[bucket]; 82 83 i = 0; 84 list_for_each_entry(vsk, head, bound_table) { 85 struct sock *sk = sk_vsock(vsk); 86 87 if (!net_eq(sock_net(sk), net)) 88 continue; 89 if (i < last_i) 90 goto next_bind; 91 if (!(req->vdiag_states & (1 << sk->sk_state))) 92 goto next_bind; 93 if (sk_diag_fill(sk, skb, 94 NETLINK_CB(cb->skb).portid, 95 cb->nlh->nlmsg_seq, 96 NLM_F_MULTI) < 0) 97 goto done; 98 next_bind: 99 i++; 100 } 101 last_i = 0; 102 bucket++; 103 } 104 105 table++; 106 bucket = 0; 107 } 108 109 /* Connected table (accepted connections) */ 110 while (bucket < ARRAY_SIZE(vsock_connected_table)) { 111 struct list_head *head = &vsock_connected_table[bucket]; 112 113 i = 0; 114 list_for_each_entry(vsk, head, connected_table) { 115 struct sock *sk = sk_vsock(vsk); 116 117 /* Skip sockets we've already seen above */ 118 if (__vsock_in_bound_table(vsk)) 119 continue; 120 121 if (!net_eq(sock_net(sk), net)) 122 continue; 123 if (i < last_i) 124 goto next_connected; 125 if (!(req->vdiag_states & (1 << sk->sk_state))) 126 goto next_connected; 127 if (sk_diag_fill(sk, skb, 128 NETLINK_CB(cb->skb).portid, 129 cb->nlh->nlmsg_seq, 130 NLM_F_MULTI) < 0) 131 goto done; 132 next_connected: 133 i++; 134 } 135 last_i = 0; 136 bucket++; 137 } 138 139 done: 140 spin_unlock_bh(&vsock_table_lock); 141 142 cb->args[0] = table; 143 cb->args[1] = bucket; 144 cb->args[2] = i; 145 146 return skb->len; 147 } 148 149 static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) 150 { 151 int hdrlen = sizeof(struct vsock_diag_req); 152 struct net *net = sock_net(skb->sk); 153 154 if (nlmsg_len(h) < hdrlen) 155 return -EINVAL; 156 157 if (h->nlmsg_flags & NLM_F_DUMP) { 158 struct netlink_dump_control c = { 159 .dump = vsock_diag_dump, 160 }; 161 return netlink_dump_start(net->diag_nlsk, skb, h, &c); 162 } 163 164 return -EOPNOTSUPP; 165 } 166 167 static const struct sock_diag_handler vsock_diag_handler = { 168 .family = AF_VSOCK, 169 .dump = vsock_diag_handler_dump, 170 }; 171 172 static int __init vsock_diag_init(void) 173 { 174 return sock_diag_register(&vsock_diag_handler); 175 } 176 177 static void __exit vsock_diag_exit(void) 178 { 179 sock_diag_unregister(&vsock_diag_handler); 180 } 181 182 module_init(vsock_diag_init); 183 module_exit(vsock_diag_exit); 184 MODULE_LICENSE("GPL"); 185 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 186 40 /* AF_VSOCK */); 187