nf_sockopt.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/module.h>
  5. #include <linux/skbuff.h>
  6. #include <linux/netfilter.h>
  7. #include <linux/mutex.h>
  8. #include <net/sock.h>
  9. #include "nf_internals.h"
  10. /* Sockopts only registered and called from user context, so
  11. net locking would be overkill. Also, [gs]etsockopt calls may
  12. sleep. */
  13. static DEFINE_MUTEX(nf_sockopt_mutex);
  14. static LIST_HEAD(nf_sockopts);
  15. /* Do exclusive ranges overlap? */
  16. static inline int overlap(int min1, int max1, int min2, int max2)
  17. {
  18. return max1 > min2 && min1 < max2;
  19. }
  20. /* Functions to register sockopt ranges (exclusive). */
  21. int nf_register_sockopt(struct nf_sockopt_ops *reg)
  22. {
  23. struct nf_sockopt_ops *ops;
  24. int ret = 0;
  25. mutex_lock(&nf_sockopt_mutex);
  26. list_for_each_entry(ops, &nf_sockopts, list) {
  27. if (ops->pf == reg->pf
  28. && (overlap(ops->set_optmin, ops->set_optmax,
  29. reg->set_optmin, reg->set_optmax)
  30. || overlap(ops->get_optmin, ops->get_optmax,
  31. reg->get_optmin, reg->get_optmax))) {
  32. pr_debug("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
  33. ops->set_optmin, ops->set_optmax,
  34. ops->get_optmin, ops->get_optmax,
  35. reg->set_optmin, reg->set_optmax,
  36. reg->get_optmin, reg->get_optmax);
  37. ret = -EBUSY;
  38. goto out;
  39. }
  40. }
  41. list_add(&reg->list, &nf_sockopts);
  42. out:
  43. mutex_unlock(&nf_sockopt_mutex);
  44. return ret;
  45. }
  46. EXPORT_SYMBOL(nf_register_sockopt);
  47. void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
  48. {
  49. mutex_lock(&nf_sockopt_mutex);
  50. list_del(&reg->list);
  51. mutex_unlock(&nf_sockopt_mutex);
  52. }
  53. EXPORT_SYMBOL(nf_unregister_sockopt);
  54. static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,
  55. int val, int get)
  56. {
  57. struct nf_sockopt_ops *ops;
  58. mutex_lock(&nf_sockopt_mutex);
  59. list_for_each_entry(ops, &nf_sockopts, list) {
  60. if (ops->pf == pf) {
  61. if (!try_module_get(ops->owner))
  62. goto out_nosup;
  63. if (get) {
  64. if (val >= ops->get_optmin &&
  65. val < ops->get_optmax)
  66. goto out;
  67. } else {
  68. if (val >= ops->set_optmin &&
  69. val < ops->set_optmax)
  70. goto out;
  71. }
  72. module_put(ops->owner);
  73. }
  74. }
  75. out_nosup:
  76. ops = ERR_PTR(-ENOPROTOOPT);
  77. out:
  78. mutex_unlock(&nf_sockopt_mutex);
  79. return ops;
  80. }
  81. int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, sockptr_t opt,
  82. unsigned int len)
  83. {
  84. struct nf_sockopt_ops *ops;
  85. int ret;
  86. ops = nf_sockopt_find(sk, pf, val, 0);
  87. if (IS_ERR(ops))
  88. return PTR_ERR(ops);
  89. ret = ops->set(sk, val, opt, len);
  90. module_put(ops->owner);
  91. return ret;
  92. }
  93. EXPORT_SYMBOL(nf_setsockopt);
  94. int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
  95. int *len)
  96. {
  97. struct nf_sockopt_ops *ops;
  98. int ret;
  99. ops = nf_sockopt_find(sk, pf, val, 1);
  100. if (IS_ERR(ops))
  101. return PTR_ERR(ops);
  102. ret = ops->get(sk, val, opt, len);
  103. module_put(ops->owner);
  104. return ret;
  105. }
  106. EXPORT_SYMBOL(nf_getsockopt);