1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/module.h> 3 4 #include <net/sock.h> 5 #include <linux/netlink.h> 6 #include <linux/sock_diag.h> 7 #include <linux/netlink_diag.h> 8 #include <linux/rhashtable.h> 9 10 #include "af_netlink.h" 11 12 static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb) 13 { 14 struct netlink_sock *nlk = nlk_sk(sk); 15 unsigned long *groups; 16 unsigned int ngroups; 17 18 /* Hashed sockets are dumped from the rhashtable walk, which only 19 * holds rcu_read_lock(), while netlink_realloc_groups() can replace 20 * nlk->groups and nlk->ngroups at any time. 21 * 22 * Read nlk->ngroups first : this pairs with smp_store_release() 23 * from netlink_realloc_groups(), so that we can not use the new 24 * (bigger) size with the old (smaller) buffer. The old buffer is 25 * freed after an RCU grace period. 26 */ 27 ngroups = smp_load_acquire(&nlk->ngroups); 28 groups = READ_ONCE(nlk->groups); 29 if (!groups) 30 return 0; 31 32 return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(ngroups), groups); 33 } 34 35 static int sk_diag_put_flags(struct sock *sk, struct sk_buff *skb) 36 { 37 struct netlink_sock *nlk = nlk_sk(sk); 38 u32 flags = 0; 39 40 if (nlk->cb_running) 41 flags |= NDIAG_FLAG_CB_RUNNING; 42 if (nlk_test_bit(RECV_PKTINFO, sk)) 43 flags |= NDIAG_FLAG_PKTINFO; 44 if (nlk_test_bit(BROADCAST_SEND_ERROR, sk)) 45 flags |= NDIAG_FLAG_BROADCAST_ERROR; 46 if (nlk_test_bit(RECV_NO_ENOBUFS, sk)) 47 flags |= NDIAG_FLAG_NO_ENOBUFS; 48 if (nlk_test_bit(LISTEN_ALL_NSID, sk)) 49 flags |= NDIAG_FLAG_LISTEN_ALL_NSID; 50 if (nlk_test_bit(CAP_ACK, sk)) 51 flags |= NDIAG_FLAG_CAP_ACK; 52 53 return nla_put_u32(skb, NETLINK_DIAG_FLAGS, flags); 54 } 55 56 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, 57 struct netlink_diag_req *req, 58 u32 portid, u32 seq, u32 flags, u64 sk_ino) 59 { 60 struct nlmsghdr *nlh; 61 struct netlink_diag_msg *rep; 62 struct netlink_sock *nlk = nlk_sk(sk); 63 64 nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep), 65 flags); 66 if (!nlh) 67 return -EMSGSIZE; 68 69 rep = nlmsg_data(nlh); 70 rep->ndiag_family = AF_NETLINK; 71 rep->ndiag_type = sk->sk_type; 72 rep->ndiag_protocol = sk->sk_protocol; 73 rep->ndiag_state = sk->sk_state; 74 75 rep->ndiag_ino = sk_ino; 76 rep->ndiag_portid = nlk->portid; 77 rep->ndiag_dst_portid = nlk->dst_portid; 78 rep->ndiag_dst_group = nlk->dst_group; 79 sock_diag_save_cookie(sk, rep->ndiag_cookie); 80 81 if ((req->ndiag_show & NDIAG_SHOW_GROUPS) && 82 sk_diag_dump_groups(sk, skb)) 83 goto out_nlmsg_trim; 84 85 if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) && 86 sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO)) 87 goto out_nlmsg_trim; 88 89 if ((req->ndiag_show & NDIAG_SHOW_FLAGS) && 90 sk_diag_put_flags(sk, skb)) 91 goto out_nlmsg_trim; 92 93 nlmsg_end(skb, nlh); 94 return 0; 95 96 out_nlmsg_trim: 97 nlmsg_cancel(skb, nlh); 98 return -EMSGSIZE; 99 } 100 101 static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, 102 int protocol, int s_num) 103 { 104 struct rhashtable_iter *hti = (void *)cb->args[2]; 105 struct netlink_table *tbl = &nl_table[protocol]; 106 struct net *net = sock_net(skb->sk); 107 struct netlink_diag_req *req; 108 struct netlink_sock *nlsk; 109 unsigned long flags; 110 struct sock *sk; 111 int num = 2; 112 int ret = 0; 113 114 req = nlmsg_data(cb->nlh); 115 116 if (s_num > 1) 117 goto mc_list; 118 119 num--; 120 121 if (!hti) { 122 hti = kmalloc_obj(*hti); 123 if (!hti) 124 return -ENOMEM; 125 126 cb->args[2] = (long)hti; 127 } 128 129 if (!s_num) 130 rhashtable_walk_enter(&tbl->hash, hti); 131 132 rhashtable_walk_start(hti); 133 134 while ((nlsk = rhashtable_walk_next(hti))) { 135 if (IS_ERR(nlsk)) { 136 ret = PTR_ERR(nlsk); 137 if (ret == -EAGAIN) { 138 ret = 0; 139 continue; 140 } 141 break; 142 } 143 144 sk = (struct sock *)nlsk; 145 146 if (!net_eq(sock_net(sk), net)) 147 continue; 148 149 if (sk_diag_fill(sk, skb, req, 150 NETLINK_CB(cb->skb).portid, 151 cb->nlh->nlmsg_seq, 152 NLM_F_MULTI, 153 sock_i_ino(sk)) < 0) { 154 ret = 1; 155 break; 156 } 157 } 158 159 rhashtable_walk_stop(hti); 160 161 if (ret) 162 goto done; 163 164 rhashtable_walk_exit(hti); 165 num++; 166 167 mc_list: 168 read_lock_irqsave(&nl_table_lock, flags); 169 sk_for_each_bound(sk, &tbl->mc_list) { 170 if (sk_hashed(sk)) 171 continue; 172 if (!net_eq(sock_net(sk), net)) 173 continue; 174 if (num < s_num) { 175 num++; 176 continue; 177 } 178 179 if (sk_diag_fill(sk, skb, req, 180 NETLINK_CB(cb->skb).portid, 181 cb->nlh->nlmsg_seq, 182 NLM_F_MULTI, 183 sock_i_ino(sk)) < 0) { 184 ret = 1; 185 break; 186 } 187 num++; 188 } 189 read_unlock_irqrestore(&nl_table_lock, flags); 190 191 done: 192 cb->args[0] = num; 193 194 return ret; 195 } 196 197 static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) 198 { 199 struct netlink_diag_req *req; 200 int s_num = cb->args[0]; 201 int err = 0; 202 203 req = nlmsg_data(cb->nlh); 204 205 if (req->sdiag_protocol == NDIAG_PROTO_ALL) { 206 int i; 207 208 for (i = cb->args[1]; i < MAX_LINKS; i++) { 209 err = __netlink_diag_dump(skb, cb, i, s_num); 210 if (err) 211 break; 212 s_num = 0; 213 } 214 cb->args[1] = i; 215 } else { 216 if (req->sdiag_protocol >= MAX_LINKS) 217 return -ENOENT; 218 219 err = __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num); 220 } 221 222 return err <= 0 ? err : skb->len; 223 } 224 225 static int netlink_diag_dump_done(struct netlink_callback *cb) 226 { 227 struct rhashtable_iter *hti = (void *)cb->args[2]; 228 229 if (cb->args[0] == 1) 230 rhashtable_walk_exit(hti); 231 232 kfree(hti); 233 234 return 0; 235 } 236 237 static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) 238 { 239 int hdrlen = sizeof(struct netlink_diag_req); 240 struct net *net = sock_net(skb->sk); 241 242 if (nlmsg_len(h) < hdrlen) 243 return -EINVAL; 244 245 if (h->nlmsg_flags & NLM_F_DUMP) { 246 struct netlink_dump_control c = { 247 .dump = netlink_diag_dump, 248 .done = netlink_diag_dump_done, 249 }; 250 return netlink_dump_start(net->diag_nlsk, skb, h, &c); 251 } else 252 return -EOPNOTSUPP; 253 } 254 255 static const struct sock_diag_handler netlink_diag_handler = { 256 .owner = THIS_MODULE, 257 .family = AF_NETLINK, 258 .dump = netlink_diag_handler_dump, 259 }; 260 261 static int __init netlink_diag_init(void) 262 { 263 return sock_diag_register(&netlink_diag_handler); 264 } 265 266 static void __exit netlink_diag_exit(void) 267 { 268 sock_diag_unregister(&netlink_diag_handler); 269 } 270 271 module_init(netlink_diag_init); 272 module_exit(netlink_diag_exit); 273 MODULE_DESCRIPTION("Netlink-based socket monitoring/diagnostic interface (sock_diag)"); 274 MODULE_LICENSE("GPL"); 275 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 16 /* AF_NETLINK */); 276