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#include <linux/spinlock.h>
31#include <linux/rcupdate.h>
32#include <linux/ip.h>
33#include <linux/ipv6.h>
34#include <net/sock.h>
35#include <net/netlabel.h>
36#include <net/ip.h>
37#include <net/ipv6.h>
38
39#include "objsec.h"
40#include "security.h"
41#include "netlabel.h"
42
43
44
45
46
47
48
49
50
51
52
53
54
55static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
56 struct netlbl_lsm_secattr *secattr,
57 u32 *sid)
58{
59 int rc;
60
61 rc = security_netlbl_secattr_to_sid(secattr, sid);
62 if (rc == 0 &&
63 (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
64 (secattr->flags & NETLBL_SECATTR_CACHE))
65 netlbl_cache_add(skb, secattr);
66
67 return rc;
68}
69
70
71
72
73
74
75
76
77
78
79
80static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
81{
82 int rc;
83 struct sk_security_struct *sksec = sk->sk_security;
84 struct netlbl_lsm_secattr *secattr;
85
86 if (sksec->nlbl_secattr != NULL)
87 return sksec->nlbl_secattr;
88
89 secattr = netlbl_secattr_alloc(GFP_ATOMIC);
90 if (secattr == NULL)
91 return NULL;
92 rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
93 if (rc != 0) {
94 netlbl_secattr_free(secattr);
95 return NULL;
96 }
97 sksec->nlbl_secattr = secattr;
98
99 return secattr;
100}
101
102
103
104
105
106
107
108
109void selinux_netlbl_cache_invalidate(void)
110{
111 netlbl_cache_invalidate();
112}
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
128{
129 netlbl_skbuff_err(skb, error, gateway);
130}
131
132
133
134
135
136
137
138
139
140void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec)
141{
142 if (ssec->nlbl_secattr != NULL)
143 netlbl_secattr_free(ssec->nlbl_secattr);
144}
145
146
147
148
149
150
151
152
153
154
155
156void selinux_netlbl_sk_security_reset(struct sk_security_struct *ssec)
157{
158 ssec->nlbl_state = NLBL_UNSET;
159}
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
175 u16 family,
176 u32 *type,
177 u32 *sid)
178{
179 int rc;
180 struct netlbl_lsm_secattr secattr;
181
182 if (!netlbl_enabled()) {
183 *sid = SECSID_NULL;
184 return 0;
185 }
186
187 netlbl_secattr_init(&secattr);
188 rc = netlbl_skbuff_getattr(skb, family, &secattr);
189 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
190 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
191 else
192 *sid = SECSID_NULL;
193 *type = secattr.type;
194 netlbl_secattr_destroy(&secattr);
195
196 return rc;
197}
198
199
200
201
202
203
204
205
206
207
208
209
210int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
211 u16 family,
212 u32 sid)
213{
214 int rc;
215 struct netlbl_lsm_secattr secattr_storage;
216 struct netlbl_lsm_secattr *secattr = NULL;
217 struct sock *sk;
218
219
220
221 sk = skb->sk;
222 if (sk != NULL) {
223 struct sk_security_struct *sksec = sk->sk_security;
224 if (sksec->nlbl_state != NLBL_REQSKB)
225 return 0;
226 secattr = sksec->nlbl_secattr;
227 }
228 if (secattr == NULL) {
229 secattr = &secattr_storage;
230 netlbl_secattr_init(secattr);
231 rc = security_netlbl_sid_to_secattr(sid, secattr);
232 if (rc != 0)
233 goto skbuff_setsid_return;
234 }
235
236 rc = netlbl_skbuff_setattr(skb, family, secattr);
237
238skbuff_setsid_return:
239 if (secattr == &secattr_storage)
240 netlbl_secattr_destroy(secattr);
241 return rc;
242}
243
244
245
246
247
248
249
250
251
252
253
254
255int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
256{
257 int rc;
258 struct netlbl_lsm_secattr secattr;
259
260 if (family != PF_INET)
261 return 0;
262
263 netlbl_secattr_init(&secattr);
264 rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
265 if (rc != 0)
266 goto inet_conn_request_return;
267 rc = netlbl_req_setattr(req, &secattr);
268inet_conn_request_return:
269 netlbl_secattr_destroy(&secattr);
270 return rc;
271}
272
273
274
275
276
277
278
279
280
281
282
283void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
284{
285 struct sk_security_struct *sksec = sk->sk_security;
286
287 if (family == PF_INET)
288 sksec->nlbl_state = NLBL_LABELED;
289 else
290 sksec->nlbl_state = NLBL_UNSET;
291}
292
293
294
295
296
297
298
299
300
301
302
303int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
304{
305 int rc;
306 struct sk_security_struct *sksec = sk->sk_security;
307 struct netlbl_lsm_secattr *secattr;
308
309 if (family != PF_INET)
310 return 0;
311
312 secattr = selinux_netlbl_sock_genattr(sk);
313 if (secattr == NULL)
314 return -ENOMEM;
315 rc = netlbl_sock_setattr(sk, family, secattr);
316 switch (rc) {
317 case 0:
318 sksec->nlbl_state = NLBL_LABELED;
319 break;
320 case -EDESTADDRREQ:
321 sksec->nlbl_state = NLBL_REQSKB;
322 rc = 0;
323 break;
324 }
325
326 return rc;
327}
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
343 struct sk_buff *skb,
344 u16 family,
345 struct common_audit_data *ad)
346{
347 int rc;
348 u32 nlbl_sid;
349 u32 perm;
350 struct netlbl_lsm_secattr secattr;
351
352 if (!netlbl_enabled())
353 return 0;
354
355 netlbl_secattr_init(&secattr);
356 rc = netlbl_skbuff_getattr(skb, family, &secattr);
357 if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
358 rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
359 else
360 nlbl_sid = SECINITSID_UNLABELED;
361 netlbl_secattr_destroy(&secattr);
362 if (rc != 0)
363 return rc;
364
365 switch (sksec->sclass) {
366 case SECCLASS_UDP_SOCKET:
367 perm = UDP_SOCKET__RECVFROM;
368 break;
369 case SECCLASS_TCP_SOCKET:
370 perm = TCP_SOCKET__RECVFROM;
371 break;
372 default:
373 perm = RAWIP_SOCKET__RECVFROM;
374 }
375
376 rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
377 if (rc == 0)
378 return 0;
379
380 if (nlbl_sid != SECINITSID_UNLABELED)
381 netlbl_skbuff_err(skb, rc, 0);
382 return rc;
383}
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398int selinux_netlbl_socket_setsockopt(struct socket *sock,
399 int level,
400 int optname)
401{
402 int rc = 0;
403 struct sock *sk = sock->sk;
404 struct sk_security_struct *sksec = sk->sk_security;
405 struct netlbl_lsm_secattr secattr;
406
407 if (level == IPPROTO_IP && optname == IP_OPTIONS &&
408 (sksec->nlbl_state == NLBL_LABELED ||
409 sksec->nlbl_state == NLBL_CONNLABELED)) {
410 netlbl_secattr_init(&secattr);
411 lock_sock(sk);
412 rc = netlbl_sock_getattr(sk, &secattr);
413 release_sock(sk);
414 if (rc == 0)
415 rc = -EACCES;
416 else if (rc == -ENOMSG)
417 rc = 0;
418 netlbl_secattr_destroy(&secattr);
419 }
420
421 return rc;
422}
423
424
425
426
427
428
429
430
431
432
433
434int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
435{
436 int rc;
437 struct sk_security_struct *sksec = sk->sk_security;
438 struct netlbl_lsm_secattr *secattr;
439
440 if (sksec->nlbl_state != NLBL_REQSKB &&
441 sksec->nlbl_state != NLBL_CONNLABELED)
442 return 0;
443
444 local_bh_disable();
445 bh_lock_sock_nested(sk);
446
447
448
449
450 if (addr->sa_family == AF_UNSPEC) {
451 netlbl_sock_delattr(sk);
452 sksec->nlbl_state = NLBL_REQSKB;
453 rc = 0;
454 goto socket_connect_return;
455 }
456 secattr = selinux_netlbl_sock_genattr(sk);
457 if (secattr == NULL) {
458 rc = -ENOMEM;
459 goto socket_connect_return;
460 }
461 rc = netlbl_conn_setattr(sk, addr, secattr);
462 if (rc == 0)
463 sksec->nlbl_state = NLBL_CONNLABELED;
464
465socket_connect_return:
466 bh_unlock_sock(sk);
467 local_bh_enable();
468 return rc;
469}
470