2019-05-19 13:51:43 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2007-02-28 20:14:22 +00:00
|
|
|
/*
|
|
|
|
* SELinux NetLabel Support
|
|
|
|
*
|
|
|
|
* This file provides the necessary glue to tie NetLabel into the SELinux
|
|
|
|
* subsystem.
|
|
|
|
*
|
2011-08-01 11:10:33 +00:00
|
|
|
* Author: Paul Moore <paul@paul-moore.com>
|
2007-02-28 20:14:22 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2008-10-10 14:16:32 +00:00
|
|
|
* (c) Copyright Hewlett-Packard Development Company, L.P., 2007, 2008
|
2007-02-28 20:14:22 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/rcupdate.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/gfp.h>
|
2008-10-10 14:16:33 +00:00
|
|
|
#include <linux/ip.h>
|
|
|
|
#include <linux/ipv6.h>
|
2007-02-28 20:14:22 +00:00
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/netlabel.h>
|
2008-10-10 14:16:33 +00:00
|
|
|
#include <net/ip.h>
|
|
|
|
#include <net/ipv6.h>
|
2007-02-28 20:14:22 +00:00
|
|
|
|
|
|
|
#include "objsec.h"
|
|
|
|
#include "security.h"
|
2008-02-27 21:20:42 +00:00
|
|
|
#include "netlabel.h"
|
2007-02-28 20:14:22 +00:00
|
|
|
|
2008-01-29 13:44:18 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_sidlookup_cached - Cache a SID lookup
|
|
|
|
* @skb: the packet
|
|
|
|
* @secattr: the NetLabel security attributes
|
|
|
|
* @sid: the SID
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Query the SELinux security server to lookup the correct SID for the given
|
|
|
|
* security attributes. If the query is successful, cache the result to speed
|
|
|
|
* up future lookups. Returns zero on success, negative values on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
|
2016-06-27 19:06:17 +00:00
|
|
|
u16 family,
|
2008-01-29 13:44:18 +00:00
|
|
|
struct netlbl_lsm_secattr *secattr,
|
|
|
|
u32 *sid)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
2018-03-01 23:48:02 +00:00
|
|
|
rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
|
2008-01-29 13:44:18 +00:00
|
|
|
if (rc == 0 &&
|
|
|
|
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
|
|
|
|
(secattr->flags & NETLBL_SECATTR_CACHE))
|
2016-06-27 19:06:17 +00:00
|
|
|
netlbl_cache_add(skb, family, secattr);
|
2008-01-29 13:44:18 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-10-10 14:16:33 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
|
|
|
|
* @sk: the socket
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Generate the NetLabel security attributes for a socket, making full use of
|
|
|
|
* the socket's attribute cache. Returns a pointer to the security attributes
|
|
|
|
* on success, NULL on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
struct netlbl_lsm_secattr *secattr;
|
|
|
|
|
|
|
|
if (sksec->nlbl_secattr != NULL)
|
|
|
|
return sksec->nlbl_secattr;
|
|
|
|
|
|
|
|
secattr = netlbl_secattr_alloc(GFP_ATOMIC);
|
|
|
|
if (secattr == NULL)
|
|
|
|
return NULL;
|
2018-03-01 23:48:02 +00:00
|
|
|
rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
|
|
|
|
secattr);
|
2008-10-10 14:16:33 +00:00
|
|
|
if (rc != 0) {
|
|
|
|
netlbl_secattr_free(secattr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
sksec->nlbl_secattr = secattr;
|
|
|
|
|
|
|
|
return secattr;
|
|
|
|
}
|
|
|
|
|
2013-12-03 16:36:11 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
|
|
|
|
* @sk: the socket
|
|
|
|
* @sid: the SID
|
|
|
|
*
|
|
|
|
* Query the socket's cached secattr and if the SID matches the cached value
|
|
|
|
* return the cache, otherwise return NULL.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
|
|
|
|
const struct sock *sk,
|
|
|
|
u32 sid)
|
|
|
|
{
|
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
|
|
|
|
|
|
|
|
if (secattr == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if ((secattr->flags & NETLBL_SECATTR_SECID) &&
|
|
|
|
(secattr->attr.secid == sid))
|
|
|
|
return secattr;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2007-02-28 20:14:22 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Invalidate the NetLabel security attribute mapping cache.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void selinux_netlbl_cache_invalidate(void)
|
|
|
|
{
|
|
|
|
netlbl_cache_invalidate();
|
|
|
|
}
|
|
|
|
|
2008-10-10 14:16:31 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_err - Handle a NetLabel packet error
|
|
|
|
* @skb: the packet
|
|
|
|
* @error: the error code
|
|
|
|
* @gateway: true if host is acting as a gateway, false otherwise
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* When a packet is dropped due to a call to avc_has_perm() pass the error
|
|
|
|
* code to the NetLabel subsystem so any protocol specific processing can be
|
|
|
|
* done. This is safe to call even if you are unsure if NetLabel labeling is
|
|
|
|
* present on the packet, NetLabel is smart enough to only act when it should.
|
|
|
|
*
|
|
|
|
*/
|
2016-06-27 19:06:16 +00:00
|
|
|
void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
|
2008-10-10 14:16:31 +00:00
|
|
|
{
|
2016-06-27 19:06:16 +00:00
|
|
|
netlbl_skbuff_err(skb, family, error, gateway);
|
2008-10-10 14:16:31 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 14:16:33 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_sk_security_free - Free the NetLabel fields
|
2010-04-07 19:08:46 +00:00
|
|
|
* @sksec: the sk_security_struct
|
2008-10-10 14:16:33 +00:00
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Free all of the memory in the NetLabel fields of a sk_security_struct.
|
|
|
|
*
|
|
|
|
*/
|
2010-04-07 19:08:46 +00:00
|
|
|
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec)
|
2008-10-10 14:16:33 +00:00
|
|
|
{
|
2010-04-07 19:08:46 +00:00
|
|
|
if (sksec->nlbl_secattr != NULL)
|
|
|
|
netlbl_secattr_free(sksec->nlbl_secattr);
|
2008-10-10 14:16:33 +00:00
|
|
|
}
|
|
|
|
|
2007-02-28 20:14:22 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields
|
2010-04-07 19:08:46 +00:00
|
|
|
* @sksec: the sk_security_struct
|
2007-02-28 20:14:22 +00:00
|
|
|
* @family: the socket family
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Called when the NetLabel state of a sk_security_struct needs to be reset.
|
2011-03-31 01:57:33 +00:00
|
|
|
* The caller is responsible for all the NetLabel sk_security_struct locking.
|
2007-02-28 20:14:22 +00:00
|
|
|
*
|
|
|
|
*/
|
2010-04-07 19:08:46 +00:00
|
|
|
void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec)
|
2007-02-28 20:14:22 +00:00
|
|
|
{
|
2010-04-07 19:08:46 +00:00
|
|
|
sksec->nlbl_state = NLBL_UNSET;
|
2007-02-28 20:14:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
|
|
|
|
* @skb: the packet
|
2008-01-29 13:38:04 +00:00
|
|
|
* @family: protocol family
|
2008-01-29 13:38:23 +00:00
|
|
|
* @type: NetLabel labeling protocol type
|
2007-02-28 20:14:22 +00:00
|
|
|
* @sid: the SID
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Call the NetLabel mechanism to get the security attributes of the given
|
|
|
|
* packet and use those attributes to determine the correct context/SID to
|
|
|
|
* assign to the packet. Returns zero on success, negative values on failure.
|
|
|
|
*
|
|
|
|
*/
|
2008-01-29 13:38:04 +00:00
|
|
|
int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
|
|
|
|
u16 family,
|
2008-01-29 13:38:23 +00:00
|
|
|
u32 *type,
|
2008-01-29 13:38:04 +00:00
|
|
|
u32 *sid)
|
2007-02-28 20:14:22 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct netlbl_lsm_secattr secattr;
|
|
|
|
|
2007-07-18 16:28:45 +00:00
|
|
|
if (!netlbl_enabled()) {
|
|
|
|
*sid = SECSID_NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-28 20:14:22 +00:00
|
|
|
netlbl_secattr_init(&secattr);
|
2008-01-29 13:38:04 +00:00
|
|
|
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
2008-01-29 13:44:18 +00:00
|
|
|
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
2016-06-27 19:06:17 +00:00
|
|
|
rc = selinux_netlbl_sidlookup_cached(skb, family,
|
|
|
|
&secattr, sid);
|
2008-01-29 13:44:18 +00:00
|
|
|
else
|
2007-02-28 20:14:22 +00:00
|
|
|
*sid = SECSID_NULL;
|
2008-01-29 13:38:23 +00:00
|
|
|
*type = secattr.type;
|
2007-02-28 20:14:22 +00:00
|
|
|
netlbl_secattr_destroy(&secattr);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2008-10-10 14:16:32 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
|
|
|
|
* @skb: the packet
|
|
|
|
* @family: protocol family
|
|
|
|
* @sid: the SID
|
|
|
|
*
|
|
|
|
* Description
|
|
|
|
* Call the NetLabel mechanism to set the label of a packet using @sid.
|
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 15:09:05 +00:00
|
|
|
* Returns zero on success, negative values on failure.
|
2008-10-10 14:16:32 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
|
|
|
|
u16 family,
|
|
|
|
u32 sid)
|
|
|
|
{
|
|
|
|
int rc;
|
2008-10-10 14:16:33 +00:00
|
|
|
struct netlbl_lsm_secattr secattr_storage;
|
|
|
|
struct netlbl_lsm_secattr *secattr = NULL;
|
2008-10-10 14:16:32 +00:00
|
|
|
struct sock *sk;
|
|
|
|
|
|
|
|
/* if this is a locally generated packet check to see if it is already
|
|
|
|
* being labeled by it's parent socket, if it is just exit */
|
2015-11-08 18:54:07 +00:00
|
|
|
sk = skb_to_full_sk(skb);
|
2008-10-10 14:16:32 +00:00
|
|
|
if (sk != NULL) {
|
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
2018-02-13 20:57:18 +00:00
|
|
|
|
2008-10-10 14:16:32 +00:00
|
|
|
if (sksec->nlbl_state != NLBL_REQSKB)
|
|
|
|
return 0;
|
2013-12-03 16:36:11 +00:00
|
|
|
secattr = selinux_netlbl_sock_getattr(sk, sid);
|
2008-10-10 14:16:33 +00:00
|
|
|
}
|
|
|
|
if (secattr == NULL) {
|
|
|
|
secattr = &secattr_storage;
|
|
|
|
netlbl_secattr_init(secattr);
|
2018-03-01 23:48:02 +00:00
|
|
|
rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
|
|
|
|
secattr);
|
2008-10-10 14:16:33 +00:00
|
|
|
if (rc != 0)
|
|
|
|
goto skbuff_setsid_return;
|
2008-10-10 14:16:32 +00:00
|
|
|
}
|
|
|
|
|
2008-10-10 14:16:33 +00:00
|
|
|
rc = netlbl_skbuff_setattr(skb, family, secattr);
|
2008-10-10 14:16:32 +00:00
|
|
|
|
|
|
|
skbuff_setsid_return:
|
2008-10-10 14:16:33 +00:00
|
|
|
if (secattr == &secattr_storage)
|
|
|
|
netlbl_secattr_destroy(secattr);
|
2008-10-10 14:16:32 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-02-13 20:57:18 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_sctp_assoc_request - Label an incoming sctp association.
|
|
|
|
* @ep: incoming association endpoint.
|
|
|
|
* @skb: the packet.
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* A new incoming connection is represented by @ep, ......
|
|
|
|
* Returns zero on success, negative values on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
|
|
|
|
struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct netlbl_lsm_secattr secattr;
|
|
|
|
struct sk_security_struct *sksec = ep->base.sk->sk_security;
|
|
|
|
struct sockaddr_in addr4;
|
|
|
|
struct sockaddr_in6 addr6;
|
|
|
|
|
|
|
|
if (ep->base.sk->sk_family != PF_INET &&
|
|
|
|
ep->base.sk->sk_family != PF_INET6)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
netlbl_secattr_init(&secattr);
|
2018-03-01 23:48:02 +00:00
|
|
|
rc = security_netlbl_sid_to_secattr(&selinux_state,
|
|
|
|
ep->secid, &secattr);
|
2018-02-13 20:57:18 +00:00
|
|
|
if (rc != 0)
|
|
|
|
goto assoc_request_return;
|
|
|
|
|
|
|
|
/* Move skb hdr address info to a struct sockaddr and then call
|
|
|
|
* netlbl_conn_setattr().
|
|
|
|
*/
|
|
|
|
if (ip_hdr(skb)->version == 4) {
|
|
|
|
addr4.sin_family = AF_INET;
|
|
|
|
addr4.sin_addr.s_addr = ip_hdr(skb)->saddr;
|
2019-03-25 14:23:11 +00:00
|
|
|
rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr4, &secattr);
|
|
|
|
} else if (IS_ENABLED(CONFIG_IPV6) && ip_hdr(skb)->version == 6) {
|
2018-02-13 20:57:18 +00:00
|
|
|
addr6.sin6_family = AF_INET6;
|
|
|
|
addr6.sin6_addr = ipv6_hdr(skb)->saddr;
|
2019-03-25 14:23:11 +00:00
|
|
|
rc = netlbl_conn_setattr(ep->base.sk, (void *)&addr6, &secattr);
|
|
|
|
} else {
|
|
|
|
rc = -EAFNOSUPPORT;
|
2018-02-13 20:57:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == 0)
|
|
|
|
sksec->nlbl_state = NLBL_LABELED;
|
|
|
|
|
|
|
|
assoc_request_return:
|
|
|
|
netlbl_secattr_destroy(&secattr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2007-02-28 20:14:22 +00:00
|
|
|
/**
|
2009-03-27 21:10:34 +00:00
|
|
|
* selinux_netlbl_inet_conn_request - Label an incoming stream connection
|
|
|
|
* @req: incoming connection request socket
|
2007-02-28 20:14:22 +00:00
|
|
|
*
|
|
|
|
* Description:
|
2009-03-27 21:10:34 +00:00
|
|
|
* A new incoming connection request is represented by @req, we need to label
|
|
|
|
* the new request_sock here and the stack will ensure the on-the-wire label
|
|
|
|
* will get preserved when a full sock is created once the connection handshake
|
|
|
|
* is complete. Returns zero on success, negative values on failure.
|
2007-02-28 20:14:22 +00:00
|
|
|
*
|
|
|
|
*/
|
2009-03-27 21:10:34 +00:00
|
|
|
int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
|
2007-02-28 20:14:22 +00:00
|
|
|
{
|
2008-10-10 14:16:33 +00:00
|
|
|
int rc;
|
2009-03-27 21:10:34 +00:00
|
|
|
struct netlbl_lsm_secattr secattr;
|
2008-10-10 14:16:33 +00:00
|
|
|
|
2016-06-27 19:05:29 +00:00
|
|
|
if (family != PF_INET && family != PF_INET6)
|
2009-03-27 21:10:34 +00:00
|
|
|
return 0;
|
2008-10-10 14:16:33 +00:00
|
|
|
|
2009-03-27 21:10:34 +00:00
|
|
|
netlbl_secattr_init(&secattr);
|
2018-03-01 23:48:02 +00:00
|
|
|
rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
|
|
|
|
&secattr);
|
2009-03-27 21:10:34 +00:00
|
|
|
if (rc != 0)
|
|
|
|
goto inet_conn_request_return;
|
|
|
|
rc = netlbl_req_setattr(req, &secattr);
|
|
|
|
inet_conn_request_return:
|
|
|
|
netlbl_secattr_destroy(&secattr);
|
|
|
|
return rc;
|
2007-02-28 20:14:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-03-27 21:10:34 +00:00
|
|
|
* selinux_netlbl_inet_csk_clone - Initialize the newly created sock
|
|
|
|
* @sk: the new sock
|
2007-02-28 20:14:22 +00:00
|
|
|
*
|
|
|
|
* Description:
|
2009-03-27 21:10:34 +00:00
|
|
|
* A new connection has been established using @sk, we've already labeled the
|
|
|
|
* socket via the request_sock struct in selinux_netlbl_inet_conn_request() but
|
|
|
|
* we need to set the NetLabel state here since we now have a sock structure.
|
2007-02-28 20:14:22 +00:00
|
|
|
*
|
|
|
|
*/
|
2009-03-27 21:10:34 +00:00
|
|
|
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
|
2007-02-28 20:14:22 +00:00
|
|
|
{
|
2009-03-27 21:10:34 +00:00
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
|
|
|
|
if (family == PF_INET)
|
|
|
|
sksec->nlbl_state = NLBL_LABELED;
|
|
|
|
else
|
|
|
|
sksec->nlbl_state = NLBL_UNSET;
|
2007-02-28 20:14:22 +00:00
|
|
|
}
|
|
|
|
|
2018-02-13 20:57:18 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_sctp_sk_clone - Copy state to the newly created sock
|
|
|
|
* @sk: current sock
|
|
|
|
* @newsk: the new sock
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Called whenever a new socket is created by accept(2) or sctp_peeloff(3).
|
|
|
|
*/
|
|
|
|
void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
|
|
|
|
{
|
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
struct sk_security_struct *newsksec = newsk->sk_security;
|
|
|
|
|
|
|
|
newsksec->nlbl_state = sksec->nlbl_state;
|
|
|
|
}
|
|
|
|
|
2007-02-28 20:14:22 +00:00
|
|
|
/**
|
2009-03-27 21:10:34 +00:00
|
|
|
* selinux_netlbl_socket_post_create - Label a socket using NetLabel
|
|
|
|
* @sock: the socket to label
|
|
|
|
* @family: protocol family
|
2007-02-28 20:14:22 +00:00
|
|
|
*
|
|
|
|
* Description:
|
2009-03-27 21:10:34 +00:00
|
|
|
* Attempt to label a socket using the NetLabel mechanism using the given
|
|
|
|
* SID. Returns zero values on success, negative values on failure.
|
2007-02-28 20:14:22 +00:00
|
|
|
*
|
|
|
|
*/
|
2009-03-27 21:10:34 +00:00
|
|
|
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
|
2007-02-28 20:14:22 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2009-03-27 21:10:34 +00:00
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
struct netlbl_lsm_secattr *secattr;
|
2007-02-28 20:14:22 +00:00
|
|
|
|
2016-06-27 19:02:51 +00:00
|
|
|
if (family != PF_INET && family != PF_INET6)
|
2007-02-28 20:14:22 +00:00
|
|
|
return 0;
|
2008-02-25 16:40:33 +00:00
|
|
|
|
2009-03-27 21:10:34 +00:00
|
|
|
secattr = selinux_netlbl_sock_genattr(sk);
|
|
|
|
if (secattr == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
rc = netlbl_sock_setattr(sk, family, secattr);
|
|
|
|
switch (rc) {
|
|
|
|
case 0:
|
|
|
|
sksec->nlbl_state = NLBL_LABELED;
|
|
|
|
break;
|
|
|
|
case -EDESTADDRREQ:
|
|
|
|
sksec->nlbl_state = NLBL_REQSKB;
|
2008-02-25 16:40:33 +00:00
|
|
|
rc = 0;
|
2009-03-27 21:10:34 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-02-28 20:14:22 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
|
|
|
|
* @sksec: the sock's sk_security_struct
|
|
|
|
* @skb: the packet
|
2008-01-29 13:38:04 +00:00
|
|
|
* @family: protocol family
|
2007-02-28 20:14:22 +00:00
|
|
|
* @ad: the audit data
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Fetch the NetLabel security attributes from @skb and perform an access check
|
|
|
|
* against the receiving socket. Returns zero on success, negative values on
|
|
|
|
* error.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
|
|
|
struct sk_buff *skb,
|
2008-01-29 13:38:04 +00:00
|
|
|
u16 family,
|
2009-07-14 16:14:09 +00:00
|
|
|
struct common_audit_data *ad)
|
2007-02-28 20:14:22 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2007-07-18 16:28:46 +00:00
|
|
|
u32 nlbl_sid;
|
|
|
|
u32 perm;
|
|
|
|
struct netlbl_lsm_secattr secattr;
|
2007-02-28 20:14:22 +00:00
|
|
|
|
2007-07-18 16:28:45 +00:00
|
|
|
if (!netlbl_enabled())
|
|
|
|
return 0;
|
|
|
|
|
2007-07-18 16:28:46 +00:00
|
|
|
netlbl_secattr_init(&secattr);
|
2008-01-29 13:38:04 +00:00
|
|
|
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
2008-01-29 13:44:18 +00:00
|
|
|
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
2016-06-27 19:06:17 +00:00
|
|
|
rc = selinux_netlbl_sidlookup_cached(skb, family,
|
|
|
|
&secattr, &nlbl_sid);
|
2008-01-29 13:44:18 +00:00
|
|
|
else
|
2007-07-18 16:28:46 +00:00
|
|
|
nlbl_sid = SECINITSID_UNLABELED;
|
|
|
|
netlbl_secattr_destroy(&secattr);
|
2007-02-28 20:14:22 +00:00
|
|
|
if (rc != 0)
|
|
|
|
return rc;
|
2007-07-13 23:53:18 +00:00
|
|
|
|
2007-02-28 20:14:22 +00:00
|
|
|
switch (sksec->sclass) {
|
|
|
|
case SECCLASS_UDP_SOCKET:
|
2007-07-18 16:28:46 +00:00
|
|
|
perm = UDP_SOCKET__RECVFROM;
|
2007-02-28 20:14:22 +00:00
|
|
|
break;
|
|
|
|
case SECCLASS_TCP_SOCKET:
|
2007-07-18 16:28:46 +00:00
|
|
|
perm = TCP_SOCKET__RECVFROM;
|
2007-02-28 20:14:22 +00:00
|
|
|
break;
|
|
|
|
default:
|
2007-07-18 16:28:46 +00:00
|
|
|
perm = RAWIP_SOCKET__RECVFROM;
|
2007-02-28 20:14:22 +00:00
|
|
|
}
|
|
|
|
|
2018-03-05 16:47:56 +00:00
|
|
|
rc = avc_has_perm(&selinux_state,
|
|
|
|
sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
|
2007-02-28 20:14:22 +00:00
|
|
|
if (rc == 0)
|
|
|
|
return 0;
|
|
|
|
|
2007-07-18 16:28:46 +00:00
|
|
|
if (nlbl_sid != SECINITSID_UNLABELED)
|
2016-06-27 19:06:16 +00:00
|
|
|
netlbl_skbuff_err(skb, family, rc, 0);
|
2007-02-28 20:14:22 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-06-27 19:05:27 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_option - Is this a NetLabel option
|
|
|
|
* @level: the socket level or protocol
|
|
|
|
* @optname: the socket option name
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Returns true if @level and @optname refer to a NetLabel option.
|
|
|
|
* Helper for selinux_netlbl_socket_setsockopt().
|
|
|
|
*/
|
|
|
|
static inline int selinux_netlbl_option(int level, int optname)
|
|
|
|
{
|
|
|
|
return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
|
|
|
|
(level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
|
|
|
|
}
|
|
|
|
|
2007-02-28 20:14:22 +00:00
|
|
|
/**
|
|
|
|
* selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
|
|
|
|
* @sock: the socket
|
|
|
|
* @level: the socket level or protocol
|
|
|
|
* @optname: the socket option name
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Check the setsockopt() call and if the user is trying to replace the IP
|
|
|
|
* options on a socket and a NetLabel is in place for the socket deny the
|
|
|
|
* access; otherwise allow the access. Returns zero when the access is
|
|
|
|
* allowed, -EACCES when denied, and other negative values on error.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
|
|
|
int level,
|
|
|
|
int optname)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
2007-06-08 01:37:15 +00:00
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
2007-02-28 20:14:22 +00:00
|
|
|
struct netlbl_lsm_secattr secattr;
|
|
|
|
|
2016-06-27 19:05:27 +00:00
|
|
|
if (selinux_netlbl_option(level, optname) &&
|
2008-10-10 14:16:33 +00:00
|
|
|
(sksec->nlbl_state == NLBL_LABELED ||
|
|
|
|
sksec->nlbl_state == NLBL_CONNLABELED)) {
|
2007-02-28 20:14:22 +00:00
|
|
|
netlbl_secattr_init(&secattr);
|
2007-06-08 01:37:15 +00:00
|
|
|
lock_sock(sk);
|
2013-12-03 16:36:11 +00:00
|
|
|
/* call the netlabel function directly as we want to see the
|
|
|
|
* on-the-wire label that is assigned via the socket's options
|
|
|
|
* and not the cached netlabel/lsm attributes */
|
2007-06-08 01:37:15 +00:00
|
|
|
rc = netlbl_sock_getattr(sk, &secattr);
|
|
|
|
release_sock(sk);
|
2009-02-20 21:33:02 +00:00
|
|
|
if (rc == 0)
|
2007-02-28 20:14:22 +00:00
|
|
|
rc = -EACCES;
|
2009-02-20 21:33:02 +00:00
|
|
|
else if (rc == -ENOMSG)
|
|
|
|
rc = 0;
|
2007-02-28 20:14:22 +00:00
|
|
|
netlbl_secattr_destroy(&secattr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
2008-10-10 14:16:33 +00:00
|
|
|
|
|
|
|
/**
|
2018-02-13 20:57:18 +00:00
|
|
|
* selinux_netlbl_socket_connect_helper - Help label a client-side socket on
|
|
|
|
* connect
|
2008-10-10 14:16:33 +00:00
|
|
|
* @sk: the socket to label
|
|
|
|
* @addr: the destination address
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Attempt to label a connected socket with NetLabel using the given address.
|
|
|
|
* Returns zero values on success, negative values on failure.
|
|
|
|
*
|
|
|
|
*/
|
2018-02-13 20:57:18 +00:00
|
|
|
static int selinux_netlbl_socket_connect_helper(struct sock *sk,
|
|
|
|
struct sockaddr *addr)
|
2008-10-10 14:16:33 +00:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
2008-10-10 14:16:33 +00:00
|
|
|
struct netlbl_lsm_secattr *secattr;
|
2008-10-10 14:16:33 +00:00
|
|
|
|
|
|
|
/* connected sockets are allowed to disconnect when the address family
|
|
|
|
* is set to AF_UNSPEC, if that is what is happening we want to reset
|
|
|
|
* the socket */
|
|
|
|
if (addr->sa_family == AF_UNSPEC) {
|
|
|
|
netlbl_sock_delattr(sk);
|
|
|
|
sksec->nlbl_state = NLBL_REQSKB;
|
|
|
|
rc = 0;
|
2018-02-13 20:57:18 +00:00
|
|
|
return rc;
|
2008-10-10 14:16:33 +00:00
|
|
|
}
|
2008-10-10 14:16:33 +00:00
|
|
|
secattr = selinux_netlbl_sock_genattr(sk);
|
|
|
|
if (secattr == NULL) {
|
|
|
|
rc = -ENOMEM;
|
2018-02-13 20:57:18 +00:00
|
|
|
return rc;
|
2008-10-10 14:16:33 +00:00
|
|
|
}
|
|
|
|
rc = netlbl_conn_setattr(sk, addr, secattr);
|
|
|
|
if (rc == 0)
|
|
|
|
sksec->nlbl_state = NLBL_CONNLABELED;
|
2008-10-10 14:16:33 +00:00
|
|
|
|
2018-02-13 20:57:18 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* selinux_netlbl_socket_connect_locked - Label a client-side socket on
|
|
|
|
* connect
|
|
|
|
* @sk: the socket to label
|
|
|
|
* @addr: the destination address
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Attempt to label a connected socket that already has the socket locked
|
|
|
|
* with NetLabel using the given address.
|
|
|
|
* Returns zero values on success, negative values on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int selinux_netlbl_socket_connect_locked(struct sock *sk,
|
|
|
|
struct sockaddr *addr)
|
|
|
|
{
|
|
|
|
struct sk_security_struct *sksec = sk->sk_security;
|
|
|
|
|
|
|
|
if (sksec->nlbl_state != NLBL_REQSKB &&
|
|
|
|
sksec->nlbl_state != NLBL_CONNLABELED)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return selinux_netlbl_socket_connect_helper(sk, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* selinux_netlbl_socket_connect - Label a client-side socket on connect
|
|
|
|
* @sk: the socket to label
|
|
|
|
* @addr: the destination address
|
|
|
|
*
|
|
|
|
* Description:
|
|
|
|
* Attempt to label a connected socket with NetLabel using the given address.
|
|
|
|
* Returns zero values on success, negative values on failure.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
lock_sock(sk);
|
|
|
|
rc = selinux_netlbl_socket_connect_locked(sk, addr);
|
2013-09-26 21:00:46 +00:00
|
|
|
release_sock(sk);
|
2018-02-13 20:57:18 +00:00
|
|
|
|
2008-10-10 14:16:33 +00:00
|
|
|
return rc;
|
|
|
|
}
|