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