Blame view

net/netfilter/nf_sockopt.c 3.86 KB
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
1
2
3
4
5
  #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: ...
6
  #include <linux/mutex.h>
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
7
8
9
10
11
12
13
  #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: ...
14
  static DEFINE_MUTEX(nf_sockopt_mutex);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
15
16
17
18
19
20
21
22
23
24
25
  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...
26
  	struct nf_sockopt_ops *ops;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
27
  	int ret = 0;
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
28
  	if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
29
  		return -EINTR;
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
36
37
  				   reg->get_optmin, reg->get_optmax))) {
  			NFDEBUG("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

4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
66
  	if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
67
  		return ERR_PTR(-EINTR);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
68

55d84acd3   Alexey Dobriyan   [NETFILTER]: nf_s...
69
  	list_for_each_entry(ops, &nf_sockopts, list) {
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
70
  		if (ops->pf == pf) {
16fcec35e   Neil Horman   [NETFILTER]: Fix/...
71
72
  			if (!try_module_get(ops->owner))
  				goto out_nosup;
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
73

f6ebe77f9   Harald Welte   [NETFILTER]: spli...
74
  			if (get) {
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
75
76
  				if (val >= ops->get_optmin &&
  						val < ops->get_optmax)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
77
  					goto out;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
78
  			} else {
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
79
80
  				if (val >= ops->set_optmin &&
  						val < ops->set_optmax)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
81
  					goto out;
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
82
  			}
16fcec35e   Neil Horman   [NETFILTER]: Fix/...
83
  			module_put(ops->owner);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
84
85
  		}
  	}
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
86
87
88
  out_nosup:
  	ops = ERR_PTR(-ENOPROTOOPT);
  out:
4a3e2f711   Arjan van de Ven   [NET] sem2mutex: ...
89
  	mutex_unlock(&nf_sockopt_mutex);
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
90
91
92
93
  	return ops;
  }
  
  /* Call get/setsockopt() */
76108cea0   Jan Engelhardt   netfilter: Use un...
94
  static int nf_sockopt(struct sock *sk, u_int8_t pf, int val,
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
95
96
97
98
99
100
101
102
103
104
105
106
107
  		      char __user *opt, int *len, int get)
  {
  	struct nf_sockopt_ops *ops;
  	int ret;
  
  	ops = nf_sockopt_find(sk, pf, val, get);
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
  
  	if (get)
  		ret = ops->get(sk, val, opt, len);
  	else
  		ret = ops->set(sk, val, opt, *len);
601e68e10   YOSHIFUJI Hideaki   [NETFILTER]: Fix ...
108

16fcec35e   Neil Horman   [NETFILTER]: Fix/...
109
  	module_put(ops->owner);
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
110
111
  	return ret;
  }
76108cea0   Jan Engelhardt   netfilter: Use un...
112
  int nf_setsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
b7058842c   David S. Miller   net: Make setsock...
113
  		  unsigned int len)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
114
115
116
117
  {
  	return nf_sockopt(sk, pf, val, opt, &len, 0);
  }
  EXPORT_SYMBOL(nf_setsockopt);
76108cea0   Jan Engelhardt   netfilter: Use un...
118
119
  int nf_getsockopt(struct sock *sk, u_int8_t pf, int val, char __user *opt,
  		  int *len)
f6ebe77f9   Harald Welte   [NETFILTER]: spli...
120
121
122
123
  {
  	return nf_sockopt(sk, pf, val, opt, len, 1);
  }
  EXPORT_SYMBOL(nf_getsockopt);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
124
  #ifdef CONFIG_COMPAT
76108cea0   Jan Engelhardt   netfilter: Use un...
125
  static int compat_nf_sockopt(struct sock *sk, u_int8_t pf, int val,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
126
  			     char __user *opt, int *len, int get)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
127
  {
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
128
129
  	struct nf_sockopt_ops *ops;
  	int ret;
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
130
131
132
133
134
135
136
137
  	ops = nf_sockopt_find(sk, pf, val, get);
  	if (IS_ERR(ops))
  		return PTR_ERR(ops);
  
  	if (get) {
  		if (ops->compat_get)
  			ret = ops->compat_get(sk, val, opt, len);
  		else
6452a5fde   Patrick McHardy   [NETFILTER]: fix ...
138
  			ret = ops->get(sk, val, opt, len);
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
139
140
  	} else {
  		if (ops->compat_set)
6452a5fde   Patrick McHardy   [NETFILTER]: fix ...
141
  			ret = ops->compat_set(sk, val, opt, *len);
4ce5ba6ae   Pavel Emelyanov   [NETFILTER]: Cons...
142
  		else
6452a5fde   Patrick McHardy   [NETFILTER]: fix ...
143
  			ret = ops->set(sk, val, opt, *len);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
144
  	}
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
145

16fcec35e   Neil Horman   [NETFILTER]: Fix/...
146
  	module_put(ops->owner);
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
147
148
  	return ret;
  }
76108cea0   Jan Engelhardt   netfilter: Use un...
149
  int compat_nf_setsockopt(struct sock *sk, u_int8_t pf,
b7058842c   David S. Miller   net: Make setsock...
150
  		int val, char __user *opt, unsigned int len)
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
151
152
153
154
  {
  	return compat_nf_sockopt(sk, pf, val, opt, &len, 0);
  }
  EXPORT_SYMBOL(compat_nf_setsockopt);
76108cea0   Jan Engelhardt   netfilter: Use un...
155
  int compat_nf_getsockopt(struct sock *sk, u_int8_t pf,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
156
157
158
159
160
161
  		int val, char __user *opt, int *len)
  {
  	return compat_nf_sockopt(sk, pf, val, opt, len, 1);
  }
  EXPORT_SYMBOL(compat_nf_getsockopt);
  #endif