diag.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <linux/module.h>
  3. #include <net/sock.h>
  4. #include <linux/netlink.h>
  5. #include <linux/sock_diag.h>
  6. #include <linux/netlink_diag.h>
  7. #include <linux/rhashtable.h>
  8. #include "af_netlink.h"
  9. static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb)
  10. {
  11. struct netlink_sock *nlk = nlk_sk(sk);
  12. if (nlk->groups == NULL)
  13. return 0;
  14. return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(nlk->ngroups),
  15. nlk->groups);
  16. }
  17. static int sk_diag_put_flags(struct sock *sk, struct sk_buff *skb)
  18. {
  19. struct netlink_sock *nlk = nlk_sk(sk);
  20. u32 flags = 0;
  21. if (nlk->cb_running)
  22. flags |= NDIAG_FLAG_CB_RUNNING;
  23. if (nlk_test_bit(RECV_PKTINFO, sk))
  24. flags |= NDIAG_FLAG_PKTINFO;
  25. if (nlk_test_bit(BROADCAST_SEND_ERROR, sk))
  26. flags |= NDIAG_FLAG_BROADCAST_ERROR;
  27. if (nlk_test_bit(RECV_NO_ENOBUFS, sk))
  28. flags |= NDIAG_FLAG_NO_ENOBUFS;
  29. if (nlk_test_bit(LISTEN_ALL_NSID, sk))
  30. flags |= NDIAG_FLAG_LISTEN_ALL_NSID;
  31. if (nlk_test_bit(CAP_ACK, sk))
  32. flags |= NDIAG_FLAG_CAP_ACK;
  33. return nla_put_u32(skb, NETLINK_DIAG_FLAGS, flags);
  34. }
  35. static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
  36. struct netlink_diag_req *req,
  37. u32 portid, u32 seq, u32 flags, int sk_ino)
  38. {
  39. struct nlmsghdr *nlh;
  40. struct netlink_diag_msg *rep;
  41. struct netlink_sock *nlk = nlk_sk(sk);
  42. nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
  43. flags);
  44. if (!nlh)
  45. return -EMSGSIZE;
  46. rep = nlmsg_data(nlh);
  47. rep->ndiag_family = AF_NETLINK;
  48. rep->ndiag_type = sk->sk_type;
  49. rep->ndiag_protocol = sk->sk_protocol;
  50. rep->ndiag_state = sk->sk_state;
  51. rep->ndiag_ino = sk_ino;
  52. rep->ndiag_portid = nlk->portid;
  53. rep->ndiag_dst_portid = nlk->dst_portid;
  54. rep->ndiag_dst_group = nlk->dst_group;
  55. sock_diag_save_cookie(sk, rep->ndiag_cookie);
  56. if ((req->ndiag_show & NDIAG_SHOW_GROUPS) &&
  57. sk_diag_dump_groups(sk, skb))
  58. goto out_nlmsg_trim;
  59. if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) &&
  60. sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO))
  61. goto out_nlmsg_trim;
  62. if ((req->ndiag_show & NDIAG_SHOW_FLAGS) &&
  63. sk_diag_put_flags(sk, skb))
  64. goto out_nlmsg_trim;
  65. nlmsg_end(skb, nlh);
  66. return 0;
  67. out_nlmsg_trim:
  68. nlmsg_cancel(skb, nlh);
  69. return -EMSGSIZE;
  70. }
  71. static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
  72. int protocol, int s_num)
  73. {
  74. struct rhashtable_iter *hti = (void *)cb->args[2];
  75. struct netlink_table *tbl = &nl_table[protocol];
  76. struct net *net = sock_net(skb->sk);
  77. struct netlink_diag_req *req;
  78. struct netlink_sock *nlsk;
  79. unsigned long flags;
  80. struct sock *sk;
  81. int num = 2;
  82. int ret = 0;
  83. req = nlmsg_data(cb->nlh);
  84. if (s_num > 1)
  85. goto mc_list;
  86. num--;
  87. if (!hti) {
  88. hti = kmalloc_obj(*hti);
  89. if (!hti)
  90. return -ENOMEM;
  91. cb->args[2] = (long)hti;
  92. }
  93. if (!s_num)
  94. rhashtable_walk_enter(&tbl->hash, hti);
  95. rhashtable_walk_start(hti);
  96. while ((nlsk = rhashtable_walk_next(hti))) {
  97. if (IS_ERR(nlsk)) {
  98. ret = PTR_ERR(nlsk);
  99. if (ret == -EAGAIN) {
  100. ret = 0;
  101. continue;
  102. }
  103. break;
  104. }
  105. sk = (struct sock *)nlsk;
  106. if (!net_eq(sock_net(sk), net))
  107. continue;
  108. if (sk_diag_fill(sk, skb, req,
  109. NETLINK_CB(cb->skb).portid,
  110. cb->nlh->nlmsg_seq,
  111. NLM_F_MULTI,
  112. sock_i_ino(sk)) < 0) {
  113. ret = 1;
  114. break;
  115. }
  116. }
  117. rhashtable_walk_stop(hti);
  118. if (ret)
  119. goto done;
  120. rhashtable_walk_exit(hti);
  121. num++;
  122. mc_list:
  123. read_lock_irqsave(&nl_table_lock, flags);
  124. sk_for_each_bound(sk, &tbl->mc_list) {
  125. if (sk_hashed(sk))
  126. continue;
  127. if (!net_eq(sock_net(sk), net))
  128. continue;
  129. if (num < s_num) {
  130. num++;
  131. continue;
  132. }
  133. if (sk_diag_fill(sk, skb, req,
  134. NETLINK_CB(cb->skb).portid,
  135. cb->nlh->nlmsg_seq,
  136. NLM_F_MULTI,
  137. sock_i_ino(sk)) < 0) {
  138. ret = 1;
  139. break;
  140. }
  141. num++;
  142. }
  143. read_unlock_irqrestore(&nl_table_lock, flags);
  144. done:
  145. cb->args[0] = num;
  146. return ret;
  147. }
  148. static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
  149. {
  150. struct netlink_diag_req *req;
  151. int s_num = cb->args[0];
  152. int err = 0;
  153. req = nlmsg_data(cb->nlh);
  154. if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
  155. int i;
  156. for (i = cb->args[1]; i < MAX_LINKS; i++) {
  157. err = __netlink_diag_dump(skb, cb, i, s_num);
  158. if (err)
  159. break;
  160. s_num = 0;
  161. }
  162. cb->args[1] = i;
  163. } else {
  164. if (req->sdiag_protocol >= MAX_LINKS)
  165. return -ENOENT;
  166. err = __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
  167. }
  168. return err <= 0 ? err : skb->len;
  169. }
  170. static int netlink_diag_dump_done(struct netlink_callback *cb)
  171. {
  172. struct rhashtable_iter *hti = (void *)cb->args[2];
  173. if (cb->args[0] == 1)
  174. rhashtable_walk_exit(hti);
  175. kfree(hti);
  176. return 0;
  177. }
  178. static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
  179. {
  180. int hdrlen = sizeof(struct netlink_diag_req);
  181. struct net *net = sock_net(skb->sk);
  182. if (nlmsg_len(h) < hdrlen)
  183. return -EINVAL;
  184. if (h->nlmsg_flags & NLM_F_DUMP) {
  185. struct netlink_dump_control c = {
  186. .dump = netlink_diag_dump,
  187. .done = netlink_diag_dump_done,
  188. };
  189. return netlink_dump_start(net->diag_nlsk, skb, h, &c);
  190. } else
  191. return -EOPNOTSUPP;
  192. }
  193. static const struct sock_diag_handler netlink_diag_handler = {
  194. .owner = THIS_MODULE,
  195. .family = AF_NETLINK,
  196. .dump = netlink_diag_handler_dump,
  197. };
  198. static int __init netlink_diag_init(void)
  199. {
  200. return sock_diag_register(&netlink_diag_handler);
  201. }
  202. static void __exit netlink_diag_exit(void)
  203. {
  204. sock_diag_unregister(&netlink_diag_handler);
  205. }
  206. module_init(netlink_diag_init);
  207. module_exit(netlink_diag_exit);
  208. MODULE_DESCRIPTION("Netlink-based socket monitoring/diagnostic interface (sock_diag)");
  209. MODULE_LICENSE("GPL");
  210. MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 16 /* AF_NETLINK */);