Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/selinux/netlabel.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* SELinux NetLabel Support
4
*
5
* This file provides the necessary glue to tie NetLabel into the SELinux
6
* subsystem.
7
*
8
* Author: Paul Moore <[email protected]>
9
*/
10
11
/*
12
* (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
13
*/
14
15
#include <linux/spinlock.h>
16
#include <linux/rcupdate.h>
17
#include <linux/gfp.h>
18
#include <linux/ip.h>
19
#include <linux/ipv6.h>
20
#include <linux/lsm_hooks.h>
21
#include <net/sock.h>
22
#include <net/netlabel.h>
23
#include <net/ip.h>
24
#include <net/ipv6.h>
25
26
#include "objsec.h"
27
#include "security.h"
28
#include "netlabel.h"
29
30
/**
31
* selinux_netlbl_sidlookup_cached - Cache a SID lookup
32
* @skb: the packet
33
* @family: the packet's address family
34
* @secattr: the NetLabel security attributes
35
* @sid: the SID
36
*
37
* Description:
38
* Query the SELinux security server to lookup the correct SID for the given
39
* security attributes. If the query is successful, cache the result to speed
40
* up future lookups. Returns zero on success, negative values on failure.
41
*
42
*/
43
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
44
u16 family,
45
struct netlbl_lsm_secattr *secattr,
46
u32 *sid)
47
{
48
int rc;
49
50
rc = security_netlbl_secattr_to_sid(secattr, sid);
51
if (rc == 0 &&
52
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
53
(secattr->flags & NETLBL_SECATTR_CACHE))
54
netlbl_cache_add(skb, family, secattr);
55
56
return rc;
57
}
58
59
/**
60
* selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
61
* @sk: the socket
62
*
63
* Description:
64
* Generate the NetLabel security attributes for a socket, making full use of
65
* the socket's attribute cache. Returns a pointer to the security attributes
66
* on success, or an ERR_PTR on failure.
67
*
68
*/
69
static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
70
{
71
int rc;
72
struct sk_security_struct *sksec = selinux_sock(sk);
73
struct netlbl_lsm_secattr *secattr;
74
75
if (sksec->nlbl_secattr != NULL)
76
return sksec->nlbl_secattr;
77
78
secattr = netlbl_secattr_alloc(GFP_ATOMIC);
79
if (secattr == NULL)
80
return ERR_PTR(-ENOMEM);
81
82
rc = security_netlbl_sid_to_secattr(sksec->sid, secattr);
83
if (rc != 0) {
84
netlbl_secattr_free(secattr);
85
return ERR_PTR(rc);
86
}
87
sksec->nlbl_secattr = secattr;
88
89
return secattr;
90
}
91
92
/**
93
* selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
94
* @sk: the socket
95
* @sid: the SID
96
*
97
* Query the socket's cached secattr and if the SID matches the cached value
98
* return the cache, otherwise return NULL.
99
*
100
*/
101
static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
102
const struct sock *sk,
103
u32 sid)
104
{
105
struct sk_security_struct *sksec = selinux_sock(sk);
106
struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
107
108
if (secattr == NULL)
109
return NULL;
110
111
if ((secattr->flags & NETLBL_SECATTR_SECID) &&
112
(secattr->attr.secid == sid))
113
return secattr;
114
115
return NULL;
116
}
117
118
/**
119
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
120
*
121
* Description:
122
* Invalidate the NetLabel security attribute mapping cache.
123
*
124
*/
125
void selinux_netlbl_cache_invalidate(void)
126
{
127
netlbl_cache_invalidate();
128
}
129
130
/**
131
* selinux_netlbl_err - Handle a NetLabel packet error
132
* @skb: the packet
133
* @family: the packet's address family
134
* @error: the error code
135
* @gateway: true if host is acting as a gateway, false otherwise
136
*
137
* Description:
138
* When a packet is dropped due to a call to avc_has_perm() pass the error
139
* code to the NetLabel subsystem so any protocol specific processing can be
140
* done. This is safe to call even if you are unsure if NetLabel labeling is
141
* present on the packet, NetLabel is smart enough to only act when it should.
142
*
143
*/
144
void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
145
{
146
netlbl_skbuff_err(skb, family, error, gateway);
147
}
148
149
/**
150
* selinux_netlbl_sk_security_free - Free the NetLabel fields
151
* @sksec: the sk_security_struct
152
*
153
* Description:
154
* Free all of the memory in the NetLabel fields of a sk_security_struct.
155
*
156
*/
157
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
158
{
159
if (!sksec->nlbl_secattr)
160
return;
161
162
netlbl_secattr_free(sksec->nlbl_secattr);
163
sksec->nlbl_secattr = NULL;
164
sksec->nlbl_state = NLBL_UNSET;
165
}
166
167
/**
168
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields
169
* @sksec: the sk_security_struct
170
*
171
* Description:
172
* Called when the NetLabel state of a sk_security_struct needs to be reset.
173
* The caller is responsible for all the NetLabel sk_security_struct locking.
174
*
175
*/
176
void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
177
{
178
sksec->nlbl_state = NLBL_UNSET;
179
}
180
181
/**
182
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
183
* @skb: the packet
184
* @family: protocol family
185
* @type: NetLabel labeling protocol type
186
* @sid: the SID
187
*
188
* Description:
189
* Call the NetLabel mechanism to get the security attributes of the given
190
* packet and use those attributes to determine the correct context/SID to
191
* assign to the packet. Returns zero on success, negative values on failure.
192
*
193
*/
194
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
195
u16 family,
196
u32 *type,
197
u32 *sid)
198
{
199
int rc;
200
struct netlbl_lsm_secattr secattr;
201
202
if (!netlbl_enabled()) {
203
*type = NETLBL_NLTYPE_NONE;
204
*sid = SECSID_NULL;
205
return 0;
206
}
207
208
netlbl_secattr_init(&secattr);
209
rc = netlbl_skbuff_getattr(skb, family, &secattr);
210
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
211
rc = selinux_netlbl_sidlookup_cached(skb, family,
212
&secattr, sid);
213
else
214
*sid = SECSID_NULL;
215
*type = secattr.type;
216
netlbl_secattr_destroy(&secattr);
217
218
return rc;
219
}
220
221
/**
222
* selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
223
* @skb: the packet
224
* @family: protocol family
225
* @sid: the SID
226
*
227
* Description
228
* Call the NetLabel mechanism to set the label of a packet using @sid.
229
* Returns zero on success, negative values on failure.
230
*
231
*/
232
int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
233
u16 family,
234
u32 sid)
235
{
236
int rc;
237
struct netlbl_lsm_secattr secattr_storage;
238
struct netlbl_lsm_secattr *secattr = NULL;
239
struct sock *sk;
240
241
/* if this is a locally generated packet check to see if it is already
242
* being labeled by it's parent socket, if it is just exit */
243
sk = skb_to_full_sk(skb);
244
if (sk != NULL) {
245
struct sk_security_struct *sksec = selinux_sock(sk);
246
247
if (sksec->nlbl_state != NLBL_REQSKB)
248
return 0;
249
secattr = selinux_netlbl_sock_getattr(sk, sid);
250
}
251
if (secattr == NULL) {
252
secattr = &secattr_storage;
253
netlbl_secattr_init(secattr);
254
rc = security_netlbl_sid_to_secattr(sid, secattr);
255
if (rc != 0)
256
goto skbuff_setsid_return;
257
}
258
259
rc = netlbl_skbuff_setattr(skb, family, secattr);
260
261
skbuff_setsid_return:
262
if (secattr == &secattr_storage)
263
netlbl_secattr_destroy(secattr);
264
return rc;
265
}
266
267
/**
268
* selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
269
* @asoc: incoming association.
270
* @skb: the packet.
271
*
272
* Description:
273
* A new incoming connection is represented by @asoc, ......
274
* Returns zero on success, negative values on failure.
275
*
276
*/
277
int selinux_netlbl_sctp_assoc_request(struct sctp_association *asoc,
278
struct sk_buff *skb)
279
{
280
int rc;
281
struct netlbl_lsm_secattr secattr;
282
struct sk_security_struct *sksec = selinux_sock(asoc->base.sk);
283
struct sockaddr_in addr4;
284
struct sockaddr_in6 addr6;
285
286
if (asoc->base.sk->sk_family != PF_INET &&
287
asoc->base.sk->sk_family != PF_INET6)
288
return 0;
289
290
netlbl_secattr_init(&secattr);
291
rc = security_netlbl_sid_to_secattr(asoc->secid, &secattr);
292
if (rc != 0)
293
goto assoc_request_return;
294
295
/* Move skb hdr address info to a struct sockaddr and then call
296
* netlbl_conn_setattr().
297
*/
298
if (ip_hdr(skb)->version == 4) {
299
addr4.sin_family = AF_INET;
300
addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
301
rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr4, &secattr);
302
} else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
303
addr6.sin6_family = AF_INET6;
304
addr6.sin6_addr = ipv6_hdr(skb)->saddr;
305
rc = netlbl_conn_setattr(asoc->base.sk, (void *)&addr6, &secattr);
306
} else {
307
rc = -EAFNOSUPPORT;
308
}
309
310
if (rc == 0)
311
sksec->nlbl_state = NLBL_LABELED;
312
313
assoc_request_return:
314
netlbl_secattr_destroy(&secattr);
315
return rc;
316
}
317
318
/**
319
* selinux_netlbl_inet_conn_request - Label an incoming stream connection
320
* @req: incoming connection request socket
321
* @family: the request socket's address family
322
*
323
* Description:
324
* A new incoming connection request is represented by @req, we need to label
325
* the new request_sock here and the stack will ensure the on-the-wire label
326
* will get preserved when a full sock is created once the connection handshake
327
* is complete. Returns zero on success, negative values on failure.
328
*
329
*/
330
int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
331
{
332
int rc;
333
struct netlbl_lsm_secattr secattr;
334
335
if (family != PF_INET && family != PF_INET6)
336
return 0;
337
338
netlbl_secattr_init(&secattr);
339
rc = security_netlbl_sid_to_secattr(req->secid, &secattr);
340
if (rc != 0)
341
goto inet_conn_request_return;
342
rc = netlbl_req_setattr(req, &secattr);
343
inet_conn_request_return:
344
netlbl_secattr_destroy(&secattr);
345
return rc;
346
}
347
348
/**
349
* selinux_netlbl_inet_csk_clone - Initialize the newly created sock
350
* @sk: the new sock
351
* @family: the sock's address family
352
*
353
* Description:
354
* A new connection has been established using @sk, we've already labeled the
355
* socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
356
* we need to set the NetLabel state here since we now have a sock structure.
357
*
358
*/
359
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
360
{
361
struct sk_security_struct *sksec = selinux_sock(sk);
362
363
if (family == PF_INET || family == PF_INET6)
364
sksec->nlbl_state = NLBL_LABELED;
365
else
366
sksec->nlbl_state = NLBL_UNSET;
367
}
368
369
/**
370
* selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
371
* @sk: current sock
372
* @newsk: the new sock
373
*
374
* Description:
375
* Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
376
*/
377
void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
378
{
379
struct sk_security_struct *sksec = selinux_sock(sk);
380
struct sk_security_struct *newsksec = selinux_sock(newsk);
381
382
newsksec->nlbl_state = sksec->nlbl_state;
383
}
384
385
/**
386
* selinux_netlbl_socket_post_create - Label a socket using NetLabel
387
* @sk: the sock to label
388
* @family: protocol family
389
*
390
* Description:
391
* Attempt to label a socket using the NetLabel mechanism using the given
392
* SID. Returns zero values on success, negative values on failure.
393
*
394
*/
395
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
396
{
397
int rc;
398
struct sk_security_struct *sksec = selinux_sock(sk);
399
struct netlbl_lsm_secattr *secattr;
400
401
if (family != PF_INET && family != PF_INET6)
402
return 0;
403
404
secattr = selinux_netlbl_sock_genattr(sk);
405
if (IS_ERR(secattr))
406
return PTR_ERR(secattr);
407
/* On socket creation, replacement of IP options is safe even if
408
* the caller does not hold the socket lock.
409
*/
410
rc = netlbl_sock_setattr(sk, family, secattr, true);
411
switch (rc) {
412
case 0:
413
sksec->nlbl_state = NLBL_LABELED;
414
break;
415
case -EDESTADDRREQ:
416
sksec->nlbl_state = NLBL_REQSKB;
417
rc = 0;
418
break;
419
}
420
421
return rc;
422
}
423
424
/**
425
* selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
426
* @sksec: the sock's sk_security_struct
427
* @skb: the packet
428
* @family: protocol family
429
* @ad: the audit data
430
*
431
* Description:
432
* Fetch the NetLabel security attributes from @skb and perform an access check
433
* against the receiving socket. Returns zero on success, negative values on
434
* error.
435
*
436
*/
437
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
438
struct sk_buff *skb,
439
u16 family,
440
struct common_audit_data *ad)
441
{
442
int rc;
443
u32 nlbl_sid;
444
u32 perm;
445
struct netlbl_lsm_secattr secattr;
446
447
if (!netlbl_enabled())
448
return 0;
449
450
netlbl_secattr_init(&secattr);
451
rc = netlbl_skbuff_getattr(skb, family, &secattr);
452
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
453
rc = selinux_netlbl_sidlookup_cached(skb, family,
454
&secattr, &nlbl_sid);
455
else
456
nlbl_sid = SECINITSID_UNLABELED;
457
netlbl_secattr_destroy(&secattr);
458
if (rc != 0)
459
return rc;
460
461
switch (sksec->sclass) {
462
case SECCLASS_UDP_SOCKET:
463
perm = UDP_SOCKET__RECVFROM;
464
break;
465
case SECCLASS_TCP_SOCKET:
466
perm = TCP_SOCKET__RECVFROM;
467
break;
468
default:
469
perm = RAWIP_SOCKET__RECVFROM;
470
}
471
472
rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
473
if (rc == 0)
474
return 0;
475
476
if (nlbl_sid != SECINITSID_UNLABELED)
477
netlbl_skbuff_err(skb, family, rc, 0);
478
return rc;
479
}
480
481
/**
482
* selinux_netlbl_option - Is this a NetLabel option
483
* @level: the socket level or protocol
484
* @optname: the socket option name
485
*
486
* Description:
487
* Returns true if @level and @optname refer to a NetLabel option.
488
* Helper for selinux_netlbl_socket_setsockopt().
489
*/
490
static inline int selinux_netlbl_option(int level, int optname)
491
{
492
return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
493
(level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
494
}
495
496
/**
497
* selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
498
* @sock: the socket
499
* @level: the socket level or protocol
500
* @optname: the socket option name
501
*
502
* Description:
503
* Check the setsockopt() call and if the user is trying to replace the IP
504
* options on a socket and a NetLabel is in place for the socket deny the
505
* access; otherwise allow the access. Returns zero when the access is
506
* allowed, -EACCES when denied, and other negative values on error.
507
*
508
*/
509
int selinux_netlbl_socket_setsockopt(struct socket *sock,
510
int level,
511
int optname)
512
{
513
int rc = 0;
514
struct sock *sk = sock->sk;
515
struct sk_security_struct *sksec = selinux_sock(sk);
516
struct netlbl_lsm_secattr secattr;
517
518
if (selinux_netlbl_option(level, optname) &&
519
(sksec->nlbl_state == NLBL_LABELED ||
520
sksec->nlbl_state == NLBL_CONNLABELED)) {
521
netlbl_secattr_init(&secattr);
522
lock_sock(sk);
523
/* call the netlabel function directly as we want to see the
524
* on-the-wire label that is assigned via the socket's options
525
* and not the cached netlabel/lsm attributes */
526
rc = netlbl_sock_getattr(sk, &secattr);
527
release_sock(sk);
528
if (rc == 0)
529
rc = -EACCES;
530
else if (rc == -ENOMSG)
531
rc = 0;
532
netlbl_secattr_destroy(&secattr);
533
}
534
535
return rc;
536
}
537
538
/**
539
* selinux_netlbl_socket_connect_helper - Help label a client-side socket on
540
* connect
541
* @sk: the socket to label
542
* @addr: the destination address
543
*
544
* Description:
545
* Attempt to label a connected socket with NetLabel using the given address.
546
* Returns zero values on success, negative values on failure.
547
*
548
*/
549
static int selinux_netlbl_socket_connect_helper(struct sock *sk,
550
struct sockaddr *addr)
551
{
552
int rc;
553
struct sk_security_struct *sksec = selinux_sock(sk);
554
struct netlbl_lsm_secattr *secattr;
555
556
/* connected sockets are allowed to disconnect when the address family
557
* is set to AF_UNSPEC, if that is what is happening we want to reset
558
* the socket */
559
if (addr->sa_family == AF_UNSPEC) {
560
netlbl_sock_delattr(sk);
561
sksec->nlbl_state = NLBL_REQSKB;
562
rc = 0;
563
return rc;
564
}
565
secattr = selinux_netlbl_sock_genattr(sk);
566
if (IS_ERR(secattr))
567
return PTR_ERR(secattr);
568
569
rc = netlbl_conn_setattr(sk, addr, secattr);
570
if (rc == 0)
571
sksec->nlbl_state = NLBL_CONNLABELED;
572
573
return rc;
574
}
575
576
/**
577
* selinux_netlbl_socket_connect_locked - Label a client-side socket on
578
* connect
579
* @sk: the socket to label
580
* @addr: the destination address
581
*
582
* Description:
583
* Attempt to label a connected socket that already has the socket locked
584
* with NetLabel using the given address.
585
* Returns zero values on success, negative values on failure.
586
*
587
*/
588
int selinux_netlbl_socket_connect_locked(struct sock *sk,
589
struct sockaddr *addr)
590
{
591
struct sk_security_struct *sksec = selinux_sock(sk);
592
593
if (sksec->nlbl_state != NLBL_REQSKB &&
594
sksec->nlbl_state != NLBL_CONNLABELED)
595
return 0;
596
597
return selinux_netlbl_socket_connect_helper(sk, addr);
598
}
599
600
/**
601
* selinux_netlbl_socket_connect - Label a client-side socket on connect
602
* @sk: the socket to label
603
* @addr: the destination address
604
*
605
* Description:
606
* Attempt to label a connected socket with NetLabel using the given address.
607
* Returns zero values on success, negative values on failure.
608
*
609
*/
610
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
611
{
612
int rc;
613
614
lock_sock(sk);
615
rc = selinux_netlbl_socket_connect_locked(sk, addr);
616
release_sock(sk);
617
618
return rc;
619
}
620
621