1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#include <linux/types.h>
32#include <linux/rcupdate.h>
33#include <linux/list.h>
34#include <linux/slab.h>
35#include <linux/spinlock.h>
36#include <linux/in.h>
37#include <linux/in6.h>
38#include <linux/ip.h>
39#include <linux/ipv6.h>
40#include <net/ip.h>
41#include <net/ipv6.h>
42
43#include "netnode.h"
44#include "objsec.h"
45
46#define SEL_NETNODE_HASH_SIZE 256
47#define SEL_NETNODE_HASH_BKT_LIMIT 16
48
49struct sel_netnode_bkt {
50 unsigned int size;
51 struct list_head list;
52};
53
54struct sel_netnode {
55 struct netnode_security_struct nsec;
56
57 struct list_head list;
58 struct rcu_head rcu;
59};
60
61
62
63
64
65
66
67static LIST_HEAD(sel_netnode_list);
68static DEFINE_SPINLOCK(sel_netnode_lock);
69static struct sel_netnode_bkt sel_netnode_hash[SEL_NETNODE_HASH_SIZE];
70
71
72
73
74
75
76
77
78
79
80static unsigned int sel_netnode_hashfn_ipv4(__be32 addr)
81{
82
83
84 return (addr & (SEL_NETNODE_HASH_SIZE - 1));
85}
86
87
88
89
90
91
92
93
94
95
96static unsigned int sel_netnode_hashfn_ipv6(const struct in6_addr *addr)
97{
98
99
100
101 return (addr->s6_addr32[3] & (SEL_NETNODE_HASH_SIZE - 1));
102}
103
104
105
106
107
108
109
110
111
112
113
114static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
115{
116 unsigned int idx;
117 struct sel_netnode *node;
118
119 switch (family) {
120 case PF_INET:
121 idx = sel_netnode_hashfn_ipv4(*(__be32 *)addr);
122 break;
123 case PF_INET6:
124 idx = sel_netnode_hashfn_ipv6(addr);
125 break;
126 default:
127 BUG();
128 return NULL;
129 }
130
131 list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
132 if (node->nsec.family == family)
133 switch (family) {
134 case PF_INET:
135 if (node->nsec.addr.ipv4 == *(__be32 *)addr)
136 return node;
137 break;
138 case PF_INET6:
139 if (ipv6_addr_equal(&node->nsec.addr.ipv6,
140 addr))
141 return node;
142 break;
143 }
144
145 return NULL;
146}
147
148
149
150
151
152
153
154
155
156static void sel_netnode_insert(struct sel_netnode *node)
157{
158 unsigned int idx;
159
160 switch (node->nsec.family) {
161 case PF_INET:
162 idx = sel_netnode_hashfn_ipv4(node->nsec.addr.ipv4);
163 break;
164 case PF_INET6:
165 idx = sel_netnode_hashfn_ipv6(&node->nsec.addr.ipv6);
166 break;
167 default:
168 BUG();
169 }
170
171
172
173 list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
174 if (sel_netnode_hash[idx].size == SEL_NETNODE_HASH_BKT_LIMIT) {
175 struct sel_netnode *tail;
176 tail = list_entry(
177 rcu_dereference_protected(sel_netnode_hash[idx].list.prev,
178 lockdep_is_held(&sel_netnode_lock)),
179 struct sel_netnode, list);
180 list_del_rcu(&tail->list);
181 kfree_rcu(tail, rcu);
182 } else
183 sel_netnode_hash[idx].size++;
184}
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
200{
201 int ret = -ENOMEM;
202 struct sel_netnode *node;
203 struct sel_netnode *new = NULL;
204
205 spin_lock_bh(&sel_netnode_lock);
206 node = sel_netnode_find(addr, family);
207 if (node != NULL) {
208 *sid = node->nsec.sid;
209 spin_unlock_bh(&sel_netnode_lock);
210 return 0;
211 }
212 new = kzalloc(sizeof(*new), GFP_ATOMIC);
213 if (new == NULL)
214 goto out;
215 switch (family) {
216 case PF_INET:
217 ret = security_node_sid(PF_INET,
218 addr, sizeof(struct in_addr), sid);
219 new->nsec.addr.ipv4 = *(__be32 *)addr;
220 break;
221 case PF_INET6:
222 ret = security_node_sid(PF_INET6,
223 addr, sizeof(struct in6_addr), sid);
224 new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
225 break;
226 default:
227 BUG();
228 }
229 if (ret != 0)
230 goto out;
231
232 new->nsec.family = family;
233 new->nsec.sid = *sid;
234 sel_netnode_insert(new);
235
236out:
237 spin_unlock_bh(&sel_netnode_lock);
238 if (unlikely(ret)) {
239 printk(KERN_WARNING
240 "SELinux: failure in sel_netnode_sid_slow(),"
241 " unable to determine network node label\n");
242 kfree(new);
243 }
244 return ret;
245}
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261int sel_netnode_sid(void *addr, u16 family, u32 *sid)
262{
263 struct sel_netnode *node;
264
265 rcu_read_lock();
266 node = sel_netnode_find(addr, family);
267 if (node != NULL) {
268 *sid = node->nsec.sid;
269 rcu_read_unlock();
270 return 0;
271 }
272 rcu_read_unlock();
273
274 return sel_netnode_sid_slow(addr, family, sid);
275}
276
277
278
279
280
281
282
283
284static void sel_netnode_flush(void)
285{
286 unsigned int idx;
287 struct sel_netnode *node, *node_tmp;
288
289 spin_lock_bh(&sel_netnode_lock);
290 for (idx = 0; idx < SEL_NETNODE_HASH_SIZE; idx++) {
291 list_for_each_entry_safe(node, node_tmp,
292 &sel_netnode_hash[idx].list, list) {
293 list_del_rcu(&node->list);
294 kfree_rcu(node, rcu);
295 }
296 sel_netnode_hash[idx].size = 0;
297 }
298 spin_unlock_bh(&sel_netnode_lock);
299}
300
301static int sel_netnode_avc_callback(u32 event)
302{
303 if (event == AVC_CALLBACK_RESET) {
304 sel_netnode_flush();
305 synchronize_net();
306 }
307 return 0;
308}
309
310static __init int sel_netnode_init(void)
311{
312 int iter;
313 int ret;
314
315 if (!selinux_enabled)
316 return 0;
317
318 for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) {
319 INIT_LIST_HEAD(&sel_netnode_hash[iter].list);
320 sel_netnode_hash[iter].size = 0;
321 }
322
323 ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET);
324 if (ret != 0)
325 panic("avc_add_callback() failed, error %d\n", ret);
326
327 return ret;
328}
329
330__initcall(sel_netnode_init);
331