Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/security/selinux/netlabel.c
10814 views
1
/*
2
* SELinux NetLabel Support
3
*
4
* This file provides the necessary glue to tie NetLabel into the SELinux
5
* subsystem.
6
*
7
* Author: Paul Moore <[email protected]>
8
*
9
*/
10
11
/*
12
* (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
13
*
14
* This program is free software; you can redistribute it and/or modify
15
* it under the terms of the GNU General Public License as published by
16
* the Free Software Foundation; either version 2 of the License, or
17
* (at your option) any later version.
18
*
19
* This program is distributed in the hope that it will be useful,
20
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
22
* the GNU General Public License for more details.
23
*
24
* You should have received a copy of the GNU General Public License
25
* along with this program; if not, write to the Free Software
26
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
* selinux_netlbl_sidlookup_cached - Cache a SID lookup
46
* @skb: the packet
47
* @secattr: the NetLabel security attributes
48
* @sid: the SID
49
*
50
* Description:
51
* Query the SELinux security server to lookup the correct SID for the given
52
* security attributes. If the query is successful, cache the result to speed
53
* up future lookups. Returns zero on success, negative values on failure.
54
*
55
*/
56
static 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
* selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
73
* @sk: the socket
74
*
75
* Description:
76
* Generate the NetLabel security attributes for a socket, making full use of
77
* the socket's attribute cache. Returns a pointer to the security attributes
78
* on success, NULL on failure.
79
*
80
*/
81
static 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
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
105
*
106
* Description:
107
* Invalidate the NetLabel security attribute mapping cache.
108
*
109
*/
110
void selinux_netlbl_cache_invalidate(void)
111
{
112
netlbl_cache_invalidate();
113
}
114
115
/**
116
* selinux_netlbl_err - Handle a NetLabel packet error
117
* @skb: the packet
118
* @error: the error code
119
* @gateway: true if host is acting as a gateway, false otherwise
120
*
121
* Description:
122
* When a packet is dropped due to a call to avc_has_perm() pass the error
123
* code to the NetLabel subsystem so any protocol specific processing can be
124
* done. This is safe to call even if you are unsure if NetLabel labeling is
125
* present on the packet, NetLabel is smart enough to only act when it should.
126
*
127
*/
128
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
129
{
130
netlbl_skbuff_err(skb, error, gateway);
131
}
132
133
/**
134
* selinux_netlbl_sk_security_free - Free the NetLabel fields
135
* @sksec: the sk_security_struct
136
*
137
* Description:
138
* Free all of the memory in the NetLabel fields of a sk_security_struct.
139
*
140
*/
141
void 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
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields
149
* @sksec: the sk_security_struct
150
* @family: the socket family
151
*
152
* Description:
153
* Called when the NetLabel state of a sk_security_struct needs to be reset.
154
* The caller is responsible for all the NetLabel sk_security_struct locking.
155
*
156
*/
157
void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
158
{
159
sksec->nlbl_state = NLBL_UNSET;
160
}
161
162
/**
163
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
164
* @skb: the packet
165
* @family: protocol family
166
* @type: NetLabel labeling protocol type
167
* @sid: the SID
168
*
169
* Description:
170
* Call the NetLabel mechanism to get the security attributes of the given
171
* packet and use those attributes to determine the correct context/SID to
172
* assign to the packet. Returns zero on success, negative values on failure.
173
*
174
*/
175
int 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
* selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
202
* @skb: the packet
203
* @family: protocol family
204
* @sid: the SID
205
*
206
* Description
207
* Call the NetLabel mechanism to set the label of a packet using @sid.
208
* Returns zero on success, negative values on failure.
209
*
210
*/
211
int 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
/* if this is a locally generated packet check to see if it is already
221
* being labeled by it's parent socket, if it is just exit */
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
239
skbuff_setsid_return:
240
if (secattr == &secattr_storage)
241
netlbl_secattr_destroy(secattr);
242
return rc;
243
}
244
245
/**
246
* selinux_netlbl_inet_conn_request - Label an incoming stream connection
247
* @req: incoming connection request socket
248
*
249
* Description:
250
* A new incoming connection request is represented by @req, we need to label
251
* the new request_sock here and the stack will ensure the on-the-wire label
252
* will get preserved when a full sock is created once the connection handshake
253
* is complete. Returns zero on success, negative values on failure.
254
*
255
*/
256
int 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);
269
inet_conn_request_return:
270
netlbl_secattr_destroy(&secattr);
271
return rc;
272
}
273
274
/**
275
* selinux_netlbl_inet_csk_clone - Initialize the newly created sock
276
* @sk: the new sock
277
*
278
* Description:
279
* A new connection has been established using @sk, we've already labeled the
280
* socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
281
* we need to set the NetLabel state here since we now have a sock structure.
282
*
283
*/
284
void 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
* selinux_netlbl_socket_post_create - Label a socket using NetLabel
296
* @sock: the socket to label
297
* @family: protocol family
298
*
299
* Description:
300
* Attempt to label a socket using the NetLabel mechanism using the given
301
* SID. Returns zero values on success, negative values on failure.
302
*
303
*/
304
int 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
* selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
332
* @sksec: the sock's sk_security_struct
333
* @skb: the packet
334
* @family: protocol family
335
* @ad: the audit data
336
*
337
* Description:
338
* Fetch the NetLabel security attributes from @skb and perform an access check
339
* against the receiving socket. Returns zero on success, negative values on
340
* error.
341
*
342
*/
343
int 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
* selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
388
* @sock: the socket
389
* @level: the socket level or protocol
390
* @optname: the socket option name
391
*
392
* Description:
393
* Check the setsockopt() call and if the user is trying to replace the IP
394
* options on a socket and a NetLabel is in place for the socket deny the
395
* access; otherwise allow the access. Returns zero when the access is
396
* allowed, -EACCES when denied, and other negative values on error.
397
*
398
*/
399
int 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
* selinux_netlbl_socket_connect - Label a client-side socket on connect
427
* @sk: the socket to label
428
* @addr: the destination address
429
*
430
* Description:
431
* Attempt to label a connected socket with NetLabel using the given address.
432
* Returns zero values on success, negative values on failure.
433
*
434
*/
435
int 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
/* connected sockets are allowed to disconnect when the address family
449
* is set to AF_UNSPEC, if that is what is happening we want to reset
450
* the socket */
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
466
socket_connect_return:
467
bh_unlock_sock(sk);
468
local_bh_enable();
469
return rc;
470
}
471
472