Blame view

net/netfilter/nf_sockopt.c 2.78 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
2
3
4
5
6
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/netfilter.h>
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
7
  #include <linux/mutex.h>
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
8
9
10
11
12
13
14
  #include <net/sock.h>
  
  #include "nf_internals.h"
  
  /* Sockopts only registered and called from user context, so
     net locking would be overkill.  Also, [gs]etsockopt calls may
     sleep. */
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
15
  static DEFINE_MUTEX(nf_sockopt_mutex);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
16
17
18
19
20
21
22
23
24
25
26
  static LIST_HEAD(nf_sockopts);
  
  /* Do exclusive ranges overlap? */
  static inline int overlap(int min1, int max1, int min2, int max2)
  {
  	return max1 > min2 && min1 < max2;
  }
  
  /* Functions to register sockopt ranges (exclusive). */
  int nf_register_sockopt(struct nf_sockopt_ops *reg)
  {
55d84acd3   Alexey Dobriyan   [NETFILTER]: nf_s...
27
  	struct nf_sockopt_ops *ops;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
28
  	int ret = 0;
7926dbfa4   Pablo Neira Ayuso   netfilter: don't ...
29
  	mutex_lock(&nf_sockopt_mutex);
55d84acd3   Alexey Dobriyan   [NETFILTER]: nf_s...
30
  	list_for_each_entry(ops, &nf_sockopts, list) {
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
31
  		if (ops->pf == reg->pf
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
32
  		    && (overlap(ops->set_optmin, ops->set_optmax,
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
33
  				reg->set_optmin, reg->set_optmax)
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
34
  			|| overlap(ops->get_optmin, ops->get_optmax,
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
35
  				   reg->get_optmin, reg->get_optmax))) {
b38cf9013   Varsha Rao   netfilter: Remove...
36
37
  			pr_debug("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u
  ",
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
38
39
  				ops->set_optmin, ops->set_optmax,
  				ops->get_optmin, ops->get_optmax,
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
40
41
42
43
44
45
46
47
48
  				reg->set_optmin, reg->set_optmax,
  				reg->get_optmin, reg->get_optmax);
  			ret = -EBUSY;
  			goto out;
  		}
  	}
  
  	list_add(&reg->list, &nf_sockopts);
  out:
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
49
  	mutex_unlock(&nf_sockopt_mutex);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
50
51
52
53
54
55
  	return ret;
  }
  EXPORT_SYMBOL(nf_register_sockopt);
  
  void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
  {
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
56
  	mutex_lock(&nf_sockopt_mutex);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
57
  	list_del(&reg->list);
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
58
  	mutex_unlock(&nf_sockopt_mutex);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
59
60
  }
  EXPORT_SYMBOL(nf_unregister_sockopt);
76108cea0   Jan Engelhardt   netfilter: Use un...
61
  static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
62
  		int val, int get)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
63
  {
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
64
  	struct nf_sockopt_ops *ops;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
65

7926dbfa4   Pablo Neira Ayuso   netfilter: don't ...
66
  	mutex_lock(&nf_sockopt_mutex);
55d84acd3   Alexey Dobriyan   [NETFILTER]: nf_s...
67
  	list_for_each_entry(ops, &nf_sockopts, list) {
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
68
  		if (ops->pf == pf) {
16fcec35e   Neil Horman   [NETFILTER]: Fix/...
69
70
  			if (!try_module_get(ops->owner))
  				goto out_nosup;
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
71

f6ebe77f9   Harald Welte   [NETFILTER]: spli...
72
  			if (get) {
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
73
74
  				if (val >= ops->get_optmin &&
  						val < ops->get_optmax)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
75
  					goto out;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
76
  			} else {
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
77
78
  				if (val >= ops->set_optmin &&
  						val < ops->set_optmax)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
79
  					goto out;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
80
  			}
16fcec35e   Neil Horman   [NETFILTER]: Fix/...
81
  			module_put(ops->owner);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
82
83
  		}
  	}
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
84
85
86
  out_nosup:
  	ops = ERR_PTR(-ENOPROTOOPT);
  out:
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
87
  	mutex_unlock(&nf_sockopt_mutex);
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
88
89
  	return ops;
  }
c2f12630c   Christoph Hellwig   netfilter: switch...
90
  int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, sockptr_t opt,
657e4c34a   Christoph Hellwig   netfilter: split ...
91
  		  unsigned int len)
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
92
93
94
  {
  	struct nf_sockopt_ops *ops;
  	int ret;
657e4c34a   Christoph Hellwig   netfilter: split ...
95
  	ops = nf_sockopt_find(sk, pf, val, 0);
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
96
97
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
657e4c34a   Christoph Hellwig   netfilter: split ...
98
  	ret = ops->set(sk, val, opt, len);
16fcec35e   Neil Horman   [NETFILTER]: Fix/...
99
  	module_put(ops->owner);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
100
101
  	return ret;
  }
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
102
  EXPORT_SYMBOL(nf_setsockopt);
76108cea0   Jan Engelhardt   netfilter: Use un...
103
104
  int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
  		  int *len)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
105
  {
657e4c34a   Christoph Hellwig   netfilter: split ...
106
107
108
109
110
111
112
113
114
  	struct nf_sockopt_ops *ops;
  	int ret;
  
  	ops = nf_sockopt_find(sk, pf, val, 1);
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
  	ret = ops->get(sk, val, opt, len);
  	module_put(ops->owner);
  	return ret;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
115
116
  }
  EXPORT_SYMBOL(nf_getsockopt);