raw_diag.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #include <linux/module.h>
  2. #include <linux/inet_diag.h>
  3. #include <linux/sock_diag.h>
  4. #include <net/inet_sock.h>
  5. #include <net/raw.h>
  6. #include <net/rawv6.h>
  7. #ifdef pr_fmt
  8. # undef pr_fmt
  9. #endif
  10. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  11. static struct raw_hashinfo *
  12. raw_get_hashinfo(const struct inet_diag_req_v2 *r)
  13. {
  14. if (r->sdiag_family == AF_INET) {
  15. return &raw_v4_hashinfo;
  16. #if IS_ENABLED(CONFIG_IPV6)
  17. } else if (r->sdiag_family == AF_INET6) {
  18. return &raw_v6_hashinfo;
  19. #endif
  20. } else {
  21. pr_warn_once("Unexpected inet family %d\n",
  22. r->sdiag_family);
  23. WARN_ON_ONCE(1);
  24. return ERR_PTR(-EINVAL);
  25. }
  26. }
  27. /*
  28. * Due to requirement of not breaking user API we can't simply
  29. * rename @pad field in inet_diag_req_v2 structure, instead
  30. * use helper to figure it out.
  31. */
  32. static struct sock *raw_lookup(struct net *net, struct sock *from,
  33. const struct inet_diag_req_v2 *req)
  34. {
  35. struct inet_diag_req_raw *r = (void *)req;
  36. struct sock *sk = NULL;
  37. if (r->sdiag_family == AF_INET)
  38. sk = __raw_v4_lookup(net, from, r->sdiag_raw_protocol,
  39. r->id.idiag_dst[0],
  40. r->id.idiag_src[0],
  41. r->id.idiag_if);
  42. #if IS_ENABLED(CONFIG_IPV6)
  43. else
  44. sk = __raw_v6_lookup(net, from, r->sdiag_raw_protocol,
  45. (const struct in6_addr *)r->id.idiag_src,
  46. (const struct in6_addr *)r->id.idiag_dst,
  47. r->id.idiag_if);
  48. #endif
  49. return sk;
  50. }
  51. static struct sock *raw_sock_get(struct net *net, const struct inet_diag_req_v2 *r)
  52. {
  53. struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
  54. struct sock *sk = NULL, *s;
  55. int slot;
  56. if (IS_ERR(hashinfo))
  57. return ERR_CAST(hashinfo);
  58. read_lock(&hashinfo->lock);
  59. for (slot = 0; slot < RAW_HTABLE_SIZE; slot++) {
  60. sk_for_each(s, &hashinfo->ht[slot]) {
  61. sk = raw_lookup(net, s, r);
  62. if (sk) {
  63. /*
  64. * Grab it and keep until we fill
  65. * diag meaage to be reported, so
  66. * caller should call sock_put then.
  67. * We can do that because we're keeping
  68. * hashinfo->lock here.
  69. */
  70. sock_hold(sk);
  71. goto out_unlock;
  72. }
  73. }
  74. }
  75. out_unlock:
  76. read_unlock(&hashinfo->lock);
  77. return sk ? sk : ERR_PTR(-ENOENT);
  78. }
  79. static int raw_diag_dump_one(struct sk_buff *in_skb,
  80. const struct nlmsghdr *nlh,
  81. const struct inet_diag_req_v2 *r)
  82. {
  83. struct net *net = sock_net(in_skb->sk);
  84. struct sk_buff *rep;
  85. struct sock *sk;
  86. int err;
  87. sk = raw_sock_get(net, r);
  88. if (IS_ERR(sk))
  89. return PTR_ERR(sk);
  90. rep = nlmsg_new(sizeof(struct inet_diag_msg) +
  91. sizeof(struct inet_diag_meminfo) + 64,
  92. GFP_KERNEL);
  93. if (!rep) {
  94. sock_put(sk);
  95. return -ENOMEM;
  96. }
  97. err = inet_sk_diag_fill(sk, NULL, rep, r,
  98. sk_user_ns(NETLINK_CB(in_skb).sk),
  99. NETLINK_CB(in_skb).portid,
  100. nlh->nlmsg_seq, 0, nlh,
  101. netlink_net_capable(in_skb, CAP_NET_ADMIN));
  102. sock_put(sk);
  103. if (err < 0) {
  104. kfree_skb(rep);
  105. return err;
  106. }
  107. err = netlink_unicast(net->diag_nlsk, rep,
  108. NETLINK_CB(in_skb).portid,
  109. MSG_DONTWAIT);
  110. if (err > 0)
  111. err = 0;
  112. return err;
  113. }
  114. static int sk_diag_dump(struct sock *sk, struct sk_buff *skb,
  115. struct netlink_callback *cb,
  116. const struct inet_diag_req_v2 *r,
  117. struct nlattr *bc, bool net_admin)
  118. {
  119. if (!inet_diag_bc_sk(bc, sk))
  120. return 0;
  121. return inet_sk_diag_fill(sk, NULL, skb, r,
  122. sk_user_ns(NETLINK_CB(cb->skb).sk),
  123. NETLINK_CB(cb->skb).portid,
  124. cb->nlh->nlmsg_seq, NLM_F_MULTI,
  125. cb->nlh, net_admin);
  126. }
  127. static void raw_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
  128. const struct inet_diag_req_v2 *r, struct nlattr *bc)
  129. {
  130. bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN);
  131. struct raw_hashinfo *hashinfo = raw_get_hashinfo(r);
  132. struct net *net = sock_net(skb->sk);
  133. int num, s_num, slot, s_slot;
  134. struct sock *sk = NULL;
  135. if (IS_ERR(hashinfo))
  136. return;
  137. s_slot = cb->args[0];
  138. num = s_num = cb->args[1];
  139. read_lock(&hashinfo->lock);
  140. for (slot = s_slot; slot < RAW_HTABLE_SIZE; s_num = 0, slot++) {
  141. num = 0;
  142. sk_for_each(sk, &hashinfo->ht[slot]) {
  143. struct inet_sock *inet = inet_sk(sk);
  144. if (!net_eq(sock_net(sk), net))
  145. continue;
  146. if (num < s_num)
  147. goto next;
  148. if (sk->sk_family != r->sdiag_family)
  149. goto next;
  150. if (r->id.idiag_sport != inet->inet_sport &&
  151. r->id.idiag_sport)
  152. goto next;
  153. if (r->id.idiag_dport != inet->inet_dport &&
  154. r->id.idiag_dport)
  155. goto next;
  156. if (sk_diag_dump(sk, skb, cb, r, bc, net_admin) < 0)
  157. goto out_unlock;
  158. next:
  159. num++;
  160. }
  161. }
  162. out_unlock:
  163. read_unlock(&hashinfo->lock);
  164. cb->args[0] = slot;
  165. cb->args[1] = num;
  166. }
  167. static void raw_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
  168. void *info)
  169. {
  170. r->idiag_rqueue = sk_rmem_alloc_get(sk);
  171. r->idiag_wqueue = sk_wmem_alloc_get(sk);
  172. }
  173. #ifdef CONFIG_INET_DIAG_DESTROY
  174. static int raw_diag_destroy(struct sk_buff *in_skb,
  175. const struct inet_diag_req_v2 *r)
  176. {
  177. struct net *net = sock_net(in_skb->sk);
  178. struct sock *sk;
  179. int err;
  180. sk = raw_sock_get(net, r);
  181. if (IS_ERR(sk))
  182. return PTR_ERR(sk);
  183. err = sock_diag_destroy(sk, ECONNABORTED);
  184. sock_put(sk);
  185. return err;
  186. }
  187. #endif
  188. static const struct inet_diag_handler raw_diag_handler = {
  189. .dump = raw_diag_dump,
  190. .dump_one = raw_diag_dump_one,
  191. .idiag_get_info = raw_diag_get_info,
  192. .idiag_type = IPPROTO_RAW,
  193. .idiag_info_size = 0,
  194. #ifdef CONFIG_INET_DIAG_DESTROY
  195. .destroy = raw_diag_destroy,
  196. #endif
  197. };
  198. static void __always_unused __check_inet_diag_req_raw(void)
  199. {
  200. /*
  201. * Make sure the two structures are identical,
  202. * except the @pad field.
  203. */
  204. #define __offset_mismatch(m1, m2) \
  205. (offsetof(struct inet_diag_req_v2, m1) != \
  206. offsetof(struct inet_diag_req_raw, m2))
  207. BUILD_BUG_ON(sizeof(struct inet_diag_req_v2) !=
  208. sizeof(struct inet_diag_req_raw));
  209. BUILD_BUG_ON(__offset_mismatch(sdiag_family, sdiag_family));
  210. BUILD_BUG_ON(__offset_mismatch(sdiag_protocol, sdiag_protocol));
  211. BUILD_BUG_ON(__offset_mismatch(idiag_ext, idiag_ext));
  212. BUILD_BUG_ON(__offset_mismatch(pad, sdiag_raw_protocol));
  213. BUILD_BUG_ON(__offset_mismatch(idiag_states, idiag_states));
  214. BUILD_BUG_ON(__offset_mismatch(id, id));
  215. #undef __offset_mismatch
  216. }
  217. static int __init raw_diag_init(void)
  218. {
  219. return inet_diag_register(&raw_diag_handler);
  220. }
  221. static void __exit raw_diag_exit(void)
  222. {
  223. inet_diag_unregister(&raw_diag_handler);
  224. }
  225. module_init(raw_diag_init);
  226. module_exit(raw_diag_exit);
  227. MODULE_LICENSE("GPL");
  228. MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-255 /* AF_INET - IPPROTO_RAW */);
  229. MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10-255 /* AF_INET6 - IPPROTO_RAW */);