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