提交 9eda2d2d 编写于 作者: L Linus Torvalds

Merge tag 'selinux-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull SELinux updates from Paul Moore:
 "A bigger than usual pull request for SELinux, 13 patches (lucky!)
  along with a scary looking diffstat.

  Although if you look a bit closer, excluding the usual minor
  tweaks/fixes, there are really only two significant changes in this
  pull request: the addition of proper SELinux access controls for SCTP
  and the encapsulation of a lot of internal SELinux state.

  The SCTP changes are the result of a multi-month effort (maybe even a
  year or longer?) between the SELinux folks and the SCTP folks to add
  proper SELinux controls. A special thanks go to Richard for seeing
  this through and keeping the effort moving forward.

  The state encapsulation work is a bit of janitorial work that came out
  of some early work on SELinux namespacing. The question of namespacing
  is still an open one, but I believe there is some real value in the
  encapsulation work so we've split that out and are now sending that up
  to you"

* tag 'selinux-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: wrap AVC state
  selinux: wrap selinuxfs state
  selinux: fix handling of uninitialized selinux state in get_bools/classes
  selinux: Update SELinux SCTP documentation
  selinux: Fix ltp test connect-syscall failure
  selinux: rename the {is,set}_enforcing() functions
  selinux: wrap global selinux state
  selinux: fix typo in selinux_netlbl_sctp_sk_clone declaration
  selinux: Add SCTP support
  sctp: Add LSM hooks
  sctp: Add ip option support
  security: Add support for SCTP security hooks
  netlabel: If PF_INET6, check sk_buff ip header version
SCTP LSM Support
================
For security module support, three SCTP specific hooks have been implemented::
security_sctp_assoc_request()
security_sctp_bind_connect()
security_sctp_sk_clone()
Also the following security hook has been utilised::
security_inet_conn_established()
The usage of these hooks are described below with the SELinux implementation
described in ``Documentation/security/SELinux-sctp.rst``
security_sctp_assoc_request()
-----------------------------
Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@ep - pointer to sctp endpoint structure.
@skb - pointer to skbuff of association packet.
security_sctp_bind_connect()
-----------------------------
Passes one or more ipv4/ipv6 addresses to the security module for validation
based on the ``@optname`` that will result in either a bind or connect
service as shown in the permission check tables below.
Returns 0 on success, error on failure.
::
@sk - Pointer to sock structure.
@optname - Name of the option to validate.
@address - One or more ipv4 / ipv6 addresses.
@addrlen - The total length of address(s). This is calculated on each
ipv4 or ipv6 address using sizeof(struct sockaddr_in) or
sizeof(struct sockaddr_in6).
------------------------------------------------------------------
| BIND Type Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_BINDX_ADD | One or more ipv4 / ipv6 addresses |
| SCTP_PRIMARY_ADDR | Single ipv4 or ipv6 address |
| SCTP_SET_PEER_PRIMARY_ADDR | Single ipv4 or ipv6 address |
------------------------------------------------------------------
------------------------------------------------------------------
| CONNECT Type Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_CONNECTX | One or more ipv4 / ipv6 addresses |
| SCTP_PARAM_ADD_IP | One or more ipv4 / ipv6 addresses |
| SCTP_SENDMSG_CONNECT | Single ipv4 or ipv6 address |
| SCTP_PARAM_SET_PRIMARY | Single ipv4 or ipv6 address |
------------------------------------------------------------------
A summary of the ``@optname`` entries is as follows::
SCTP_SOCKOPT_BINDX_ADD - Allows additional bind addresses to be
associated after (optionally) calling
bind(3).
sctp_bindx(3) adds a set of bind
addresses on a socket.
SCTP_SOCKOPT_CONNECTX - Allows the allocation of multiple
addresses for reaching a peer
(multi-homed).
sctp_connectx(3) initiates a connection
on an SCTP socket using multiple
destination addresses.
SCTP_SENDMSG_CONNECT - Initiate a connection that is generated by a
sendmsg(2) or sctp_sendmsg(3) on a new asociation.
SCTP_PRIMARY_ADDR - Set local primary address.
SCTP_SET_PEER_PRIMARY_ADDR - Request peer sets address as
association primary.
SCTP_PARAM_ADD_IP - These are used when Dynamic Address
SCTP_PARAM_SET_PRIMARY - Reconfiguration is enabled as explained below.
To support Dynamic Address Reconfiguration the following parameters must be
enabled on both endpoints (or use the appropriate **setsockopt**\(2))::
/proc/sys/net/sctp/addip_enable
/proc/sys/net/sctp/addip_noauth_enable
then the following *_PARAM_*'s are sent to the peer in an
ASCONF chunk when the corresponding ``@optname``'s are present::
@optname ASCONF Parameter
---------- ------------------
SCTP_SOCKOPT_BINDX_ADD -> SCTP_PARAM_ADD_IP
SCTP_SET_PEER_PRIMARY_ADDR -> SCTP_PARAM_SET_PRIMARY
security_sctp_sk_clone()
-------------------------
Called whenever a new socket is created by **accept**\(2)
(i.e. a TCP style socket) or when a socket is 'peeled off' e.g userspace
calls **sctp_peeloff**\(3).
::
@ep - pointer to current sctp endpoint structure.
@sk - pointer to current sock structure.
@sk - pointer to new sock structure.
security_inet_conn_established()
---------------------------------
Called when a COOKIE ACK is received::
@sk - pointer to sock structure.
@skb - pointer to skbuff of the COOKIE ACK packet.
Security Hooks used for Association Establishment
=================================================
The following diagram shows the use of ``security_sctp_bind_connect()``,
``security_sctp_assoc_request()``, ``security_inet_conn_established()`` when
establishing an association.
::
SCTP endpoint "A" SCTP endpoint "Z"
================= =================
sctp_sf_do_prm_asoc()
Association setup can be initiated
by a connect(2), sctp_connectx(3),
sendmsg(2) or sctp_sendmsg(3).
These will result in a call to
security_sctp_bind_connect() to
initiate an association to
SCTP peer endpoint "Z".
INIT --------------------------------------------->
sctp_sf_do_5_1B_init()
Respond to an INIT chunk.
SCTP peer endpoint "A" is
asking for an association. Call
security_sctp_assoc_request()
to set the peer label if first
association.
If not first association, check
whether allowed, IF so send:
<----------------------------------------------- INIT ACK
| ELSE audit event and silently
| discard the packet.
|
COOKIE ECHO ------------------------------------------>
|
|
|
<------------------------------------------- COOKIE ACK
| |
sctp_sf_do_5_1E_ca |
Call security_inet_conn_established() |
to set the peer label. |
| |
| If SCTP_SOCKET_TCP or peeled off
| socket security_sctp_sk_clone() is
| called to clone the new socket.
| |
ESTABLISHED ESTABLISHED
| |
------------------------------------------------------------------
| Association Established |
------------------------------------------------------------------
SCTP SELinux Support
=====================
Security Hooks
===============
``Documentation/security/LSM-sctp.rst`` describes the following SCTP security
hooks with the SELinux specifics expanded below::
security_sctp_assoc_request()
security_sctp_bind_connect()
security_sctp_sk_clone()
security_inet_conn_established()
security_sctp_assoc_request()
-----------------------------
Passes the ``@ep`` and ``@chunk->skb`` of the association INIT packet to the
security module. Returns 0 on success, error on failure.
::
@ep - pointer to sctp endpoint structure.
@skb - pointer to skbuff of association packet.
The security module performs the following operations:
IF this is the first association on ``@ep->base.sk``, then set the peer
sid to that in ``@skb``. This will ensure there is only one peer sid
assigned to ``@ep->base.sk`` that may support multiple associations.
ELSE validate the ``@ep->base.sk peer_sid`` against the ``@skb peer sid``
to determine whether the association should be allowed or denied.
Set the sctp ``@ep sid`` to socket's sid (from ``ep->base.sk``) with
MLS portion taken from ``@skb peer sid``. This will be used by SCTP
TCP style sockets and peeled off connections as they cause a new socket
to be generated.
If IP security options are configured (CIPSO/CALIPSO), then the ip
options are set on the socket.
security_sctp_bind_connect()
-----------------------------
Checks permissions required for ipv4/ipv6 addresses based on the ``@optname``
as follows::
------------------------------------------------------------------
| BIND Permission Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_BINDX_ADD | One or more ipv4 / ipv6 addresses |
| SCTP_PRIMARY_ADDR | Single ipv4 or ipv6 address |
| SCTP_SET_PEER_PRIMARY_ADDR | Single ipv4 or ipv6 address |
------------------------------------------------------------------
------------------------------------------------------------------
| CONNECT Permission Checks |
| @optname | @address contains |
|----------------------------|-----------------------------------|
| SCTP_SOCKOPT_CONNECTX | One or more ipv4 / ipv6 addresses |
| SCTP_PARAM_ADD_IP | One or more ipv4 / ipv6 addresses |
| SCTP_SENDMSG_CONNECT | Single ipv4 or ipv6 address |
| SCTP_PARAM_SET_PRIMARY | Single ipv4 or ipv6 address |
------------------------------------------------------------------
``Documentation/security/LSM-sctp.rst`` gives a summary of the ``@optname``
entries and also describes ASCONF chunk processing when Dynamic Address
Reconfiguration is enabled.
security_sctp_sk_clone()
-------------------------
Called whenever a new socket is created by **accept**\(2) (i.e. a TCP style
socket) or when a socket is 'peeled off' e.g userspace calls
**sctp_peeloff**\(3). ``security_sctp_sk_clone()`` will set the new
sockets sid and peer sid to that contained in the ``@ep sid`` and
``@ep peer sid`` respectively.
::
@ep - pointer to current sctp endpoint structure.
@sk - pointer to current sock structure.
@sk - pointer to new sock structure.
security_inet_conn_established()
---------------------------------
Called when a COOKIE ACK is received where it sets the connection's peer sid
to that in ``@skb``::
@sk - pointer to sock structure.
@skb - pointer to skbuff of the COOKIE ACK packet.
Policy Statements
==================
The following class and permissions to support SCTP are available within the
kernel::
class sctp_socket inherits socket { node_bind }
whenever the following policy capability is enabled::
policycap extended_socket_class;
SELinux SCTP support adds the ``name_connect`` permission for connecting
to a specific port type and the ``association`` permission that is explained
in the section below.
If userspace tools have been updated, SCTP will support the ``portcon``
statement as shown in the following example::
portcon sctp 1024-1036 system_u:object_r:sctp_ports_t:s0
SCTP Peer Labeling
===================
An SCTP socket will only have one peer label assigned to it. This will be
assigned during the establishment of the first association. Any further
associations on this socket will have their packet peer label compared to
the sockets peer label, and only if they are different will the
``association`` permission be validated. This is validated by checking the
socket peer sid against the received packets peer sid to determine whether
the association should be allowed or denied.
NOTES:
1) If peer labeling is not enabled, then the peer context will always be
``SECINITSID_UNLABELED`` (``unlabeled_t`` in Reference Policy).
2) As SCTP can support more than one transport address per endpoint
(multi-homing) on a single socket, it is possible to configure policy
and NetLabel to provide different peer labels for each of these. As the
socket peer label is determined by the first associations transport
address, it is recommended that all peer labels are consistent.
3) **getpeercon**\(3) may be used by userspace to retrieve the sockets peer
context.
4) While not SCTP specific, be aware when using NetLabel that if a label
is assigned to a specific interface, and that interface 'goes down',
then the NetLabel service will remove the entry. Therefore ensure that
the network startup scripts call **netlabelctl**\(8) to set the required
label (see **netlabel-config**\(8) helper script for details).
5) The NetLabel SCTP peer labeling rules apply as discussed in the following
set of posts tagged "netlabel" at: http://www.paul-moore.com/blog/t.
6) CIPSO is only supported for IPv4 addressing: ``socket(AF_INET, ...)``
CALIPSO is only supported for IPv6 addressing: ``socket(AF_INET6, ...)``
Note the following when testing CIPSO/CALIPSO:
a) CIPSO will send an ICMP packet if an SCTP packet cannot be
delivered because of an invalid label.
b) CALIPSO does not send an ICMP packet, just silently discards it.
7) IPSEC is not supported as RFC 3554 - sctp/ipsec support has not been
implemented in userspace (**racoon**\(8) or **ipsec_pluto**\(8)),
although the kernel supports SCTP/IPSEC.
...@@ -906,6 +906,33 @@ ...@@ -906,6 +906,33 @@
* associated with the TUN device's security structure. * associated with the TUN device's security structure.
* @security pointer to the TUN devices's security structure. * @security pointer to the TUN devices's security structure.
* *
* Security hooks for SCTP
*
* @sctp_assoc_request:
* Passes the @ep and @chunk->skb of the association INIT packet to
* the security module.
* @ep pointer to sctp endpoint structure.
* @skb pointer to skbuff of association packet.
* Return 0 on success, error on failure.
* @sctp_bind_connect:
* Validiate permissions required for each address associated with sock
* @sk. Depending on @optname, the addresses will be treated as either
* for a connect or bind service. The @addrlen is calculated on each
* ipv4 and ipv6 address using sizeof(struct sockaddr_in) or
* sizeof(struct sockaddr_in6).
* @sk pointer to sock structure.
* @optname name of the option to validate.
* @address list containing one or more ipv4/ipv6 addresses.
* @addrlen total length of address(s).
* Return 0 on success, error on failure.
* @sctp_sk_clone:
* Called whenever a new socket is created by accept(2) (i.e. a TCP
* style socket) or when a socket is 'peeled off' e.g userspace
* calls sctp_peeloff(3).
* @ep pointer to current sctp endpoint structure.
* @sk pointer to current sock structure.
* @sk pointer to new sock structure.
*
* Security hooks for Infiniband * Security hooks for Infiniband
* *
* @ib_pkey_access: * @ib_pkey_access:
...@@ -1665,6 +1692,12 @@ union security_list_options { ...@@ -1665,6 +1692,12 @@ union security_list_options {
int (*tun_dev_attach_queue)(void *security); int (*tun_dev_attach_queue)(void *security);
int (*tun_dev_attach)(struct sock *sk, void *security); int (*tun_dev_attach)(struct sock *sk, void *security);
int (*tun_dev_open)(void *security); int (*tun_dev_open)(void *security);
int (*sctp_assoc_request)(struct sctp_endpoint *ep,
struct sk_buff *skb);
int (*sctp_bind_connect)(struct sock *sk, int optname,
struct sockaddr *address, int addrlen);
void (*sctp_sk_clone)(struct sctp_endpoint *ep, struct sock *sk,
struct sock *newsk);
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND #ifdef CONFIG_SECURITY_INFINIBAND
...@@ -1914,6 +1947,9 @@ struct security_hook_heads { ...@@ -1914,6 +1947,9 @@ struct security_hook_heads {
struct list_head tun_dev_attach_queue; struct list_head tun_dev_attach_queue;
struct list_head tun_dev_attach; struct list_head tun_dev_attach;
struct list_head tun_dev_open; struct list_head tun_dev_open;
struct list_head sctp_assoc_request;
struct list_head sctp_bind_connect;
struct list_head sctp_sk_clone;
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND #ifdef CONFIG_SECURITY_INFINIBAND
struct list_head ib_pkey_access; struct list_head ib_pkey_access;
......
...@@ -112,6 +112,7 @@ struct xfrm_policy; ...@@ -112,6 +112,7 @@ struct xfrm_policy;
struct xfrm_state; struct xfrm_state;
struct xfrm_user_sec_ctx; struct xfrm_user_sec_ctx;
struct seq_file; struct seq_file;
struct sctp_endpoint;
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
extern unsigned long mmap_min_addr; extern unsigned long mmap_min_addr;
...@@ -1226,6 +1227,11 @@ int security_tun_dev_create(void); ...@@ -1226,6 +1227,11 @@ int security_tun_dev_create(void);
int security_tun_dev_attach_queue(void *security); int security_tun_dev_attach_queue(void *security);
int security_tun_dev_attach(struct sock *sk, void *security); int security_tun_dev_attach(struct sock *sk, void *security);
int security_tun_dev_open(void *security); int security_tun_dev_open(void *security);
int security_sctp_assoc_request(struct sctp_endpoint *ep, struct sk_buff *skb);
int security_sctp_bind_connect(struct sock *sk, int optname,
struct sockaddr *address, int addrlen);
void security_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
struct sock *newsk);
#else /* CONFIG_SECURITY_NETWORK */ #else /* CONFIG_SECURITY_NETWORK */
static inline int security_unix_stream_connect(struct sock *sock, static inline int security_unix_stream_connect(struct sock *sock,
...@@ -1418,6 +1424,25 @@ static inline int security_tun_dev_open(void *security) ...@@ -1418,6 +1424,25 @@ static inline int security_tun_dev_open(void *security)
{ {
return 0; return 0;
} }
static inline int security_sctp_assoc_request(struct sctp_endpoint *ep,
struct sk_buff *skb)
{
return 0;
}
static inline int security_sctp_bind_connect(struct sock *sk, int optname,
struct sockaddr *address,
int addrlen)
{
return 0;
}
static inline void security_sctp_sk_clone(struct sctp_endpoint *ep,
struct sock *sk,
struct sock *newsk)
{
}
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND #ifdef CONFIG_SECURITY_INFINIBAND
......
...@@ -432,9 +432,11 @@ static inline int sctp_list_single_entry(struct list_head *head) ...@@ -432,9 +432,11 @@ static inline int sctp_list_single_entry(struct list_head *head)
static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu) static inline int sctp_frag_point(const struct sctp_association *asoc, int pmtu)
{ {
struct sctp_sock *sp = sctp_sk(asoc->base.sk); struct sctp_sock *sp = sctp_sk(asoc->base.sk);
struct sctp_af *af = sp->pf->af;
int frag = pmtu; int frag = pmtu;
frag -= sp->pf->af->net_header_len; frag -= af->ip_options_len(asoc->base.sk);
frag -= af->net_header_len;
frag -= sizeof(struct sctphdr) + sctp_datachk_len(&asoc->stream); frag -= sizeof(struct sctphdr) + sctp_datachk_len(&asoc->stream);
if (asoc->user_frag) if (asoc->user_frag)
......
...@@ -491,6 +491,7 @@ struct sctp_af { ...@@ -491,6 +491,7 @@ struct sctp_af {
void (*ecn_capable)(struct sock *sk); void (*ecn_capable)(struct sock *sk);
__u16 net_header_len; __u16 net_header_len;
int sockaddr_len; int sockaddr_len;
int (*ip_options_len)(struct sock *sk);
sa_family_t sa_family; sa_family_t sa_family;
struct list_head list; struct list_head list;
}; };
...@@ -515,6 +516,7 @@ struct sctp_pf { ...@@ -515,6 +516,7 @@ struct sctp_pf {
int (*addr_to_user)(struct sctp_sock *sk, union sctp_addr *addr); int (*addr_to_user)(struct sctp_sock *sk, union sctp_addr *addr);
void (*to_sk_saddr)(union sctp_addr *, struct sock *sk); void (*to_sk_saddr)(union sctp_addr *, struct sock *sk);
void (*to_sk_daddr)(union sctp_addr *, struct sock *sk); void (*to_sk_daddr)(union sctp_addr *, struct sock *sk);
void (*copy_ip_options)(struct sock *sk, struct sock *newsk);
struct sctp_af *af; struct sctp_af *af;
}; };
...@@ -1320,6 +1322,16 @@ struct sctp_endpoint { ...@@ -1320,6 +1322,16 @@ struct sctp_endpoint {
reconf_enable:1; reconf_enable:1;
__u8 strreset_enable; __u8 strreset_enable;
/* Security identifiers from incoming (INIT). These are set by
* security_sctp_assoc_request(). These will only be used by
* SCTP TCP type sockets and peeled off connections as they
* cause a new socket to be generated. security_sctp_sk_clone()
* will then plug these into the new socket.
*/
u32 secid;
u32 peer_secid;
}; };
/* Recover the outter endpoint structure. */ /* Recover the outter endpoint structure. */
......
...@@ -127,6 +127,7 @@ typedef __s32 sctp_assoc_t; ...@@ -127,6 +127,7 @@ typedef __s32 sctp_assoc_t;
#define SCTP_STREAM_SCHEDULER 123 #define SCTP_STREAM_SCHEDULER 123
#define SCTP_STREAM_SCHEDULER_VALUE 124 #define SCTP_STREAM_SCHEDULER_VALUE 124
#define SCTP_INTERLEAVING_SUPPORTED 125 #define SCTP_INTERLEAVING_SUPPORTED 125
#define SCTP_SENDMSG_CONNECT 126
/* PR-SCTP policies */ /* PR-SCTP policies */
#define SCTP_PR_SCTP_NONE 0x0000 #define SCTP_PR_SCTP_NONE 0x0000
......
...@@ -1472,6 +1472,16 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, ...@@ -1472,6 +1472,16 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
iface = rcu_dereference(netlbl_unlhsh_def); iface = rcu_dereference(netlbl_unlhsh_def);
if (iface == NULL || !iface->valid) if (iface == NULL || !iface->valid)
goto unlabel_getattr_nolabel; goto unlabel_getattr_nolabel;
#if IS_ENABLED(CONFIG_IPV6)
/* When resolving a fallback label, check the sk_buff version as
* it is possible (e.g. SCTP) to have family = PF_INET6 while
* receiving ip_hdr(skb)->version = 4.
*/
if (family == PF_INET6 && ip_hdr(skb)->version == 4)
family = PF_INET;
#endif /* IPv6 */
switch (family) { switch (family) {
case PF_INET: { case PF_INET: {
struct iphdr *hdr4; struct iphdr *hdr4;
......
...@@ -172,6 +172,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -172,6 +172,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
struct list_head *pos, *temp; struct list_head *pos, *temp;
struct sctp_chunk *chunk; struct sctp_chunk *chunk;
struct sctp_datamsg *msg; struct sctp_datamsg *msg;
struct sctp_sock *sp;
struct sctp_af *af;
int err; int err;
msg = sctp_datamsg_new(GFP_KERNEL); msg = sctp_datamsg_new(GFP_KERNEL);
...@@ -190,9 +192,11 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, ...@@ -190,9 +192,11 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
/* This is the biggest possible DATA chunk that can fit into /* This is the biggest possible DATA chunk that can fit into
* the packet * the packet
*/ */
max_data = asoc->pathmtu - sp = sctp_sk(asoc->base.sk);
sctp_sk(asoc->base.sk)->pf->af->net_header_len - af = sp->pf->af;
sizeof(struct sctphdr) - sctp_datachk_len(&asoc->stream); max_data = asoc->pathmtu - af->net_header_len -
sizeof(struct sctphdr) - sctp_datachk_len(&asoc->stream) -
af->ip_options_len(asoc->base.sk);
max_data = SCTP_TRUNC4(max_data); max_data = SCTP_TRUNC4(max_data);
/* If the the peer requested that we authenticate DATA chunks /* If the the peer requested that we authenticate DATA chunks
......
...@@ -427,6 +427,41 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, ...@@ -427,6 +427,41 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
rcu_read_unlock(); rcu_read_unlock();
} }
/* Copy over any ip options */
static void sctp_v6_copy_ip_options(struct sock *sk, struct sock *newsk)
{
struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
struct ipv6_txoptions *opt;
newnp = inet6_sk(newsk);
rcu_read_lock();
opt = rcu_dereference(np->opt);
if (opt) {
opt = ipv6_dup_options(newsk, opt);
if (!opt)
pr_err("%s: Failed to copy ip options\n", __func__);
}
RCU_INIT_POINTER(newnp->opt, opt);
rcu_read_unlock();
}
/* Account for the IP options */
static int sctp_v6_ip_options_len(struct sock *sk)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct ipv6_txoptions *opt;
int len = 0;
rcu_read_lock();
opt = rcu_dereference(np->opt);
if (opt)
len = opt->opt_flen + opt->opt_nflen;
rcu_read_unlock();
return len;
}
/* Initialize a sockaddr_storage from in incoming skb. */ /* Initialize a sockaddr_storage from in incoming skb. */
static void sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb, static void sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr) int is_saddr)
...@@ -666,7 +701,6 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, ...@@ -666,7 +701,6 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
struct sock *newsk; struct sock *newsk;
struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
struct sctp6_sock *newsctp6sk; struct sctp6_sock *newsctp6sk;
struct ipv6_txoptions *opt;
newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, kern); newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, kern);
if (!newsk) if (!newsk)
...@@ -689,12 +723,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, ...@@ -689,12 +723,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
newnp->ipv6_ac_list = NULL; newnp->ipv6_ac_list = NULL;
newnp->ipv6_fl_list = NULL; newnp->ipv6_fl_list = NULL;
rcu_read_lock(); sctp_v6_copy_ip_options(sk, newsk);
opt = rcu_dereference(np->opt);
if (opt)
opt = ipv6_dup_options(newsk, opt);
RCU_INIT_POINTER(newnp->opt, opt);
rcu_read_unlock();
/* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname() /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
* and getpeername(). * and getpeername().
...@@ -1041,6 +1070,7 @@ static struct sctp_af sctp_af_inet6 = { ...@@ -1041,6 +1070,7 @@ static struct sctp_af sctp_af_inet6 = {
.ecn_capable = sctp_v6_ecn_capable, .ecn_capable = sctp_v6_ecn_capable,
.net_header_len = sizeof(struct ipv6hdr), .net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6), .sockaddr_len = sizeof(struct sockaddr_in6),
.ip_options_len = sctp_v6_ip_options_len,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ipv6_setsockopt, .compat_setsockopt = compat_ipv6_setsockopt,
.compat_getsockopt = compat_ipv6_getsockopt, .compat_getsockopt = compat_ipv6_getsockopt,
...@@ -1059,6 +1089,7 @@ static struct sctp_pf sctp_pf_inet6 = { ...@@ -1059,6 +1089,7 @@ static struct sctp_pf sctp_pf_inet6 = {
.addr_to_user = sctp_v6_addr_to_user, .addr_to_user = sctp_v6_addr_to_user,
.to_sk_saddr = sctp_v6_to_sk_saddr, .to_sk_saddr = sctp_v6_to_sk_saddr,
.to_sk_daddr = sctp_v6_to_sk_daddr, .to_sk_daddr = sctp_v6_to_sk_daddr,
.copy_ip_options = sctp_v6_copy_ip_options,
.af = &sctp_af_inet6, .af = &sctp_af_inet6,
}; };
......
...@@ -69,7 +69,11 @@ static enum sctp_xmit sctp_packet_will_fit(struct sctp_packet *packet, ...@@ -69,7 +69,11 @@ static enum sctp_xmit sctp_packet_will_fit(struct sctp_packet *packet,
static void sctp_packet_reset(struct sctp_packet *packet) static void sctp_packet_reset(struct sctp_packet *packet)
{ {
/* sctp_packet_transmit() relies on this to reset size to the
* current overhead after sending packets.
*/
packet->size = packet->overhead; packet->size = packet->overhead;
packet->has_cookie_echo = 0; packet->has_cookie_echo = 0;
packet->has_sack = 0; packet->has_sack = 0;
packet->has_data = 0; packet->has_data = 0;
...@@ -87,6 +91,7 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag, ...@@ -87,6 +91,7 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag,
struct sctp_transport *tp = packet->transport; struct sctp_transport *tp = packet->transport;
struct sctp_association *asoc = tp->asoc; struct sctp_association *asoc = tp->asoc;
struct sock *sk; struct sock *sk;
size_t overhead = sizeof(struct ipv6hdr) + sizeof(struct sctphdr);
pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); pr_debug("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag);
packet->vtag = vtag; packet->vtag = vtag;
...@@ -95,10 +100,22 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag, ...@@ -95,10 +100,22 @@ void sctp_packet_config(struct sctp_packet *packet, __u32 vtag,
if (!sctp_packet_empty(packet)) if (!sctp_packet_empty(packet))
return; return;
/* set packet max_size with pathmtu */ /* set packet max_size with pathmtu, then calculate overhead */
packet->max_size = tp->pathmtu; packet->max_size = tp->pathmtu;
if (!asoc) if (asoc) {
struct sctp_sock *sp = sctp_sk(asoc->base.sk);
struct sctp_af *af = sp->pf->af;
overhead = af->net_header_len +
af->ip_options_len(asoc->base.sk);
overhead += sizeof(struct sctphdr);
packet->overhead = overhead;
packet->size = overhead;
} else {
packet->overhead = overhead;
packet->size = overhead;
return; return;
}
/* update dst or transport pathmtu if in need */ /* update dst or transport pathmtu if in need */
sk = asoc->base.sk; sk = asoc->base.sk;
...@@ -140,23 +157,14 @@ void sctp_packet_init(struct sctp_packet *packet, ...@@ -140,23 +157,14 @@ void sctp_packet_init(struct sctp_packet *packet,
struct sctp_transport *transport, struct sctp_transport *transport,
__u16 sport, __u16 dport) __u16 sport, __u16 dport)
{ {
struct sctp_association *asoc = transport->asoc;
size_t overhead;
pr_debug("%s: packet:%p transport:%p\n", __func__, packet, transport); pr_debug("%s: packet:%p transport:%p\n", __func__, packet, transport);
packet->transport = transport; packet->transport = transport;
packet->source_port = sport; packet->source_port = sport;
packet->destination_port = dport; packet->destination_port = dport;
INIT_LIST_HEAD(&packet->chunk_list); INIT_LIST_HEAD(&packet->chunk_list);
if (asoc) { /* The overhead will be calculated by sctp_packet_config() */
struct sctp_sock *sp = sctp_sk(asoc->base.sk); packet->overhead = 0;
overhead = sp->pf->af->net_header_len;
} else {
overhead = sizeof(struct ipv6hdr);
}
overhead += sizeof(struct sctphdr);
packet->overhead = overhead;
sctp_packet_reset(packet); sctp_packet_reset(packet);
packet->vtag = 0; packet->vtag = 0;
} }
......
...@@ -187,6 +187,45 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp, ...@@ -187,6 +187,45 @@ int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
return error; return error;
} }
/* Copy over any ip options */
static void sctp_v4_copy_ip_options(struct sock *sk, struct sock *newsk)
{
struct inet_sock *newinet, *inet = inet_sk(sk);
struct ip_options_rcu *inet_opt, *newopt = NULL;
newinet = inet_sk(newsk);
rcu_read_lock();
inet_opt = rcu_dereference(inet->inet_opt);
if (inet_opt) {
newopt = sock_kmalloc(newsk, sizeof(*inet_opt) +
inet_opt->opt.optlen, GFP_ATOMIC);
if (newopt)
memcpy(newopt, inet_opt, sizeof(*inet_opt) +
inet_opt->opt.optlen);
else
pr_err("%s: Failed to copy ip options\n", __func__);
}
RCU_INIT_POINTER(newinet->inet_opt, newopt);
rcu_read_unlock();
}
/* Account for the IP options */
static int sctp_v4_ip_options_len(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
struct ip_options_rcu *inet_opt;
int len = 0;
rcu_read_lock();
inet_opt = rcu_dereference(inet->inet_opt);
if (inet_opt)
len = inet_opt->opt.optlen;
rcu_read_unlock();
return len;
}
/* Initialize a sctp_addr from in incoming skb. */ /* Initialize a sctp_addr from in incoming skb. */
static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr) int is_saddr)
...@@ -538,6 +577,8 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, ...@@ -538,6 +577,8 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
sctp_copy_sock(newsk, sk, asoc); sctp_copy_sock(newsk, sk, asoc);
sock_reset_flag(newsk, SOCK_ZAPPED); sock_reset_flag(newsk, SOCK_ZAPPED);
sctp_v4_copy_ip_options(sk, newsk);
newinet = inet_sk(newsk); newinet = inet_sk(newsk);
newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
...@@ -956,6 +997,7 @@ static struct sctp_pf sctp_pf_inet = { ...@@ -956,6 +997,7 @@ static struct sctp_pf sctp_pf_inet = {
.addr_to_user = sctp_v4_addr_to_user, .addr_to_user = sctp_v4_addr_to_user,
.to_sk_saddr = sctp_v4_to_sk_saddr, .to_sk_saddr = sctp_v4_to_sk_saddr,
.to_sk_daddr = sctp_v4_to_sk_daddr, .to_sk_daddr = sctp_v4_to_sk_daddr,
.copy_ip_options = sctp_v4_copy_ip_options,
.af = &sctp_af_inet .af = &sctp_af_inet
}; };
...@@ -1040,6 +1082,7 @@ static struct sctp_af sctp_af_inet = { ...@@ -1040,6 +1082,7 @@ static struct sctp_af sctp_af_inet = {
.ecn_capable = sctp_v4_ecn_capable, .ecn_capable = sctp_v4_ecn_capable,
.net_header_len = sizeof(struct iphdr), .net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in), .sockaddr_len = sizeof(struct sockaddr_in),
.ip_options_len = sctp_v4_ip_options_len,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ip_setsockopt, .compat_setsockopt = compat_ip_setsockopt,
.compat_getsockopt = compat_ip_getsockopt, .compat_getsockopt = compat_ip_getsockopt,
......
...@@ -3098,6 +3098,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, ...@@ -3098,6 +3098,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
if (af->is_any(&addr)) if (af->is_any(&addr))
memcpy(&addr, &asconf->source, sizeof(addr)); memcpy(&addr, &asconf->source, sizeof(addr));
if (security_sctp_bind_connect(asoc->ep->base.sk,
SCTP_PARAM_ADD_IP,
(struct sockaddr *)&addr,
af->sockaddr_len))
return SCTP_ERROR_REQ_REFUSED;
/* ADDIP 4.3 D9) If an endpoint receives an ADD IP address /* ADDIP 4.3 D9) If an endpoint receives an ADD IP address
* request and does not have the local resources to add this * request and does not have the local resources to add this
* new address to the association, it MUST return an Error * new address to the association, it MUST return an Error
...@@ -3164,6 +3170,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, ...@@ -3164,6 +3170,12 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
if (af->is_any(&addr)) if (af->is_any(&addr))
memcpy(&addr.v4, sctp_source(asconf), sizeof(addr)); memcpy(&addr.v4, sctp_source(asconf), sizeof(addr));
if (security_sctp_bind_connect(asoc->ep->base.sk,
SCTP_PARAM_SET_PRIMARY,
(struct sockaddr *)&addr,
af->sockaddr_len))
return SCTP_ERROR_REQ_REFUSED;
peer = sctp_assoc_lookup_paddr(asoc, &addr); peer = sctp_assoc_lookup_paddr(asoc, &addr);
if (!peer) if (!peer)
return SCTP_ERROR_DNS_FAILED; return SCTP_ERROR_DNS_FAILED;
......
...@@ -321,6 +321,11 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net, ...@@ -321,6 +321,11 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net,
struct sctp_packet *packet; struct sctp_packet *packet;
int len; int len;
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_endpoint *)ep,
chunk->skb))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
/* 6.10 Bundling /* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or * An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks. * SHUTDOWN COMPLETE with any other chunks.
...@@ -922,6 +927,9 @@ enum sctp_disposition sctp_sf_do_5_1E_ca(struct net *net, ...@@ -922,6 +927,9 @@ enum sctp_disposition sctp_sf_do_5_1E_ca(struct net *net,
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_RESET, SCTP_NULL()); sctp_add_cmd_sf(commands, SCTP_CMD_INIT_COUNTER_RESET, SCTP_NULL());
/* Set peer label for connection. */
security_inet_conn_established(ep->base.sk, chunk->skb);
/* RFC 2960 5.1 Normal Establishment of an Association /* RFC 2960 5.1 Normal Establishment of an Association
* *
* E) Upon reception of the COOKIE ACK, endpoint "A" will move * E) Upon reception of the COOKIE ACK, endpoint "A" will move
...@@ -1459,6 +1467,11 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( ...@@ -1459,6 +1467,11 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(
struct sctp_packet *packet; struct sctp_packet *packet;
int len; int len;
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_endpoint *)ep,
chunk->skb))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
/* 6.10 Bundling /* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or * An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks. * SHUTDOWN COMPLETE with any other chunks.
...@@ -2145,6 +2158,11 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook( ...@@ -2145,6 +2158,11 @@ enum sctp_disposition sctp_sf_do_5_2_4_dupcook(
} }
} }
/* Update socket peer label if first association. */
if (security_sctp_assoc_request((struct sctp_endpoint *)ep,
chunk->skb))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
/* Set temp so that it won't be added into hashtable */ /* Set temp so that it won't be added into hashtable */
new_asoc->temp = 1; new_asoc->temp = 1;
......
...@@ -1046,6 +1046,12 @@ static int sctp_setsockopt_bindx(struct sock *sk, ...@@ -1046,6 +1046,12 @@ static int sctp_setsockopt_bindx(struct sock *sk,
/* Do the work. */ /* Do the work. */
switch (op) { switch (op) {
case SCTP_BINDX_ADD_ADDR: case SCTP_BINDX_ADD_ADDR:
/* Allow security module to validate bindx addresses. */
err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_BINDX_ADD,
(struct sockaddr *)kaddrs,
addrs_size);
if (err)
goto out;
err = sctp_bindx_add(sk, kaddrs, addrcnt); err = sctp_bindx_add(sk, kaddrs, addrcnt);
if (err) if (err)
goto out; goto out;
...@@ -1255,6 +1261,7 @@ static int __sctp_connect(struct sock *sk, ...@@ -1255,6 +1261,7 @@ static int __sctp_connect(struct sock *sk,
if (assoc_id) if (assoc_id)
*assoc_id = asoc->assoc_id; *assoc_id = asoc->assoc_id;
err = sctp_wait_for_connect(asoc, &timeo); err = sctp_wait_for_connect(asoc, &timeo);
/* Note: the asoc may be freed after the return of /* Note: the asoc may be freed after the return of
* sctp_wait_for_connect. * sctp_wait_for_connect.
...@@ -1350,7 +1357,16 @@ static int __sctp_setsockopt_connectx(struct sock *sk, ...@@ -1350,7 +1357,16 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
if (unlikely(IS_ERR(kaddrs))) if (unlikely(IS_ERR(kaddrs)))
return PTR_ERR(kaddrs); return PTR_ERR(kaddrs);
/* Allow security module to validate connectx addresses. */
err = security_sctp_bind_connect(sk, SCTP_SOCKOPT_CONNECTX,
(struct sockaddr *)kaddrs,
addrs_size);
if (err)
goto out_free;
err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id); err = __sctp_connect(sk, kaddrs, addrs_size, assoc_id);
out_free:
kvfree(kaddrs); kvfree(kaddrs);
return err; return err;
...@@ -1680,6 +1696,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, ...@@ -1680,6 +1696,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
struct sctp_association *asoc; struct sctp_association *asoc;
enum sctp_scope scope; enum sctp_scope scope;
struct cmsghdr *cmsg; struct cmsghdr *cmsg;
struct sctp_af *af;
int err; int err;
*tp = NULL; *tp = NULL;
...@@ -1705,6 +1722,21 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags, ...@@ -1705,6 +1722,21 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
scope = sctp_scope(daddr); scope = sctp_scope(daddr);
/* Label connection socket for first association 1-to-many
* style for client sequence socket()->sendmsg(). This
* needs to be done before sctp_assoc_add_peer() as that will
* set up the initial packet that needs to account for any
* security ip options (CIPSO/CALIPSO) added to the packet.
*/
af = sctp_get_af_specific(daddr->sa.sa_family);
if (!af)
return -EINVAL;
err = security_sctp_bind_connect(sk, SCTP_SENDMSG_CONNECT,
(struct sockaddr *)daddr,
af->sockaddr_len);
if (err < 0)
return err;
asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL); asoc = sctp_association_new(ep, sk, scope, GFP_KERNEL);
if (!asoc) if (!asoc)
return -ENOMEM; return -ENOMEM;
...@@ -2932,6 +2964,8 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, ...@@ -2932,6 +2964,8 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
{ {
struct sctp_prim prim; struct sctp_prim prim;
struct sctp_transport *trans; struct sctp_transport *trans;
struct sctp_af *af;
int err;
if (optlen != sizeof(struct sctp_prim)) if (optlen != sizeof(struct sctp_prim))
return -EINVAL; return -EINVAL;
...@@ -2939,6 +2973,17 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval, ...@@ -2939,6 +2973,17 @@ static int sctp_setsockopt_primary_addr(struct sock *sk, char __user *optval,
if (copy_from_user(&prim, optval, sizeof(struct sctp_prim))) if (copy_from_user(&prim, optval, sizeof(struct sctp_prim)))
return -EFAULT; return -EFAULT;
/* Allow security module to validate address but need address len. */
af = sctp_get_af_specific(prim.ssp_addr.ss_family);
if (!af)
return -EINVAL;
err = security_sctp_bind_connect(sk, SCTP_PRIMARY_ADDR,
(struct sockaddr *)&prim.ssp_addr,
af->sockaddr_len);
if (err)
return err;
trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id); trans = sctp_addr_id2transport(sk, &prim.ssp_addr, prim.ssp_assoc_id);
if (!trans) if (!trans)
return -EINVAL; return -EINVAL;
...@@ -3161,6 +3206,7 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign ...@@ -3161,6 +3206,7 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, unsign
static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen) static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned int optlen)
{ {
struct sctp_sock *sp = sctp_sk(sk); struct sctp_sock *sp = sctp_sk(sk);
struct sctp_af *af = sp->pf->af;
struct sctp_assoc_value params; struct sctp_assoc_value params;
struct sctp_association *asoc; struct sctp_association *asoc;
int val; int val;
...@@ -3185,7 +3231,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned ...@@ -3185,7 +3231,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
if (val) { if (val) {
int min_len, max_len; int min_len, max_len;
min_len = SCTP_DEFAULT_MINSEGMENT - sp->pf->af->net_header_len; min_len = SCTP_DEFAULT_MINSEGMENT - af->net_header_len;
min_len -= af->ip_options_len(sk);
min_len -= sizeof(struct sctphdr) + min_len -= sizeof(struct sctphdr) +
sizeof(struct sctp_data_chunk); sizeof(struct sctp_data_chunk);
...@@ -3198,7 +3245,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned ...@@ -3198,7 +3245,8 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
asoc = sctp_id2assoc(sk, params.assoc_id); asoc = sctp_id2assoc(sk, params.assoc_id);
if (asoc) { if (asoc) {
if (val == 0) { if (val == 0) {
val = asoc->pathmtu - sp->pf->af->net_header_len; val = asoc->pathmtu - af->net_header_len;
val -= af->ip_options_len(sk);
val -= sizeof(struct sctphdr) + val -= sizeof(struct sctphdr) +
sctp_datachk_len(&asoc->stream); sctp_datachk_len(&asoc->stream);
} }
...@@ -3267,6 +3315,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva ...@@ -3267,6 +3315,13 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr)) if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
return -EADDRNOTAVAIL; return -EADDRNOTAVAIL;
/* Allow security module to validate address. */
err = security_sctp_bind_connect(sk, SCTP_SET_PEER_PRIMARY_ADDR,
(struct sockaddr *)&prim.sspp_addr,
af->sockaddr_len);
if (err)
return err;
/* Create an ASCONF chunk with SET_PRIMARY parameter */ /* Create an ASCONF chunk with SET_PRIMARY parameter */
chunk = sctp_make_asconf_set_prim(asoc, chunk = sctp_make_asconf_set_prim(asoc,
(union sctp_addr *)&prim.sspp_addr); (union sctp_addr *)&prim.sspp_addr);
...@@ -5140,9 +5195,11 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp) ...@@ -5140,9 +5195,11 @@ int sctp_do_peeloff(struct sock *sk, sctp_assoc_t id, struct socket **sockp)
sctp_copy_sock(sock->sk, sk, asoc); sctp_copy_sock(sock->sk, sk, asoc);
/* Make peeled-off sockets more like 1-1 accepted sockets. /* Make peeled-off sockets more like 1-1 accepted sockets.
* Set the daddr and initialize id to something more random * Set the daddr and initialize id to something more random and also
* copy over any ip options.
*/ */
sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk); sp->pf->to_sk_daddr(&asoc->peer.primary_addr, sk);
sp->pf->copy_ip_options(sk, sock->sk);
/* Populate the fields of the newsk from the oldsk and migrate the /* Populate the fields of the newsk from the oldsk and migrate the
* asoc to the newsk. * asoc to the newsk.
...@@ -8465,6 +8522,8 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, ...@@ -8465,6 +8522,8 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
{ {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
struct inet_sock *newinet; struct inet_sock *newinet;
struct sctp_sock *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep;
newsk->sk_type = sk->sk_type; newsk->sk_type = sk->sk_type;
newsk->sk_bound_dev_if = sk->sk_bound_dev_if; newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
...@@ -8507,7 +8566,10 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk, ...@@ -8507,7 +8566,10 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
if (newsk->sk_flags & SK_FLAGS_TIMESTAMP) if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
net_enable_timestamp(); net_enable_timestamp();
security_sk_clone(sk, newsk); /* Set newsk security attributes from orginal sk and connection
* security attribute from ep.
*/
security_sctp_sk_clone(ep, sk, newsk);
} }
static inline void sctp_copy_descendant(struct sock *sk_to, static inline void sctp_copy_descendant(struct sock *sk_to,
......
...@@ -1473,6 +1473,7 @@ void security_inet_conn_established(struct sock *sk, ...@@ -1473,6 +1473,7 @@ void security_inet_conn_established(struct sock *sk,
{ {
call_void_hook(inet_conn_established, sk, skb); call_void_hook(inet_conn_established, sk, skb);
} }
EXPORT_SYMBOL(security_inet_conn_established);
int security_secmark_relabel_packet(u32 secid) int security_secmark_relabel_packet(u32 secid)
{ {
...@@ -1528,6 +1529,27 @@ int security_tun_dev_open(void *security) ...@@ -1528,6 +1529,27 @@ int security_tun_dev_open(void *security)
} }
EXPORT_SYMBOL(security_tun_dev_open); EXPORT_SYMBOL(security_tun_dev_open);
int security_sctp_assoc_request(struct sctp_endpoint *ep, struct sk_buff *skb)
{
return call_int_hook(sctp_assoc_request, 0, ep, skb);
}
EXPORT_SYMBOL(security_sctp_assoc_request);
int security_sctp_bind_connect(struct sock *sk, int optname,
struct sockaddr *address, int addrlen)
{
return call_int_hook(sctp_bind_connect, 0, sk, optname,
address, addrlen);
}
EXPORT_SYMBOL(security_sctp_bind_connect);
void security_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
struct sock *newsk)
{
call_void_hook(sctp_sk_clone, ep, sk, newsk);
}
EXPORT_SYMBOL(security_sctp_sk_clone);
#endif /* CONFIG_SECURITY_NETWORK */ #endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_INFINIBAND #ifdef CONFIG_SECURITY_INFINIBAND
......
...@@ -82,14 +82,42 @@ struct avc_callback_node { ...@@ -82,14 +82,42 @@ struct avc_callback_node {
struct avc_callback_node *next; struct avc_callback_node *next;
}; };
/* Exported via selinufs */
unsigned int avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS #ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
#endif #endif
static struct avc_cache avc_cache; struct selinux_avc {
unsigned int avc_cache_threshold;
struct avc_cache avc_cache;
};
static struct selinux_avc selinux_avc;
void selinux_avc_init(struct selinux_avc **avc)
{
int i;
selinux_avc.avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
INIT_HLIST_HEAD(&selinux_avc.avc_cache.slots[i]);
spin_lock_init(&selinux_avc.avc_cache.slots_lock[i]);
}
atomic_set(&selinux_avc.avc_cache.active_nodes, 0);
atomic_set(&selinux_avc.avc_cache.lru_hint, 0);
*avc = &selinux_avc;
}
unsigned int avc_get_cache_threshold(struct selinux_avc *avc)
{
return avc->avc_cache_threshold;
}
void avc_set_cache_threshold(struct selinux_avc *avc,
unsigned int cache_threshold)
{
avc->avc_cache_threshold = cache_threshold;
}
static struct avc_callback_node *avc_callbacks; static struct avc_callback_node *avc_callbacks;
static struct kmem_cache *avc_node_cachep; static struct kmem_cache *avc_node_cachep;
static struct kmem_cache *avc_xperms_data_cachep; static struct kmem_cache *avc_xperms_data_cachep;
...@@ -143,13 +171,14 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) ...@@ -143,13 +171,14 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
* @tsid: target security identifier * @tsid: target security identifier
* @tclass: target security class * @tclass: target security class
*/ */
static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tclass) static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass)
{ {
int rc; int rc;
char *scontext; char *scontext;
u32 scontext_len; u32 scontext_len;
rc = security_sid_to_context(ssid, &scontext, &scontext_len); rc = security_sid_to_context(state, ssid, &scontext, &scontext_len);
if (rc) if (rc)
audit_log_format(ab, "ssid=%d", ssid); audit_log_format(ab, "ssid=%d", ssid);
else { else {
...@@ -157,7 +186,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla ...@@ -157,7 +186,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla
kfree(scontext); kfree(scontext);
} }
rc = security_sid_to_context(tsid, &scontext, &scontext_len); rc = security_sid_to_context(state, tsid, &scontext, &scontext_len);
if (rc) if (rc)
audit_log_format(ab, " tsid=%d", tsid); audit_log_format(ab, " tsid=%d", tsid);
else { else {
...@@ -176,15 +205,6 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla ...@@ -176,15 +205,6 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla
*/ */
void __init avc_init(void) void __init avc_init(void)
{ {
int i;
for (i = 0; i < AVC_CACHE_SLOTS; i++) {
INIT_HLIST_HEAD(&avc_cache.slots[i]);
spin_lock_init(&avc_cache.slots_lock[i]);
}
atomic_set(&avc_cache.active_nodes, 0);
atomic_set(&avc_cache.lru_hint, 0);
avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
avc_xperms_cachep = kmem_cache_create("avc_xperms_node", avc_xperms_cachep = kmem_cache_create("avc_xperms_node",
...@@ -199,7 +219,7 @@ void __init avc_init(void) ...@@ -199,7 +219,7 @@ void __init avc_init(void)
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
} }
int avc_get_hash_stats(char *page) int avc_get_hash_stats(struct selinux_avc *avc, char *page)
{ {
int i, chain_len, max_chain_len, slots_used; int i, chain_len, max_chain_len, slots_used;
struct avc_node *node; struct avc_node *node;
...@@ -210,7 +230,7 @@ int avc_get_hash_stats(char *page) ...@@ -210,7 +230,7 @@ int avc_get_hash_stats(char *page)
slots_used = 0; slots_used = 0;
max_chain_len = 0; max_chain_len = 0;
for (i = 0; i < AVC_CACHE_SLOTS; i++) { for (i = 0; i < AVC_CACHE_SLOTS; i++) {
head = &avc_cache.slots[i]; head = &avc->avc_cache.slots[i];
if (!hlist_empty(head)) { if (!hlist_empty(head)) {
slots_used++; slots_used++;
chain_len = 0; chain_len = 0;
...@@ -225,7 +245,7 @@ int avc_get_hash_stats(char *page) ...@@ -225,7 +245,7 @@ int avc_get_hash_stats(char *page)
return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n" return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
"longest chain: %d\n", "longest chain: %d\n",
atomic_read(&avc_cache.active_nodes), atomic_read(&avc->avc_cache.active_nodes),
slots_used, AVC_CACHE_SLOTS, max_chain_len); slots_used, AVC_CACHE_SLOTS, max_chain_len);
} }
...@@ -462,11 +482,12 @@ static inline u32 avc_xperms_audit_required(u32 requested, ...@@ -462,11 +482,12 @@ static inline u32 avc_xperms_audit_required(u32 requested,
return audited; return audited;
} }
static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, static inline int avc_xperms_audit(struct selinux_state *state,
u32 requested, struct av_decision *avd, u32 ssid, u32 tsid, u16 tclass,
struct extended_perms_decision *xpd, u32 requested, struct av_decision *avd,
u8 perm, int result, struct extended_perms_decision *xpd,
struct common_audit_data *ad) u8 perm, int result,
struct common_audit_data *ad)
{ {
u32 audited, denied; u32 audited, denied;
...@@ -474,7 +495,7 @@ static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, ...@@ -474,7 +495,7 @@ static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass,
requested, avd, xpd, perm, result, &denied); requested, avd, xpd, perm, result, &denied);
if (likely(!audited)) if (likely(!audited))
return 0; return 0;
return slow_avc_audit(ssid, tsid, tclass, requested, return slow_avc_audit(state, ssid, tsid, tclass, requested,
audited, denied, result, ad, 0); audited, denied, result, ad, 0);
} }
...@@ -486,29 +507,30 @@ static void avc_node_free(struct rcu_head *rhead) ...@@ -486,29 +507,30 @@ static void avc_node_free(struct rcu_head *rhead)
avc_cache_stats_incr(frees); avc_cache_stats_incr(frees);
} }
static void avc_node_delete(struct avc_node *node) static void avc_node_delete(struct selinux_avc *avc, struct avc_node *node)
{ {
hlist_del_rcu(&node->list); hlist_del_rcu(&node->list);
call_rcu(&node->rhead, avc_node_free); call_rcu(&node->rhead, avc_node_free);
atomic_dec(&avc_cache.active_nodes); atomic_dec(&avc->avc_cache.active_nodes);
} }
static void avc_node_kill(struct avc_node *node) static void avc_node_kill(struct selinux_avc *avc, struct avc_node *node)
{ {
avc_xperms_free(node->ae.xp_node); avc_xperms_free(node->ae.xp_node);
kmem_cache_free(avc_node_cachep, node); kmem_cache_free(avc_node_cachep, node);
avc_cache_stats_incr(frees); avc_cache_stats_incr(frees);
atomic_dec(&avc_cache.active_nodes); atomic_dec(&avc->avc_cache.active_nodes);
} }
static void avc_node_replace(struct avc_node *new, struct avc_node *old) static void avc_node_replace(struct selinux_avc *avc,
struct avc_node *new, struct avc_node *old)
{ {
hlist_replace_rcu(&old->list, &new->list); hlist_replace_rcu(&old->list, &new->list);
call_rcu(&old->rhead, avc_node_free); call_rcu(&old->rhead, avc_node_free);
atomic_dec(&avc_cache.active_nodes); atomic_dec(&avc->avc_cache.active_nodes);
} }
static inline int avc_reclaim_node(void) static inline int avc_reclaim_node(struct selinux_avc *avc)
{ {
struct avc_node *node; struct avc_node *node;
int hvalue, try, ecx; int hvalue, try, ecx;
...@@ -517,16 +539,17 @@ static inline int avc_reclaim_node(void) ...@@ -517,16 +539,17 @@ static inline int avc_reclaim_node(void)
spinlock_t *lock; spinlock_t *lock;
for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) { for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) {
hvalue = atomic_inc_return(&avc_cache.lru_hint) & (AVC_CACHE_SLOTS - 1); hvalue = atomic_inc_return(&avc->avc_cache.lru_hint) &
head = &avc_cache.slots[hvalue]; (AVC_CACHE_SLOTS - 1);
lock = &avc_cache.slots_lock[hvalue]; head = &avc->avc_cache.slots[hvalue];
lock = &avc->avc_cache.slots_lock[hvalue];
if (!spin_trylock_irqsave(lock, flags)) if (!spin_trylock_irqsave(lock, flags))
continue; continue;
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry(node, head, list) { hlist_for_each_entry(node, head, list) {
avc_node_delete(node); avc_node_delete(avc, node);
avc_cache_stats_incr(reclaims); avc_cache_stats_incr(reclaims);
ecx++; ecx++;
if (ecx >= AVC_CACHE_RECLAIM) { if (ecx >= AVC_CACHE_RECLAIM) {
...@@ -542,7 +565,7 @@ static inline int avc_reclaim_node(void) ...@@ -542,7 +565,7 @@ static inline int avc_reclaim_node(void)
return ecx; return ecx;
} }
static struct avc_node *avc_alloc_node(void) static struct avc_node *avc_alloc_node(struct selinux_avc *avc)
{ {
struct avc_node *node; struct avc_node *node;
...@@ -553,8 +576,9 @@ static struct avc_node *avc_alloc_node(void) ...@@ -553,8 +576,9 @@ static struct avc_node *avc_alloc_node(void)
INIT_HLIST_NODE(&node->list); INIT_HLIST_NODE(&node->list);
avc_cache_stats_incr(allocations); avc_cache_stats_incr(allocations);
if (atomic_inc_return(&avc_cache.active_nodes) > avc_cache_threshold) if (atomic_inc_return(&avc->avc_cache.active_nodes) >
avc_reclaim_node(); avc->avc_cache_threshold)
avc_reclaim_node(avc);
out: out:
return node; return node;
...@@ -568,14 +592,15 @@ static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tcl ...@@ -568,14 +592,15 @@ static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tcl
memcpy(&node->ae.avd, avd, sizeof(node->ae.avd)); memcpy(&node->ae.avd, avd, sizeof(node->ae.avd));
} }
static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) static inline struct avc_node *avc_search_node(struct selinux_avc *avc,
u32 ssid, u32 tsid, u16 tclass)
{ {
struct avc_node *node, *ret = NULL; struct avc_node *node, *ret = NULL;
int hvalue; int hvalue;
struct hlist_head *head; struct hlist_head *head;
hvalue = avc_hash(ssid, tsid, tclass); hvalue = avc_hash(ssid, tsid, tclass);
head = &avc_cache.slots[hvalue]; head = &avc->avc_cache.slots[hvalue];
hlist_for_each_entry_rcu(node, head, list) { hlist_for_each_entry_rcu(node, head, list) {
if (ssid == node->ae.ssid && if (ssid == node->ae.ssid &&
tclass == node->ae.tclass && tclass == node->ae.tclass &&
...@@ -600,12 +625,13 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass) ...@@ -600,12 +625,13 @@ static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
* then this function returns the avc_node. * then this function returns the avc_node.
* Otherwise, this function returns NULL. * Otherwise, this function returns NULL.
*/ */
static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) static struct avc_node *avc_lookup(struct selinux_avc *avc,
u32 ssid, u32 tsid, u16 tclass)
{ {
struct avc_node *node; struct avc_node *node;
avc_cache_stats_incr(lookups); avc_cache_stats_incr(lookups);
node = avc_search_node(ssid, tsid, tclass); node = avc_search_node(avc, ssid, tsid, tclass);
if (node) if (node)
return node; return node;
...@@ -614,7 +640,8 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass) ...@@ -614,7 +640,8 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
return NULL; return NULL;
} }
static int avc_latest_notif_update(int seqno, int is_insert) static int avc_latest_notif_update(struct selinux_avc *avc,
int seqno, int is_insert)
{ {
int ret = 0; int ret = 0;
static DEFINE_SPINLOCK(notif_lock); static DEFINE_SPINLOCK(notif_lock);
...@@ -622,14 +649,14 @@ static int avc_latest_notif_update(int seqno, int is_insert) ...@@ -622,14 +649,14 @@ static int avc_latest_notif_update(int seqno, int is_insert)
spin_lock_irqsave(&notif_lock, flag); spin_lock_irqsave(&notif_lock, flag);
if (is_insert) { if (is_insert) {
if (seqno < avc_cache.latest_notif) { if (seqno < avc->avc_cache.latest_notif) {
printk(KERN_WARNING "SELinux: avc: seqno %d < latest_notif %d\n", printk(KERN_WARNING "SELinux: avc: seqno %d < latest_notif %d\n",
seqno, avc_cache.latest_notif); seqno, avc->avc_cache.latest_notif);
ret = -EAGAIN; ret = -EAGAIN;
} }
} else { } else {
if (seqno > avc_cache.latest_notif) if (seqno > avc->avc_cache.latest_notif)
avc_cache.latest_notif = seqno; avc->avc_cache.latest_notif = seqno;
} }
spin_unlock_irqrestore(&notif_lock, flag); spin_unlock_irqrestore(&notif_lock, flag);
...@@ -654,18 +681,19 @@ static int avc_latest_notif_update(int seqno, int is_insert) ...@@ -654,18 +681,19 @@ static int avc_latest_notif_update(int seqno, int is_insert)
* the access vectors into a cache entry, returns * the access vectors into a cache entry, returns
* avc_node inserted. Otherwise, this function returns NULL. * avc_node inserted. Otherwise, this function returns NULL.
*/ */
static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, static struct avc_node *avc_insert(struct selinux_avc *avc,
struct av_decision *avd, u32 ssid, u32 tsid, u16 tclass,
struct avc_xperms_node *xp_node) struct av_decision *avd,
struct avc_xperms_node *xp_node)
{ {
struct avc_node *pos, *node = NULL; struct avc_node *pos, *node = NULL;
int hvalue; int hvalue;
unsigned long flag; unsigned long flag;
if (avc_latest_notif_update(avd->seqno, 1)) if (avc_latest_notif_update(avc, avd->seqno, 1))
goto out; goto out;
node = avc_alloc_node(); node = avc_alloc_node(avc);
if (node) { if (node) {
struct hlist_head *head; struct hlist_head *head;
spinlock_t *lock; spinlock_t *lock;
...@@ -678,15 +706,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, ...@@ -678,15 +706,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass,
kmem_cache_free(avc_node_cachep, node); kmem_cache_free(avc_node_cachep, node);
return NULL; return NULL;
} }
head = &avc_cache.slots[hvalue]; head = &avc->avc_cache.slots[hvalue];
lock = &avc_cache.slots_lock[hvalue]; lock = &avc->avc_cache.slots_lock[hvalue];
spin_lock_irqsave(lock, flag); spin_lock_irqsave(lock, flag);
hlist_for_each_entry(pos, head, list) { hlist_for_each_entry(pos, head, list) {
if (pos->ae.ssid == ssid && if (pos->ae.ssid == ssid &&
pos->ae.tsid == tsid && pos->ae.tsid == tsid &&
pos->ae.tclass == tclass) { pos->ae.tclass == tclass) {
avc_node_replace(node, pos); avc_node_replace(avc, node, pos);
goto found; goto found;
} }
} }
...@@ -724,9 +752,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) ...@@ -724,9 +752,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
{ {
struct common_audit_data *ad = a; struct common_audit_data *ad = a;
audit_log_format(ab, " "); audit_log_format(ab, " ");
avc_dump_query(ab, ad->selinux_audit_data->ssid, avc_dump_query(ab, ad->selinux_audit_data->state,
ad->selinux_audit_data->tsid, ad->selinux_audit_data->ssid,
ad->selinux_audit_data->tclass); ad->selinux_audit_data->tsid,
ad->selinux_audit_data->tclass);
if (ad->selinux_audit_data->denied) { if (ad->selinux_audit_data->denied) {
audit_log_format(ab, " permissive=%u", audit_log_format(ab, " permissive=%u",
ad->selinux_audit_data->result ? 0 : 1); ad->selinux_audit_data->result ? 0 : 1);
...@@ -734,10 +763,11 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) ...@@ -734,10 +763,11 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
} }
/* This is the slow part of avc audit with big stack footprint */ /* This is the slow part of avc audit with big stack footprint */
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, noinline int slow_avc_audit(struct selinux_state *state,
u32 requested, u32 audited, u32 denied, int result, u32 ssid, u32 tsid, u16 tclass,
struct common_audit_data *a, u32 requested, u32 audited, u32 denied, int result,
unsigned flags) struct common_audit_data *a,
unsigned int flags)
{ {
struct common_audit_data stack_data; struct common_audit_data stack_data;
struct selinux_audit_data sad; struct selinux_audit_data sad;
...@@ -765,6 +795,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, ...@@ -765,6 +795,7 @@ noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
sad.audited = audited; sad.audited = audited;
sad.denied = denied; sad.denied = denied;
sad.result = result; sad.result = result;
sad.state = state;
a->selinux_audit_data = &sad; a->selinux_audit_data = &sad;
...@@ -813,10 +844,11 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events) ...@@ -813,10 +844,11 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
* otherwise, this function updates the AVC entry. The original AVC-entry object * otherwise, this function updates the AVC entry. The original AVC-entry object
* will release later by RCU. * will release later by RCU.
*/ */
static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, static int avc_update_node(struct selinux_avc *avc,
u32 tsid, u16 tclass, u32 seqno, u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
struct extended_perms_decision *xpd, u32 tsid, u16 tclass, u32 seqno,
u32 flags) struct extended_perms_decision *xpd,
u32 flags)
{ {
int hvalue, rc = 0; int hvalue, rc = 0;
unsigned long flag; unsigned long flag;
...@@ -824,7 +856,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, ...@@ -824,7 +856,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
struct hlist_head *head; struct hlist_head *head;
spinlock_t *lock; spinlock_t *lock;
node = avc_alloc_node(); node = avc_alloc_node(avc);
if (!node) { if (!node) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
...@@ -833,8 +865,8 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, ...@@ -833,8 +865,8 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
/* Lock the target slot */ /* Lock the target slot */
hvalue = avc_hash(ssid, tsid, tclass); hvalue = avc_hash(ssid, tsid, tclass);
head = &avc_cache.slots[hvalue]; head = &avc->avc_cache.slots[hvalue];
lock = &avc_cache.slots_lock[hvalue]; lock = &avc->avc_cache.slots_lock[hvalue];
spin_lock_irqsave(lock, flag); spin_lock_irqsave(lock, flag);
...@@ -850,7 +882,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, ...@@ -850,7 +882,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
if (!orig) { if (!orig) {
rc = -ENOENT; rc = -ENOENT;
avc_node_kill(node); avc_node_kill(avc, node);
goto out_unlock; goto out_unlock;
} }
...@@ -894,7 +926,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, ...@@ -894,7 +926,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
avc_add_xperms_decision(node, xpd); avc_add_xperms_decision(node, xpd);
break; break;
} }
avc_node_replace(node, orig); avc_node_replace(avc, node, orig);
out_unlock: out_unlock:
spin_unlock_irqrestore(lock, flag); spin_unlock_irqrestore(lock, flag);
out: out:
...@@ -904,7 +936,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, ...@@ -904,7 +936,7 @@ static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
/** /**
* avc_flush - Flush the cache * avc_flush - Flush the cache
*/ */
static void avc_flush(void) static void avc_flush(struct selinux_avc *avc)
{ {
struct hlist_head *head; struct hlist_head *head;
struct avc_node *node; struct avc_node *node;
...@@ -913,8 +945,8 @@ static void avc_flush(void) ...@@ -913,8 +945,8 @@ static void avc_flush(void)
int i; int i;
for (i = 0; i < AVC_CACHE_SLOTS; i++) { for (i = 0; i < AVC_CACHE_SLOTS; i++) {
head = &avc_cache.slots[i]; head = &avc->avc_cache.slots[i];
lock = &avc_cache.slots_lock[i]; lock = &avc->avc_cache.slots_lock[i];
spin_lock_irqsave(lock, flag); spin_lock_irqsave(lock, flag);
/* /*
...@@ -923,7 +955,7 @@ static void avc_flush(void) ...@@ -923,7 +955,7 @@ static void avc_flush(void)
*/ */
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry(node, head, list) hlist_for_each_entry(node, head, list)
avc_node_delete(node); avc_node_delete(avc, node);
rcu_read_unlock(); rcu_read_unlock();
spin_unlock_irqrestore(lock, flag); spin_unlock_irqrestore(lock, flag);
} }
...@@ -933,12 +965,12 @@ static void avc_flush(void) ...@@ -933,12 +965,12 @@ static void avc_flush(void)
* avc_ss_reset - Flush the cache and revalidate migrated permissions. * avc_ss_reset - Flush the cache and revalidate migrated permissions.
* @seqno: policy sequence number * @seqno: policy sequence number
*/ */
int avc_ss_reset(u32 seqno) int avc_ss_reset(struct selinux_avc *avc, u32 seqno)
{ {
struct avc_callback_node *c; struct avc_callback_node *c;
int rc = 0, tmprc; int rc = 0, tmprc;
avc_flush(); avc_flush(avc);
for (c = avc_callbacks; c; c = c->next) { for (c = avc_callbacks; c; c = c->next) {
if (c->events & AVC_CALLBACK_RESET) { if (c->events & AVC_CALLBACK_RESET) {
...@@ -950,7 +982,7 @@ int avc_ss_reset(u32 seqno) ...@@ -950,7 +982,7 @@ int avc_ss_reset(u32 seqno)
} }
} }
avc_latest_notif_update(seqno, 0); avc_latest_notif_update(avc, seqno, 0);
return rc; return rc;
} }
...@@ -963,30 +995,34 @@ int avc_ss_reset(u32 seqno) ...@@ -963,30 +995,34 @@ int avc_ss_reset(u32 seqno)
* Don't inline this, since it's the slow-path and just * Don't inline this, since it's the slow-path and just
* results in a bigger stack frame. * results in a bigger stack frame.
*/ */
static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, static noinline
u16 tclass, struct av_decision *avd, struct avc_node *avc_compute_av(struct selinux_state *state,
struct avc_xperms_node *xp_node) u32 ssid, u32 tsid,
u16 tclass, struct av_decision *avd,
struct avc_xperms_node *xp_node)
{ {
rcu_read_unlock(); rcu_read_unlock();
INIT_LIST_HEAD(&xp_node->xpd_head); INIT_LIST_HEAD(&xp_node->xpd_head);
security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); security_compute_av(state, ssid, tsid, tclass, avd, &xp_node->xp);
rcu_read_lock(); rcu_read_lock();
return avc_insert(ssid, tsid, tclass, avd, xp_node); return avc_insert(state->avc, ssid, tsid, tclass, avd, xp_node);
} }
static noinline int avc_denied(u32 ssid, u32 tsid, static noinline int avc_denied(struct selinux_state *state,
u16 tclass, u32 requested, u32 ssid, u32 tsid,
u8 driver, u8 xperm, unsigned flags, u16 tclass, u32 requested,
struct av_decision *avd) u8 driver, u8 xperm, unsigned int flags,
struct av_decision *avd)
{ {
if (flags & AVC_STRICT) if (flags & AVC_STRICT)
return -EACCES; return -EACCES;
if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) if (enforcing_enabled(state) &&
!(avd->flags & AVD_FLAGS_PERMISSIVE))
return -EACCES; return -EACCES;
avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, avc_update_node(state->avc, AVC_CALLBACK_GRANT, requested, driver,
tsid, tclass, avd->seqno, NULL, flags); xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);
return 0; return 0;
} }
...@@ -997,8 +1033,9 @@ static noinline int avc_denied(u32 ssid, u32 tsid, ...@@ -997,8 +1033,9 @@ static noinline int avc_denied(u32 ssid, u32 tsid,
* as-is the case with ioctls, then multiple may be chained together and the * as-is the case with ioctls, then multiple may be chained together and the
* driver field is used to specify which set contains the permission. * driver field is used to specify which set contains the permission.
*/ */
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, int avc_has_extended_perms(struct selinux_state *state,
u8 driver, u8 xperm, struct common_audit_data *ad) u32 ssid, u32 tsid, u16 tclass, u32 requested,
u8 driver, u8 xperm, struct common_audit_data *ad)
{ {
struct avc_node *node; struct avc_node *node;
struct av_decision avd; struct av_decision avd;
...@@ -1017,9 +1054,9 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, ...@@ -1017,9 +1054,9 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
rcu_read_lock(); rcu_read_lock();
node = avc_lookup(ssid, tsid, tclass); node = avc_lookup(state->avc, ssid, tsid, tclass);
if (unlikely(!node)) { if (unlikely(!node)) {
node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node); node = avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node);
} else { } else {
memcpy(&avd, &node->ae.avd, sizeof(avd)); memcpy(&avd, &node->ae.avd, sizeof(avd));
xp_node = node->ae.xp_node; xp_node = node->ae.xp_node;
...@@ -1043,11 +1080,12 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, ...@@ -1043,11 +1080,12 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
goto decision; goto decision;
} }
rcu_read_unlock(); rcu_read_unlock();
security_compute_xperms_decision(ssid, tsid, tclass, driver, security_compute_xperms_decision(state, ssid, tsid, tclass,
&local_xpd); driver, &local_xpd);
rcu_read_lock(); rcu_read_lock();
avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, avc_update_node(state->avc, AVC_CALLBACK_ADD_XPERMS, requested,
ssid, tsid, tclass, avd.seqno, &local_xpd, 0); driver, xperm, ssid, tsid, tclass, avd.seqno,
&local_xpd, 0);
} else { } else {
avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd);
} }
...@@ -1059,12 +1097,12 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, ...@@ -1059,12 +1097,12 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
decision: decision:
denied = requested & ~(avd.allowed); denied = requested & ~(avd.allowed);
if (unlikely(denied)) if (unlikely(denied))
rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, rc = avc_denied(state, ssid, tsid, tclass, requested,
AVC_EXTENDED_PERMS, &avd); driver, xperm, AVC_EXTENDED_PERMS, &avd);
rcu_read_unlock(); rcu_read_unlock();
rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, rc2 = avc_xperms_audit(state, ssid, tsid, tclass, requested,
&avd, xpd, xperm, rc, ad); &avd, xpd, xperm, rc, ad);
if (rc2) if (rc2)
return rc2; return rc2;
...@@ -1091,10 +1129,11 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, ...@@ -1091,10 +1129,11 @@ int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
* auditing, e.g. in cases where a lock must be held for the check but * auditing, e.g. in cases where a lock must be held for the check but
* should be released for the auditing. * should be released for the auditing.
*/ */
inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, inline int avc_has_perm_noaudit(struct selinux_state *state,
u16 tclass, u32 requested, u32 ssid, u32 tsid,
unsigned flags, u16 tclass, u32 requested,
struct av_decision *avd) unsigned int flags,
struct av_decision *avd)
{ {
struct avc_node *node; struct avc_node *node;
struct avc_xperms_node xp_node; struct avc_xperms_node xp_node;
...@@ -1105,15 +1144,16 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, ...@@ -1105,15 +1144,16 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
rcu_read_lock(); rcu_read_lock();
node = avc_lookup(ssid, tsid, tclass); node = avc_lookup(state->avc, ssid, tsid, tclass);
if (unlikely(!node)) if (unlikely(!node))
node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node); node = avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node);
else else
memcpy(avd, &node->ae.avd, sizeof(*avd)); memcpy(avd, &node->ae.avd, sizeof(*avd));
denied = requested & ~(avd->allowed); denied = requested & ~(avd->allowed);
if (unlikely(denied)) if (unlikely(denied))
rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd); rc = avc_denied(state, ssid, tsid, tclass, requested, 0, 0,
flags, avd);
rcu_read_unlock(); rcu_read_unlock();
return rc; return rc;
...@@ -1135,39 +1175,43 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, ...@@ -1135,39 +1175,43 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
* permissions are granted, -%EACCES if any permissions are denied, or * permissions are granted, -%EACCES if any permissions are denied, or
* another -errno upon other errors. * another -errno upon other errors.
*/ */
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct common_audit_data *auditdata) u32 requested, struct common_audit_data *auditdata)
{ {
struct av_decision avd; struct av_decision avd;
int rc, rc2; int rc, rc2;
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
&avd);
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, 0); rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
auditdata, 0);
if (rc2) if (rc2)
return rc2; return rc2;
return rc; return rc;
} }
int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass, int avc_has_perm_flags(struct selinux_state *state,
u32 requested, struct common_audit_data *auditdata, u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct common_audit_data *auditdata,
int flags) int flags)
{ {
struct av_decision avd; struct av_decision avd;
int rc, rc2; int rc, rc2;
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd); rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
&avd);
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
auditdata, flags); auditdata, flags);
if (rc2) if (rc2)
return rc2; return rc2;
return rc; return rc;
} }
u32 avc_policy_seqno(void) u32 avc_policy_seqno(struct selinux_state *state)
{ {
return avc_cache.latest_notif; return state->avc->avc_cache.latest_notif;
} }
void avc_disable(void) void avc_disable(void)
...@@ -1184,7 +1228,7 @@ void avc_disable(void) ...@@ -1184,7 +1228,7 @@ void avc_disable(void)
* the cache and get that memory back. * the cache and get that memory back.
*/ */
if (avc_node_cachep) { if (avc_node_cachep) {
avc_flush(); avc_flush(selinux_state.avc);
/* kmem_cache_destroy(avc_node_cachep); */ /* kmem_cache_destroy(avc_node_cachep); */
} }
} }
...@@ -67,6 +67,8 @@ ...@@ -67,6 +67,8 @@
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/dccp.h> #include <linux/dccp.h>
#include <linux/sctp.h>
#include <net/sctp/structs.h>
#include <linux/quota.h> #include <linux/quota.h>
#include <linux/un.h> /* for Unix socket types */ #include <linux/un.h> /* for Unix socket types */
#include <net/af_unix.h> /* for Unix socket types */ #include <net/af_unix.h> /* for Unix socket types */
...@@ -98,20 +100,24 @@ ...@@ -98,20 +100,24 @@
#include "audit.h" #include "audit.h"
#include "avc_ss.h" #include "avc_ss.h"
struct selinux_state selinux_state;
/* SECMARK reference count */ /* SECMARK reference count */
static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
int selinux_enforcing; static int selinux_enforcing_boot;
static int __init enforcing_setup(char *str) static int __init enforcing_setup(char *str)
{ {
unsigned long enforcing; unsigned long enforcing;
if (!kstrtoul(str, 0, &enforcing)) if (!kstrtoul(str, 0, &enforcing))
selinux_enforcing = enforcing ? 1 : 0; selinux_enforcing_boot = enforcing ? 1 : 0;
return 1; return 1;
} }
__setup("enforcing=", enforcing_setup); __setup("enforcing=", enforcing_setup);
#else
#define selinux_enforcing_boot 1
#endif #endif
#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
...@@ -129,6 +135,19 @@ __setup("selinux=", selinux_enabled_setup); ...@@ -129,6 +135,19 @@ __setup("selinux=", selinux_enabled_setup);
int selinux_enabled = 1; int selinux_enabled = 1;
#endif #endif
static unsigned int selinux_checkreqprot_boot =
CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
static int __init checkreqprot_setup(char *str)
{
unsigned long checkreqprot;
if (!kstrtoul(str, 0, &checkreqprot))
selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
return 1;
}
__setup("checkreqprot=", checkreqprot_setup);
static struct kmem_cache *sel_inode_cache; static struct kmem_cache *sel_inode_cache;
static struct kmem_cache *file_security_cache; static struct kmem_cache *file_security_cache;
...@@ -145,7 +164,8 @@ static struct kmem_cache *file_security_cache; ...@@ -145,7 +164,8 @@ static struct kmem_cache *file_security_cache;
*/ */
static int selinux_secmark_enabled(void) static int selinux_secmark_enabled(void)
{ {
return (selinux_policycap_alwaysnetwork || atomic_read(&selinux_secmark_refcount)); return (selinux_policycap_alwaysnetwork() ||
atomic_read(&selinux_secmark_refcount));
} }
/** /**
...@@ -160,7 +180,8 @@ static int selinux_secmark_enabled(void) ...@@ -160,7 +180,8 @@ static int selinux_secmark_enabled(void)
*/ */
static int selinux_peerlbl_enabled(void) static int selinux_peerlbl_enabled(void)
{ {
return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled()); return (selinux_policycap_alwaysnetwork() ||
netlbl_enabled() || selinux_xfrm_enabled());
} }
static int selinux_netcache_avc_callback(u32 event) static int selinux_netcache_avc_callback(u32 event)
...@@ -264,7 +285,8 @@ static int __inode_security_revalidate(struct inode *inode, ...@@ -264,7 +285,8 @@ static int __inode_security_revalidate(struct inode *inode,
might_sleep_if(may_sleep); might_sleep_if(may_sleep);
if (ss_initialized && isec->initialized != LABEL_INITIALIZED) { if (selinux_state.initialized &&
isec->initialized != LABEL_INITIALIZED) {
if (!may_sleep) if (!may_sleep)
return -ECHILD; return -ECHILD;
...@@ -446,12 +468,14 @@ static int may_context_mount_sb_relabel(u32 sid, ...@@ -446,12 +468,14 @@ static int may_context_mount_sb_relabel(u32 sid,
const struct task_security_struct *tsec = cred->security; const struct task_security_struct *tsec = cred->security;
int rc; int rc;
rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, rc = avc_has_perm(&selinux_state,
tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL); FILESYSTEM__RELABELFROM, NULL);
if (rc) if (rc)
return rc; return rc;
rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, rc = avc_has_perm(&selinux_state,
tsec->sid, sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELTO, NULL); FILESYSTEM__RELABELTO, NULL);
return rc; return rc;
} }
...@@ -462,12 +486,14 @@ static int may_context_mount_inode_relabel(u32 sid, ...@@ -462,12 +486,14 @@ static int may_context_mount_inode_relabel(u32 sid,
{ {
const struct task_security_struct *tsec = cred->security; const struct task_security_struct *tsec = cred->security;
int rc; int rc;
rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, rc = avc_has_perm(&selinux_state,
tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__RELABELFROM, NULL); FILESYSTEM__RELABELFROM, NULL);
if (rc) if (rc)
return rc; return rc;
rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, rc = avc_has_perm(&selinux_state,
sid, sbsec->sid, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, NULL); FILESYSTEM__ASSOCIATE, NULL);
return rc; return rc;
} }
...@@ -486,7 +512,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb) ...@@ -486,7 +512,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
!strcmp(sb->s_type->name, "debugfs") || !strcmp(sb->s_type->name, "debugfs") ||
!strcmp(sb->s_type->name, "tracefs") || !strcmp(sb->s_type->name, "tracefs") ||
!strcmp(sb->s_type->name, "rootfs") || !strcmp(sb->s_type->name, "rootfs") ||
(selinux_policycap_cgroupseclabel && (selinux_policycap_cgroupseclabel() &&
(!strcmp(sb->s_type->name, "cgroup") || (!strcmp(sb->s_type->name, "cgroup") ||
!strcmp(sb->s_type->name, "cgroup2"))); !strcmp(sb->s_type->name, "cgroup2")));
} }
...@@ -586,7 +612,7 @@ static int selinux_get_mnt_opts(const struct super_block *sb, ...@@ -586,7 +612,7 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
if (!(sbsec->flags & SE_SBINITIALIZED)) if (!(sbsec->flags & SE_SBINITIALIZED))
return -EINVAL; return -EINVAL;
if (!ss_initialized) if (!selinux_state.initialized)
return -EINVAL; return -EINVAL;
/* make sure we always check enough bits to cover the mask */ /* make sure we always check enough bits to cover the mask */
...@@ -617,21 +643,25 @@ static int selinux_get_mnt_opts(const struct super_block *sb, ...@@ -617,21 +643,25 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
i = 0; i = 0;
if (sbsec->flags & FSCONTEXT_MNT) { if (sbsec->flags & FSCONTEXT_MNT) {
rc = security_sid_to_context(sbsec->sid, &context, &len); rc = security_sid_to_context(&selinux_state, sbsec->sid,
&context, &len);
if (rc) if (rc)
goto out_free; goto out_free;
opts->mnt_opts[i] = context; opts->mnt_opts[i] = context;
opts->mnt_opts_flags[i++] = FSCONTEXT_MNT; opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
} }
if (sbsec->flags & CONTEXT_MNT) { if (sbsec->flags & CONTEXT_MNT) {
rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len); rc = security_sid_to_context(&selinux_state,
sbsec->mntpoint_sid,
&context, &len);
if (rc) if (rc)
goto out_free; goto out_free;
opts->mnt_opts[i] = context; opts->mnt_opts[i] = context;
opts->mnt_opts_flags[i++] = CONTEXT_MNT; opts->mnt_opts_flags[i++] = CONTEXT_MNT;
} }
if (sbsec->flags & DEFCONTEXT_MNT) { if (sbsec->flags & DEFCONTEXT_MNT) {
rc = security_sid_to_context(sbsec->def_sid, &context, &len); rc = security_sid_to_context(&selinux_state, sbsec->def_sid,
&context, &len);
if (rc) if (rc)
goto out_free; goto out_free;
opts->mnt_opts[i] = context; opts->mnt_opts[i] = context;
...@@ -641,7 +671,8 @@ static int selinux_get_mnt_opts(const struct super_block *sb, ...@@ -641,7 +671,8 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
struct dentry *root = sbsec->sb->s_root; struct dentry *root = sbsec->sb->s_root;
struct inode_security_struct *isec = backing_inode_security(root); struct inode_security_struct *isec = backing_inode_security(root);
rc = security_sid_to_context(isec->sid, &context, &len); rc = security_sid_to_context(&selinux_state, isec->sid,
&context, &len);
if (rc) if (rc)
goto out_free; goto out_free;
opts->mnt_opts[i] = context; opts->mnt_opts[i] = context;
...@@ -704,7 +735,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -704,7 +735,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
mutex_lock(&sbsec->lock); mutex_lock(&sbsec->lock);
if (!ss_initialized) { if (!selinux_state.initialized) {
if (!num_opts) { if (!num_opts) {
/* Defer initialization until selinux_complete_init, /* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security after the initial policy is loaded and the security
...@@ -750,7 +781,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -750,7 +781,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
if (flags[i] == SBLABEL_MNT) if (flags[i] == SBLABEL_MNT)
continue; continue;
rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL); rc = security_context_str_to_sid(&selinux_state,
mount_options[i], &sid,
GFP_KERNEL);
if (rc) { if (rc) {
printk(KERN_WARNING "SELinux: security_context_str_to_sid" printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n", "(%s) failed for (dev %s, type %s) errno=%d\n",
...@@ -826,7 +859,7 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -826,7 +859,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* Determine the labeling behavior to use for this * Determine the labeling behavior to use for this
* filesystem type. * filesystem type.
*/ */
rc = security_fs_use(sb); rc = security_fs_use(&selinux_state, sb);
if (rc) { if (rc) {
printk(KERN_WARNING printk(KERN_WARNING
"%s: security_fs_use(%s) returned %d\n", "%s: security_fs_use(%s) returned %d\n",
...@@ -851,7 +884,9 @@ static int selinux_set_mnt_opts(struct super_block *sb, ...@@ -851,7 +884,9 @@ static int selinux_set_mnt_opts(struct super_block *sb,
} }
if (sbsec->behavior == SECURITY_FS_USE_XATTR) { if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
sbsec->behavior = SECURITY_FS_USE_MNTPOINT; sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
rc = security_transition_sid(current_sid(), current_sid(), rc = security_transition_sid(&selinux_state,
current_sid(),
current_sid(),
SECCLASS_FILE, NULL, SECCLASS_FILE, NULL,
&sbsec->mntpoint_sid); &sbsec->mntpoint_sid);
if (rc) if (rc)
...@@ -987,7 +1022,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, ...@@ -987,7 +1022,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
* if the parent was able to be mounted it clearly had no special lsm * if the parent was able to be mounted it clearly had no special lsm
* mount options. thus we can safely deal with this superblock later * mount options. thus we can safely deal with this superblock later
*/ */
if (!ss_initialized) if (!selinux_state.initialized)
return 0; return 0;
/* /*
...@@ -1014,7 +1049,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, ...@@ -1014,7 +1049,7 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
rc = security_fs_use(newsb); rc = security_fs_use(&selinux_state, newsb);
if (rc) if (rc)
goto out; goto out;
} }
...@@ -1297,7 +1332,7 @@ static inline int default_protocol_dgram(int protocol) ...@@ -1297,7 +1332,7 @@ static inline int default_protocol_dgram(int protocol)
static inline u16 socket_type_to_security_class(int family, int type, int protocol) static inline u16 socket_type_to_security_class(int family, int type, int protocol)
{ {
int extsockclass = selinux_policycap_extsockclass; int extsockclass = selinux_policycap_extsockclass();
switch (family) { switch (family) {
case PF_UNIX: case PF_UNIX:
...@@ -1471,7 +1506,8 @@ static int selinux_genfs_get_sid(struct dentry *dentry, ...@@ -1471,7 +1506,8 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
path++; path++;
} }
} }
rc = security_genfs_sid(sb->s_type->name, path, tclass, sid); rc = security_genfs_sid(&selinux_state, sb->s_type->name,
path, tclass, sid);
} }
free_page((unsigned long)buffer); free_page((unsigned long)buffer);
return rc; return rc;
...@@ -1589,7 +1625,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent ...@@ -1589,7 +1625,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->def_sid; sid = sbsec->def_sid;
rc = 0; rc = 0;
} else { } else {
rc = security_context_to_sid_default(context, rc, &sid, rc = security_context_to_sid_default(&selinux_state,
context, rc, &sid,
sbsec->def_sid, sbsec->def_sid,
GFP_NOFS); GFP_NOFS);
if (rc) { if (rc) {
...@@ -1622,7 +1659,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent ...@@ -1622,7 +1659,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sid = sbsec->sid; sid = sbsec->sid;
/* Try to obtain a transition SID. */ /* Try to obtain a transition SID. */
rc = security_transition_sid(task_sid, sid, sclass, NULL, &sid); rc = security_transition_sid(&selinux_state, task_sid, sid,
sclass, NULL, &sid);
if (rc) if (rc)
goto out; goto out;
break; break;
...@@ -1740,9 +1778,11 @@ static int cred_has_capability(const struct cred *cred, ...@@ -1740,9 +1778,11 @@ static int cred_has_capability(const struct cred *cred,
return -EINVAL; return -EINVAL;
} }
rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); rc = avc_has_perm_noaudit(&selinux_state,
sid, sid, sclass, av, 0, &avd);
if (audit == SECURITY_CAP_AUDIT) { if (audit == SECURITY_CAP_AUDIT) {
int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0); int rc2 = avc_audit(&selinux_state,
sid, sid, sclass, av, &avd, rc, &ad, 0);
if (rc2) if (rc2)
return rc2; return rc2;
} }
...@@ -1768,7 +1808,8 @@ static int inode_has_perm(const struct cred *cred, ...@@ -1768,7 +1808,8 @@ static int inode_has_perm(const struct cred *cred,
sid = cred_sid(cred); sid = cred_sid(cred);
isec = inode->i_security; isec = inode->i_security;
return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); return avc_has_perm(&selinux_state,
sid, isec->sid, isec->sclass, perms, adp);
} }
/* Same as inode_has_perm, but pass explicit audit data containing /* Same as inode_has_perm, but pass explicit audit data containing
...@@ -1841,7 +1882,8 @@ static int file_has_perm(const struct cred *cred, ...@@ -1841,7 +1882,8 @@ static int file_has_perm(const struct cred *cred,
ad.u.file = file; ad.u.file = file;
if (sid != fsec->sid) { if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid, rc = avc_has_perm(&selinux_state,
sid, fsec->sid,
SECCLASS_FD, SECCLASS_FD,
FD__USE, FD__USE,
&ad); &ad);
...@@ -1883,7 +1925,8 @@ selinux_determine_inode_label(const struct task_security_struct *tsec, ...@@ -1883,7 +1925,8 @@ selinux_determine_inode_label(const struct task_security_struct *tsec,
*_new_isid = tsec->create_sid; *_new_isid = tsec->create_sid;
} else { } else {
const struct inode_security_struct *dsec = inode_security(dir); const struct inode_security_struct *dsec = inode_security(dir);
return security_transition_sid(tsec->sid, dsec->sid, tclass, return security_transition_sid(&selinux_state, tsec->sid,
dsec->sid, tclass,
name, _new_isid); name, _new_isid);
} }
...@@ -1910,7 +1953,8 @@ static int may_create(struct inode *dir, ...@@ -1910,7 +1953,8 @@ static int may_create(struct inode *dir,
ad.type = LSM_AUDIT_DATA_DENTRY; ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry; ad.u.dentry = dentry;
rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, rc = avc_has_perm(&selinux_state,
sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH, DIR__ADD_NAME | DIR__SEARCH,
&ad); &ad);
if (rc) if (rc)
...@@ -1921,11 +1965,13 @@ static int may_create(struct inode *dir, ...@@ -1921,11 +1965,13 @@ static int may_create(struct inode *dir,
if (rc) if (rc)
return rc; return rc;
rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); rc = avc_has_perm(&selinux_state,
sid, newsid, tclass, FILE__CREATE, &ad);
if (rc) if (rc)
return rc; return rc;
return avc_has_perm(newsid, sbsec->sid, return avc_has_perm(&selinux_state,
newsid, sbsec->sid,
SECCLASS_FILESYSTEM, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, &ad); FILESYSTEM__ASSOCIATE, &ad);
} }
...@@ -1954,7 +2000,8 @@ static int may_link(struct inode *dir, ...@@ -1954,7 +2000,8 @@ static int may_link(struct inode *dir,
av = DIR__SEARCH; av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad); rc = avc_has_perm(&selinux_state,
sid, dsec->sid, SECCLASS_DIR, av, &ad);
if (rc) if (rc)
return rc; return rc;
...@@ -1974,7 +2021,8 @@ static int may_link(struct inode *dir, ...@@ -1974,7 +2021,8 @@ static int may_link(struct inode *dir,
return 0; return 0;
} }
rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad); rc = avc_has_perm(&selinux_state,
sid, isec->sid, isec->sclass, av, &ad);
return rc; return rc;
} }
...@@ -1998,16 +2046,19 @@ static inline int may_rename(struct inode *old_dir, ...@@ -1998,16 +2046,19 @@ static inline int may_rename(struct inode *old_dir,
ad.type = LSM_AUDIT_DATA_DENTRY; ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = old_dentry; ad.u.dentry = old_dentry;
rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, rc = avc_has_perm(&selinux_state,
sid, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad); DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc) if (rc)
return rc; return rc;
rc = avc_has_perm(sid, old_isec->sid, rc = avc_has_perm(&selinux_state,
sid, old_isec->sid,
old_isec->sclass, FILE__RENAME, &ad); old_isec->sclass, FILE__RENAME, &ad);
if (rc) if (rc)
return rc; return rc;
if (old_is_dir && new_dir != old_dir) { if (old_is_dir && new_dir != old_dir) {
rc = avc_has_perm(sid, old_isec->sid, rc = avc_has_perm(&selinux_state,
sid, old_isec->sid,
old_isec->sclass, DIR__REPARENT, &ad); old_isec->sclass, DIR__REPARENT, &ad);
if (rc) if (rc)
return rc; return rc;
...@@ -2017,13 +2068,15 @@ static inline int may_rename(struct inode *old_dir, ...@@ -2017,13 +2068,15 @@ static inline int may_rename(struct inode *old_dir,
av = DIR__ADD_NAME | DIR__SEARCH; av = DIR__ADD_NAME | DIR__SEARCH;
if (d_is_positive(new_dentry)) if (d_is_positive(new_dentry))
av |= DIR__REMOVE_NAME; av |= DIR__REMOVE_NAME;
rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); rc = avc_has_perm(&selinux_state,
sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
if (rc) if (rc)
return rc; return rc;
if (d_is_positive(new_dentry)) { if (d_is_positive(new_dentry)) {
new_isec = backing_inode_security(new_dentry); new_isec = backing_inode_security(new_dentry);
new_is_dir = d_is_dir(new_dentry); new_is_dir = d_is_dir(new_dentry);
rc = avc_has_perm(sid, new_isec->sid, rc = avc_has_perm(&selinux_state,
sid, new_isec->sid,
new_isec->sclass, new_isec->sclass,
(new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
if (rc) if (rc)
...@@ -2043,7 +2096,8 @@ static int superblock_has_perm(const struct cred *cred, ...@@ -2043,7 +2096,8 @@ static int superblock_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred); u32 sid = cred_sid(cred);
sbsec = sb->s_security; sbsec = sb->s_security;
return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); return avc_has_perm(&selinux_state,
sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
} }
/* Convert a Linux mode and permission mask to an access vector. */ /* Convert a Linux mode and permission mask to an access vector. */
...@@ -2106,7 +2160,8 @@ static inline u32 open_file_to_av(struct file *file) ...@@ -2106,7 +2160,8 @@ static inline u32 open_file_to_av(struct file *file)
u32 av = file_to_av(file); u32 av = file_to_av(file);
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
if (selinux_policycap_openperm && inode->i_sb->s_magic != SOCKFS_MAGIC) if (selinux_policycap_openperm() &&
inode->i_sb->s_magic != SOCKFS_MAGIC)
av |= FILE__OPEN; av |= FILE__OPEN;
return av; return av;
...@@ -2119,7 +2174,8 @@ static int selinux_binder_set_context_mgr(struct task_struct *mgr) ...@@ -2119,7 +2174,8 @@ static int selinux_binder_set_context_mgr(struct task_struct *mgr)
u32 mysid = current_sid(); u32 mysid = current_sid();
u32 mgrsid = task_sid(mgr); u32 mgrsid = task_sid(mgr);
return avc_has_perm(mysid, mgrsid, SECCLASS_BINDER, return avc_has_perm(&selinux_state,
mysid, mgrsid, SECCLASS_BINDER,
BINDER__SET_CONTEXT_MGR, NULL); BINDER__SET_CONTEXT_MGR, NULL);
} }
...@@ -2132,13 +2188,15 @@ static int selinux_binder_transaction(struct task_struct *from, ...@@ -2132,13 +2188,15 @@ static int selinux_binder_transaction(struct task_struct *from,
int rc; int rc;
if (mysid != fromsid) { if (mysid != fromsid) {
rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER, rc = avc_has_perm(&selinux_state,
mysid, fromsid, SECCLASS_BINDER,
BINDER__IMPERSONATE, NULL); BINDER__IMPERSONATE, NULL);
if (rc) if (rc)
return rc; return rc;
} }
return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, return avc_has_perm(&selinux_state,
fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
NULL); NULL);
} }
...@@ -2148,7 +2206,8 @@ static int selinux_binder_transfer_binder(struct task_struct *from, ...@@ -2148,7 +2206,8 @@ static int selinux_binder_transfer_binder(struct task_struct *from,
u32 fromsid = task_sid(from); u32 fromsid = task_sid(from);
u32 tosid = task_sid(to); u32 tosid = task_sid(to);
return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, return avc_has_perm(&selinux_state,
fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
NULL); NULL);
} }
...@@ -2167,7 +2226,8 @@ static int selinux_binder_transfer_file(struct task_struct *from, ...@@ -2167,7 +2226,8 @@ static int selinux_binder_transfer_file(struct task_struct *from,
ad.u.path = file->f_path; ad.u.path = file->f_path;
if (sid != fsec->sid) { if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid, rc = avc_has_perm(&selinux_state,
sid, fsec->sid,
SECCLASS_FD, SECCLASS_FD,
FD__USE, FD__USE,
&ad); &ad);
...@@ -2185,7 +2245,8 @@ static int selinux_binder_transfer_file(struct task_struct *from, ...@@ -2185,7 +2245,8 @@ static int selinux_binder_transfer_file(struct task_struct *from,
return 0; return 0;
isec = backing_inode_security(dentry); isec = backing_inode_security(dentry);
return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file), return avc_has_perm(&selinux_state,
sid, isec->sid, isec->sclass, file_to_av(file),
&ad); &ad);
} }
...@@ -2196,21 +2257,25 @@ static int selinux_ptrace_access_check(struct task_struct *child, ...@@ -2196,21 +2257,25 @@ static int selinux_ptrace_access_check(struct task_struct *child,
u32 csid = task_sid(child); u32 csid = task_sid(child);
if (mode & PTRACE_MODE_READ) if (mode & PTRACE_MODE_READ)
return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); return avc_has_perm(&selinux_state,
sid, csid, SECCLASS_FILE, FILE__READ, NULL);
return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); return avc_has_perm(&selinux_state,
sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
} }
static int selinux_ptrace_traceme(struct task_struct *parent) static int selinux_ptrace_traceme(struct task_struct *parent)
{ {
return avc_has_perm(task_sid(parent), current_sid(), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
task_sid(parent), current_sid(), SECCLASS_PROCESS,
PROCESS__PTRACE, NULL); PROCESS__PTRACE, NULL);
} }
static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted) kernel_cap_t *inheritable, kernel_cap_t *permitted)
{ {
return avc_has_perm(current_sid(), task_sid(target), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(target), SECCLASS_PROCESS,
PROCESS__GETCAP, NULL); PROCESS__GETCAP, NULL);
} }
...@@ -2219,7 +2284,8 @@ static int selinux_capset(struct cred *new, const struct cred *old, ...@@ -2219,7 +2284,8 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable, const kernel_cap_t *inheritable,
const kernel_cap_t *permitted) const kernel_cap_t *permitted)
{ {
return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
PROCESS__SETCAP, NULL); PROCESS__SETCAP, NULL);
} }
...@@ -2279,18 +2345,21 @@ static int selinux_syslog(int type) ...@@ -2279,18 +2345,21 @@ static int selinux_syslog(int type)
switch (type) { switch (type) {
case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */
case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */
return avc_has_perm(current_sid(), SECINITSID_KERNEL, return avc_has_perm(&selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL); SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */
/* Set level of messages printed to console */ /* Set level of messages printed to console */
case SYSLOG_ACTION_CONSOLE_LEVEL: case SYSLOG_ACTION_CONSOLE_LEVEL:
return avc_has_perm(current_sid(), SECINITSID_KERNEL, return avc_has_perm(&selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
NULL); NULL);
} }
/* All other syslog types */ /* All other syslog types */
return avc_has_perm(current_sid(), SECINITSID_KERNEL, return avc_has_perm(&selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL); SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
} }
...@@ -2351,13 +2420,14 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm, ...@@ -2351,13 +2420,14 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
* policy allows the corresponding permission between * policy allows the corresponding permission between
* the old and new contexts. * the old and new contexts.
*/ */
if (selinux_policycap_nnp_nosuid_transition) { if (selinux_policycap_nnp_nosuid_transition()) {
av = 0; av = 0;
if (nnp) if (nnp)
av |= PROCESS2__NNP_TRANSITION; av |= PROCESS2__NNP_TRANSITION;
if (nosuid) if (nosuid)
av |= PROCESS2__NOSUID_TRANSITION; av |= PROCESS2__NOSUID_TRANSITION;
rc = avc_has_perm(old_tsec->sid, new_tsec->sid, rc = avc_has_perm(&selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS2, av, NULL); SECCLASS_PROCESS2, av, NULL);
if (!rc) if (!rc)
return 0; return 0;
...@@ -2368,7 +2438,8 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm, ...@@ -2368,7 +2438,8 @@ static int check_nnp_nosuid(const struct linux_binprm *bprm,
* i.e. SIDs that are guaranteed to only be allowed a subset * i.e. SIDs that are guaranteed to only be allowed a subset
* of the permissions of the current SID. * of the permissions of the current SID.
*/ */
rc = security_bounded_transition(old_tsec->sid, new_tsec->sid); rc = security_bounded_transition(&selinux_state, old_tsec->sid,
new_tsec->sid);
if (!rc) if (!rc)
return 0; return 0;
...@@ -2420,8 +2491,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) ...@@ -2420,8 +2491,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
return rc; return rc;
} else { } else {
/* Check for a default transition on this program. */ /* Check for a default transition on this program. */
rc = security_transition_sid(old_tsec->sid, isec->sid, rc = security_transition_sid(&selinux_state, old_tsec->sid,
SECCLASS_PROCESS, NULL, isec->sid, SECCLASS_PROCESS, NULL,
&new_tsec->sid); &new_tsec->sid);
if (rc) if (rc)
return rc; return rc;
...@@ -2439,25 +2510,29 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) ...@@ -2439,25 +2510,29 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
ad.u.file = bprm->file; ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) { if (new_tsec->sid == old_tsec->sid) {
rc = avc_has_perm(old_tsec->sid, isec->sid, rc = avc_has_perm(&selinux_state,
old_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
if (rc) if (rc)
return rc; return rc;
} else { } else {
/* Check permissions for the transition. */ /* Check permissions for the transition. */
rc = avc_has_perm(old_tsec->sid, new_tsec->sid, rc = avc_has_perm(&selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
if (rc) if (rc)
return rc; return rc;
rc = avc_has_perm(new_tsec->sid, isec->sid, rc = avc_has_perm(&selinux_state,
new_tsec->sid, isec->sid,
SECCLASS_FILE, FILE__ENTRYPOINT, &ad); SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
if (rc) if (rc)
return rc; return rc;
/* Check for shared state */ /* Check for shared state */
if (bprm->unsafe & LSM_UNSAFE_SHARE) { if (bprm->unsafe & LSM_UNSAFE_SHARE) {
rc = avc_has_perm(old_tsec->sid, new_tsec->sid, rc = avc_has_perm(&selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__SHARE, SECCLASS_PROCESS, PROCESS__SHARE,
NULL); NULL);
if (rc) if (rc)
...@@ -2469,7 +2544,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) ...@@ -2469,7 +2544,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
if (bprm->unsafe & LSM_UNSAFE_PTRACE) { if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
u32 ptsid = ptrace_parent_sid(); u32 ptsid = ptrace_parent_sid();
if (ptsid != 0) { if (ptsid != 0) {
rc = avc_has_perm(ptsid, new_tsec->sid, rc = avc_has_perm(&selinux_state,
ptsid, new_tsec->sid,
SECCLASS_PROCESS, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL); PROCESS__PTRACE, NULL);
if (rc) if (rc)
...@@ -2483,7 +2559,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) ...@@ -2483,7 +2559,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
/* Enable secure mode for SIDs transitions unless /* Enable secure mode for SIDs transitions unless
the noatsecure permission is granted between the noatsecure permission is granted between
the two SIDs, i.e. ahp returns 0. */ the two SIDs, i.e. ahp returns 0. */
rc = avc_has_perm(old_tsec->sid, new_tsec->sid, rc = avc_has_perm(&selinux_state,
old_tsec->sid, new_tsec->sid,
SECCLASS_PROCESS, PROCESS__NOATSECURE, SECCLASS_PROCESS, PROCESS__NOATSECURE,
NULL); NULL);
bprm->secureexec |= !!rc; bprm->secureexec |= !!rc;
...@@ -2575,7 +2652,8 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm) ...@@ -2575,7 +2652,8 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
* higher than the default soft limit for cases where the default is * higher than the default soft limit for cases where the default is
* lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK. * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
*/ */
rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS, rc = avc_has_perm(&selinux_state,
new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
PROCESS__RLIMITINH, NULL); PROCESS__RLIMITINH, NULL);
if (rc) { if (rc) {
/* protect against do_prlimit() */ /* protect against do_prlimit() */
...@@ -2615,7 +2693,8 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm) ...@@ -2615,7 +2693,8 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
* This must occur _after_ the task SID has been updated so that any * This must occur _after_ the task SID has been updated so that any
* kill done after the flush will be checked against the new SID. * kill done after the flush will be checked against the new SID.
*/ */
rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); rc = avc_has_perm(&selinux_state,
osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
if (rc) { if (rc) {
if (IS_ENABLED(CONFIG_POSIX_TIMERS)) { if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
memset(&itimer, 0, sizeof itimer); memset(&itimer, 0, sizeof itimer);
...@@ -2779,7 +2858,9 @@ static int selinux_sb_remount(struct super_block *sb, void *data) ...@@ -2779,7 +2858,9 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
if (flags[i] == SBLABEL_MNT) if (flags[i] == SBLABEL_MNT)
continue; continue;
rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL); rc = security_context_str_to_sid(&selinux_state,
mount_options[i], &sid,
GFP_KERNEL);
if (rc) { if (rc) {
printk(KERN_WARNING "SELinux: security_context_str_to_sid" printk(KERN_WARNING "SELinux: security_context_str_to_sid"
"(%s) failed for (dev %s, type %s) errno=%d\n", "(%s) failed for (dev %s, type %s) errno=%d\n",
...@@ -2904,7 +2985,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, ...@@ -2904,7 +2985,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
if (rc) if (rc)
return rc; return rc;
return security_sid_to_context(newsid, (char **)ctx, ctxlen); return security_sid_to_context(&selinux_state, newsid, (char **)ctx,
ctxlen);
} }
static int selinux_dentry_create_files_as(struct dentry *dentry, int mode, static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
...@@ -2958,14 +3040,15 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, ...@@ -2958,14 +3040,15 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
isec->initialized = LABEL_INITIALIZED; isec->initialized = LABEL_INITIALIZED;
} }
if (!ss_initialized || !(sbsec->flags & SBLABEL_MNT)) if (!selinux_state.initialized || !(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (name) if (name)
*name = XATTR_SELINUX_SUFFIX; *name = XATTR_SELINUX_SUFFIX;
if (value && len) { if (value && len) {
rc = security_sid_to_context_force(newsid, &context, &clen); rc = security_sid_to_context_force(&selinux_state, newsid,
&context, &clen);
if (rc) if (rc)
return rc; return rc;
*value = context; *value = context;
...@@ -3040,7 +3123,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, ...@@ -3040,7 +3123,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
if (IS_ERR(isec)) if (IS_ERR(isec))
return PTR_ERR(isec); return PTR_ERR(isec);
return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad, return avc_has_perm_flags(&selinux_state,
sid, isec->sid, isec->sclass, FILE__READ, &ad,
rcu ? MAY_NOT_BLOCK : 0); rcu ? MAY_NOT_BLOCK : 0);
} }
...@@ -3056,7 +3140,8 @@ static noinline int audit_inode_permission(struct inode *inode, ...@@ -3056,7 +3140,8 @@ static noinline int audit_inode_permission(struct inode *inode,
ad.type = LSM_AUDIT_DATA_INODE; ad.type = LSM_AUDIT_DATA_INODE;
ad.u.inode = inode; ad.u.inode = inode;
rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, rc = slow_avc_audit(&selinux_state,
current_sid(), isec->sid, isec->sclass, perms,
audited, denied, result, &ad, flags); audited, denied, result, &ad, flags);
if (rc) if (rc)
return rc; return rc;
...@@ -3094,7 +3179,8 @@ static int selinux_inode_permission(struct inode *inode, int mask) ...@@ -3094,7 +3179,8 @@ static int selinux_inode_permission(struct inode *inode, int mask)
if (IS_ERR(isec)) if (IS_ERR(isec))
return PTR_ERR(isec); return PTR_ERR(isec);
rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd); rc = avc_has_perm_noaudit(&selinux_state,
sid, isec->sid, isec->sclass, perms, 0, &avd);
audited = avc_audit_required(perms, &avd, rc, audited = avc_audit_required(perms, &avd, rc,
from_access ? FILE__AUDIT_ACCESS : 0, from_access ? FILE__AUDIT_ACCESS : 0,
&denied); &denied);
...@@ -3126,7 +3212,7 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) ...@@ -3126,7 +3212,7 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, dentry, FILE__SETATTR); return dentry_has_perm(cred, dentry, FILE__SETATTR);
if (selinux_policycap_openperm && if (selinux_policycap_openperm() &&
inode->i_sb->s_magic != SOCKFS_MAGIC && inode->i_sb->s_magic != SOCKFS_MAGIC &&
(ia_valid & ATTR_SIZE) && (ia_valid & ATTR_SIZE) &&
!(ia_valid & ATTR_FILE)) !(ia_valid & ATTR_FILE))
...@@ -3183,12 +3269,14 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -3183,12 +3269,14 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
ad.u.dentry = dentry; ad.u.dentry = dentry;
isec = backing_inode_security(dentry); isec = backing_inode_security(dentry);
rc = avc_has_perm(sid, isec->sid, isec->sclass, rc = avc_has_perm(&selinux_state,
sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad); FILE__RELABELFROM, &ad);
if (rc) if (rc)
return rc; return rc;
rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL); rc = security_context_to_sid(&selinux_state, value, size, &newsid,
GFP_KERNEL);
if (rc == -EINVAL) { if (rc == -EINVAL) {
if (!has_cap_mac_admin(true)) { if (!has_cap_mac_admin(true)) {
struct audit_buffer *ab; struct audit_buffer *ab;
...@@ -3213,22 +3301,25 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -3213,22 +3301,25 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
return rc; return rc;
} }
rc = security_context_to_sid_force(value, size, &newsid); rc = security_context_to_sid_force(&selinux_state, value,
size, &newsid);
} }
if (rc) if (rc)
return rc; return rc;
rc = avc_has_perm(sid, newsid, isec->sclass, rc = avc_has_perm(&selinux_state,
sid, newsid, isec->sclass,
FILE__RELABELTO, &ad); FILE__RELABELTO, &ad);
if (rc) if (rc)
return rc; return rc;
rc = security_validate_transition(isec->sid, newsid, sid, rc = security_validate_transition(&selinux_state, isec->sid, newsid,
isec->sclass); sid, isec->sclass);
if (rc) if (rc)
return rc; return rc;
return avc_has_perm(newsid, return avc_has_perm(&selinux_state,
newsid,
sbsec->sid, sbsec->sid,
SECCLASS_FILESYSTEM, SECCLASS_FILESYSTEM,
FILESYSTEM__ASSOCIATE, FILESYSTEM__ASSOCIATE,
...@@ -3249,7 +3340,8 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, ...@@ -3249,7 +3340,8 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
return; return;
} }
rc = security_context_to_sid_force(value, size, &newsid); rc = security_context_to_sid_force(&selinux_state, value, size,
&newsid);
if (rc) { if (rc) {
printk(KERN_ERR "SELinux: unable to map context to SID" printk(KERN_ERR "SELinux: unable to map context to SID"
"for (%s, %lu), rc=%d\n", "for (%s, %lu), rc=%d\n",
...@@ -3324,10 +3416,12 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void ...@@ -3324,10 +3416,12 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
*/ */
isec = inode_security(inode); isec = inode_security(inode);
if (has_cap_mac_admin(false)) if (has_cap_mac_admin(false))
error = security_sid_to_context_force(isec->sid, &context, error = security_sid_to_context_force(&selinux_state,
isec->sid, &context,
&size); &size);
else else
error = security_sid_to_context(isec->sid, &context, &size); error = security_sid_to_context(&selinux_state, isec->sid,
&context, &size);
if (error) if (error)
return error; return error;
error = size; error = size;
...@@ -3353,7 +3447,8 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name, ...@@ -3353,7 +3447,8 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
if (!value || !size) if (!value || !size)
return -EACCES; return -EACCES;
rc = security_context_to_sid(value, size, &newsid, GFP_KERNEL); rc = security_context_to_sid(&selinux_state, value, size, &newsid,
GFP_KERNEL);
if (rc) if (rc)
return rc; return rc;
...@@ -3442,7 +3537,7 @@ static int selinux_file_permission(struct file *file, int mask) ...@@ -3442,7 +3537,7 @@ static int selinux_file_permission(struct file *file, int mask)
isec = inode_security(inode); isec = inode_security(inode);
if (sid == fsec->sid && fsec->isid == isec->sid && if (sid == fsec->sid && fsec->isid == isec->sid &&
fsec->pseqno == avc_policy_seqno()) fsec->pseqno == avc_policy_seqno(&selinux_state))
/* No change since file_open check. */ /* No change since file_open check. */
return 0; return 0;
...@@ -3482,7 +3577,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, ...@@ -3482,7 +3577,8 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
ad.u.op->path = file->f_path; ad.u.op->path = file->f_path;
if (ssid != fsec->sid) { if (ssid != fsec->sid) {
rc = avc_has_perm(ssid, fsec->sid, rc = avc_has_perm(&selinux_state,
ssid, fsec->sid,
SECCLASS_FD, SECCLASS_FD,
FD__USE, FD__USE,
&ad); &ad);
...@@ -3494,8 +3590,9 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file, ...@@ -3494,8 +3590,9 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
return 0; return 0;
isec = inode_security(inode); isec = inode_security(inode);
rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, rc = avc_has_extended_perms(&selinux_state,
requested, driver, xperm, &ad); ssid, isec->sid, isec->sclass,
requested, driver, xperm, &ad);
out: out:
return rc; return rc;
} }
...@@ -3563,7 +3660,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared ...@@ -3563,7 +3660,8 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
* private file mapping that will also be writable. * private file mapping that will also be writable.
* This has an additional check. * This has an additional check.
*/ */
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, rc = avc_has_perm(&selinux_state,
sid, sid, SECCLASS_PROCESS,
PROCESS__EXECMEM, NULL); PROCESS__EXECMEM, NULL);
if (rc) if (rc)
goto error; goto error;
...@@ -3593,7 +3691,8 @@ static int selinux_mmap_addr(unsigned long addr) ...@@ -3593,7 +3691,8 @@ static int selinux_mmap_addr(unsigned long addr)
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
u32 sid = current_sid(); u32 sid = current_sid();
rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, rc = avc_has_perm(&selinux_state,
sid, sid, SECCLASS_MEMPROTECT,
MEMPROTECT__MMAP_ZERO, NULL); MEMPROTECT__MMAP_ZERO, NULL);
} }
...@@ -3615,7 +3714,7 @@ static int selinux_mmap_file(struct file *file, unsigned long reqprot, ...@@ -3615,7 +3714,7 @@ static int selinux_mmap_file(struct file *file, unsigned long reqprot,
return rc; return rc;
} }
if (selinux_checkreqprot) if (selinux_state.checkreqprot)
prot = reqprot; prot = reqprot;
return file_map_prot_check(file, prot, return file_map_prot_check(file, prot,
...@@ -3629,7 +3728,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, ...@@ -3629,7 +3728,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
u32 sid = cred_sid(cred); u32 sid = cred_sid(cred);
if (selinux_checkreqprot) if (selinux_state.checkreqprot)
prot = reqprot; prot = reqprot;
if (default_noexec && if (default_noexec &&
...@@ -3637,13 +3736,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma, ...@@ -3637,13 +3736,15 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
int rc = 0; int rc = 0;
if (vma->vm_start >= vma->vm_mm->start_brk && if (vma->vm_start >= vma->vm_mm->start_brk &&
vma->vm_end <= vma->vm_mm->brk) { vma->vm_end <= vma->vm_mm->brk) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, rc = avc_has_perm(&selinux_state,
sid, sid, SECCLASS_PROCESS,
PROCESS__EXECHEAP, NULL); PROCESS__EXECHEAP, NULL);
} else if (!vma->vm_file && } else if (!vma->vm_file &&
((vma->vm_start <= vma->vm_mm->start_stack && ((vma->vm_start <= vma->vm_mm->start_stack &&
vma->vm_end >= vma->vm_mm->start_stack) || vma->vm_end >= vma->vm_mm->start_stack) ||
vma_is_stack_for_current(vma))) { vma_is_stack_for_current(vma))) {
rc = avc_has_perm(sid, sid, SECCLASS_PROCESS, rc = avc_has_perm(&selinux_state,
sid, sid, SECCLASS_PROCESS,
PROCESS__EXECSTACK, NULL); PROCESS__EXECSTACK, NULL);
} else if (vma->vm_file && vma->anon_vma) { } else if (vma->vm_file && vma->anon_vma) {
/* /*
...@@ -3735,7 +3836,8 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk, ...@@ -3735,7 +3836,8 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
else else
perm = signal_to_av(signum); perm = signal_to_av(signum);
return avc_has_perm(fsec->fown_sid, sid, return avc_has_perm(&selinux_state,
fsec->fown_sid, sid,
SECCLASS_PROCESS, perm, NULL); SECCLASS_PROCESS, perm, NULL);
} }
...@@ -3761,7 +3863,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred) ...@@ -3761,7 +3863,7 @@ static int selinux_file_open(struct file *file, const struct cred *cred)
* struct as its SID. * struct as its SID.
*/ */
fsec->isid = isec->sid; fsec->isid = isec->sid;
fsec->pseqno = avc_policy_seqno(); fsec->pseqno = avc_policy_seqno(&selinux_state);
/* /*
* Since the inode label or policy seqno may have changed * Since the inode label or policy seqno may have changed
* between the selinux_inode_permission check and the saving * between the selinux_inode_permission check and the saving
...@@ -3780,7 +3882,8 @@ static int selinux_task_alloc(struct task_struct *task, ...@@ -3780,7 +3882,8 @@ static int selinux_task_alloc(struct task_struct *task,
{ {
u32 sid = current_sid(); u32 sid = current_sid();
return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); return avc_has_perm(&selinux_state,
sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
} }
/* /*
...@@ -3854,7 +3957,8 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid) ...@@ -3854,7 +3957,8 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
u32 sid = current_sid(); u32 sid = current_sid();
int ret; int ret;
ret = avc_has_perm(sid, secid, ret = avc_has_perm(&selinux_state,
sid, secid,
SECCLASS_KERNEL_SERVICE, SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__USE_AS_OVERRIDE, KERNEL_SERVICE__USE_AS_OVERRIDE,
NULL); NULL);
...@@ -3878,7 +3982,8 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) ...@@ -3878,7 +3982,8 @@ static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
u32 sid = current_sid(); u32 sid = current_sid();
int ret; int ret;
ret = avc_has_perm(sid, isec->sid, ret = avc_has_perm(&selinux_state,
sid, isec->sid,
SECCLASS_KERNEL_SERVICE, SECCLASS_KERNEL_SERVICE,
KERNEL_SERVICE__CREATE_FILES_AS, KERNEL_SERVICE__CREATE_FILES_AS,
NULL); NULL);
...@@ -3895,7 +4000,8 @@ static int selinux_kernel_module_request(char *kmod_name) ...@@ -3895,7 +4000,8 @@ static int selinux_kernel_module_request(char *kmod_name)
ad.type = LSM_AUDIT_DATA_KMOD; ad.type = LSM_AUDIT_DATA_KMOD;
ad.u.kmod_name = kmod_name; ad.u.kmod_name = kmod_name;
return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, return avc_has_perm(&selinux_state,
current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
SYSTEM__MODULE_REQUEST, &ad); SYSTEM__MODULE_REQUEST, &ad);
} }
...@@ -3909,7 +4015,8 @@ static int selinux_kernel_module_from_file(struct file *file) ...@@ -3909,7 +4015,8 @@ static int selinux_kernel_module_from_file(struct file *file)
/* init_module */ /* init_module */
if (file == NULL) if (file == NULL)
return avc_has_perm(sid, sid, SECCLASS_SYSTEM, return avc_has_perm(&selinux_state,
sid, sid, SECCLASS_SYSTEM,
SYSTEM__MODULE_LOAD, NULL); SYSTEM__MODULE_LOAD, NULL);
/* finit_module */ /* finit_module */
...@@ -3919,13 +4026,15 @@ static int selinux_kernel_module_from_file(struct file *file) ...@@ -3919,13 +4026,15 @@ static int selinux_kernel_module_from_file(struct file *file)
fsec = file->f_security; fsec = file->f_security;
if (sid != fsec->sid) { if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); rc = avc_has_perm(&selinux_state,
sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
if (rc) if (rc)
return rc; return rc;
} }
isec = inode_security(file_inode(file)); isec = inode_security(file_inode(file));
return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM, return avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_SYSTEM,
SYSTEM__MODULE_LOAD, &ad); SYSTEM__MODULE_LOAD, &ad);
} }
...@@ -3947,19 +4056,22 @@ static int selinux_kernel_read_file(struct file *file, ...@@ -3947,19 +4056,22 @@ static int selinux_kernel_read_file(struct file *file,
static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETPGID, NULL); PROCESS__SETPGID, NULL);
} }
static int selinux_task_getpgid(struct task_struct *p) static int selinux_task_getpgid(struct task_struct *p)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETPGID, NULL); PROCESS__GETPGID, NULL);
} }
static int selinux_task_getsid(struct task_struct *p) static int selinux_task_getsid(struct task_struct *p)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETSESSION, NULL); PROCESS__GETSESSION, NULL);
} }
...@@ -3970,19 +4082,22 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid) ...@@ -3970,19 +4082,22 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
static int selinux_task_setnice(struct task_struct *p, int nice) static int selinux_task_setnice(struct task_struct *p, int nice)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL); PROCESS__SETSCHED, NULL);
} }
static int selinux_task_setioprio(struct task_struct *p, int ioprio) static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL); PROCESS__SETSCHED, NULL);
} }
static int selinux_task_getioprio(struct task_struct *p) static int selinux_task_getioprio(struct task_struct *p)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL); PROCESS__GETSCHED, NULL);
} }
...@@ -3997,7 +4112,8 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre ...@@ -3997,7 +4112,8 @@ static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcre
av |= PROCESS__SETRLIMIT; av |= PROCESS__SETRLIMIT;
if (flags & LSM_PRLIMIT_READ) if (flags & LSM_PRLIMIT_READ)
av |= PROCESS__GETRLIMIT; av |= PROCESS__GETRLIMIT;
return avc_has_perm(cred_sid(cred), cred_sid(tcred), return avc_has_perm(&selinux_state,
cred_sid(cred), cred_sid(tcred),
SECCLASS_PROCESS, av, NULL); SECCLASS_PROCESS, av, NULL);
} }
...@@ -4011,7 +4127,8 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, ...@@ -4011,7 +4127,8 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
later be used as a safe reset point for the soft limit later be used as a safe reset point for the soft limit
upon context transitions. See selinux_bprm_committing_creds. */ upon context transitions. See selinux_bprm_committing_creds. */
if (old_rlim->rlim_max != new_rlim->rlim_max) if (old_rlim->rlim_max != new_rlim->rlim_max)
return avc_has_perm(current_sid(), task_sid(p), return avc_has_perm(&selinux_state,
current_sid(), task_sid(p),
SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL); SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
return 0; return 0;
...@@ -4019,19 +4136,22 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, ...@@ -4019,19 +4136,22 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
static int selinux_task_setscheduler(struct task_struct *p) static int selinux_task_setscheduler(struct task_struct *p)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL); PROCESS__SETSCHED, NULL);
} }
static int selinux_task_getscheduler(struct task_struct *p) static int selinux_task_getscheduler(struct task_struct *p)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__GETSCHED, NULL); PROCESS__GETSCHED, NULL);
} }
static int selinux_task_movememory(struct task_struct *p) static int selinux_task_movememory(struct task_struct *p)
{ {
return avc_has_perm(current_sid(), task_sid(p), SECCLASS_PROCESS, return avc_has_perm(&selinux_state,
current_sid(), task_sid(p), SECCLASS_PROCESS,
PROCESS__SETSCHED, NULL); PROCESS__SETSCHED, NULL);
} }
...@@ -4046,7 +4166,8 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info, ...@@ -4046,7 +4166,8 @@ static int selinux_task_kill(struct task_struct *p, struct siginfo *info,
perm = signal_to_av(sig); perm = signal_to_av(sig);
if (!secid) if (!secid)
secid = current_sid(); secid = current_sid();
return avc_has_perm(secid, task_sid(p), SECCLASS_PROCESS, perm, NULL); return avc_has_perm(&selinux_state,
secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
} }
static void selinux_task_to_inode(struct task_struct *p, static void selinux_task_to_inode(struct task_struct *p,
...@@ -4134,6 +4255,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb, ...@@ -4134,6 +4255,23 @@ static int selinux_parse_skb_ipv4(struct sk_buff *skb,
break; break;
} }
#if IS_ENABLED(CONFIG_IP_SCTP)
case IPPROTO_SCTP: {
struct sctphdr _sctph, *sh;
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
offset += ihlen;
sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
if (sh == NULL)
break;
ad->u.net->sport = sh->source;
ad->u.net->dport = sh->dest;
break;
}
#endif
default: default:
break; break;
} }
...@@ -4207,6 +4345,19 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, ...@@ -4207,6 +4345,19 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
break; break;
} }
#if IS_ENABLED(CONFIG_IP_SCTP)
case IPPROTO_SCTP: {
struct sctphdr _sctph, *sh;
sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
if (sh == NULL)
break;
ad->u.net->sport = sh->source;
ad->u.net->dport = sh->dest;
break;
}
#endif
/* includes fragments */ /* includes fragments */
default: default:
break; break;
...@@ -4287,7 +4438,8 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) ...@@ -4287,7 +4438,8 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
if (unlikely(err)) if (unlikely(err))
return -EACCES; return -EACCES;
err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid); err = security_net_peersid_resolve(&selinux_state, nlbl_sid,
nlbl_type, xfrm_sid, sid);
if (unlikely(err)) { if (unlikely(err)) {
printk(KERN_WARNING printk(KERN_WARNING
"SELinux: failure in selinux_skb_peerlbl_sid()," "SELinux: failure in selinux_skb_peerlbl_sid(),"
...@@ -4315,7 +4467,8 @@ static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid) ...@@ -4315,7 +4467,8 @@ static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
int err = 0; int err = 0;
if (skb_sid != SECSID_NULL) if (skb_sid != SECSID_NULL)
err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid); err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid,
conn_sid);
else else
*conn_sid = sk_sid; *conn_sid = sk_sid;
...@@ -4332,8 +4485,8 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec, ...@@ -4332,8 +4485,8 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
return 0; return 0;
} }
return security_transition_sid(tsec->sid, tsec->sid, secclass, NULL, return security_transition_sid(&selinux_state, tsec->sid, tsec->sid,
socksid); secclass, NULL, socksid);
} }
static int sock_has_perm(struct sock *sk, u32 perms) static int sock_has_perm(struct sock *sk, u32 perms)
...@@ -4349,7 +4502,8 @@ static int sock_has_perm(struct sock *sk, u32 perms) ...@@ -4349,7 +4502,8 @@ static int sock_has_perm(struct sock *sk, u32 perms)
ad.u.net = &net; ad.u.net = &net;
ad.u.net->sk = sk; ad.u.net->sk = sk;
return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms, return avc_has_perm(&selinux_state,
current_sid(), sksec->sid, sksec->sclass, perms,
&ad); &ad);
} }
...@@ -4369,7 +4523,8 @@ static int selinux_socket_create(int family, int type, ...@@ -4369,7 +4523,8 @@ static int selinux_socket_create(int family, int type,
if (rc) if (rc)
return rc; return rc;
return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); return avc_has_perm(&selinux_state,
tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
} }
static int selinux_socket_post_create(struct socket *sock, int family, static int selinux_socket_post_create(struct socket *sock, int family,
...@@ -4396,6 +4551,10 @@ static int selinux_socket_post_create(struct socket *sock, int family, ...@@ -4396,6 +4551,10 @@ static int selinux_socket_post_create(struct socket *sock, int family,
sksec = sock->sk->sk_security; sksec = sock->sk->sk_security;
sksec->sclass = sclass; sksec->sclass = sclass;
sksec->sid = sid; sksec->sid = sid;
/* Allows detection of the first association on this socket */
if (sksec->sclass == SECCLASS_SCTP_SOCKET)
sksec->sctp_assoc_state = SCTP_ASSOC_UNSET;
err = selinux_netlbl_socket_post_create(sock->sk, family); err = selinux_netlbl_socket_post_create(sock->sk, family);
} }
...@@ -4416,11 +4575,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ...@@ -4416,11 +4575,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
if (err) if (err)
goto out; goto out;
/* /* If PF_INET or PF_INET6, check name_bind permission for the port. */
* If PF_INET or PF_INET6, check name_bind permission for the port.
* Multiple address binding for SCTP is not supported yet: we just
* check the first address now.
*/
family = sk->sk_family; family = sk->sk_family;
if (family == PF_INET || family == PF_INET6) { if (family == PF_INET || family == PF_INET6) {
char *addrp; char *addrp;
...@@ -4432,22 +4587,35 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ...@@ -4432,22 +4587,35 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
unsigned short snum; unsigned short snum;
u32 sid, node_perm; u32 sid, node_perm;
if (family == PF_INET) { /*
if (addrlen < sizeof(struct sockaddr_in)) { * sctp_bindx(3) calls via selinux_sctp_bind_connect()
err = -EINVAL; * that validates multiple binding addresses. Because of this
goto out; * need to check address->sa_family as it is possible to have
} * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
*/
switch (address->sa_family) {
case AF_INET:
if (addrlen < sizeof(struct sockaddr_in))
return -EINVAL;
addr4 = (struct sockaddr_in *)address; addr4 = (struct sockaddr_in *)address;
snum = ntohs(addr4->sin_port); snum = ntohs(addr4->sin_port);
addrp = (char *)&addr4->sin_addr.s_addr; addrp = (char *)&addr4->sin_addr.s_addr;
} else { break;
if (addrlen < SIN6_LEN_RFC2133) { case AF_INET6:
err = -EINVAL; if (addrlen < SIN6_LEN_RFC2133)
goto out; return -EINVAL;
}
addr6 = (struct sockaddr_in6 *)address; addr6 = (struct sockaddr_in6 *)address;
snum = ntohs(addr6->sin6_port); snum = ntohs(addr6->sin6_port);
addrp = (char *)&addr6->sin6_addr.s6_addr; addrp = (char *)&addr6->sin6_addr.s6_addr;
break;
default:
/* Note that SCTP services expect -EINVAL, whereas
* others expect -EAFNOSUPPORT.
*/
if (sksec->sclass == SECCLASS_SCTP_SOCKET)
return -EINVAL;
else
return -EAFNOSUPPORT;
} }
if (snum) { if (snum) {
...@@ -4465,7 +4633,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ...@@ -4465,7 +4633,8 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
ad.u.net = &net; ad.u.net = &net;
ad.u.net->sport = htons(snum); ad.u.net->sport = htons(snum);
ad.u.net->family = family; ad.u.net->family = family;
err = avc_has_perm(sksec->sid, sid, err = avc_has_perm(&selinux_state,
sksec->sid, sid,
sksec->sclass, sksec->sclass,
SOCKET__NAME_BIND, &ad); SOCKET__NAME_BIND, &ad);
if (err) if (err)
...@@ -4486,6 +4655,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ...@@ -4486,6 +4655,10 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
node_perm = DCCP_SOCKET__NODE_BIND; node_perm = DCCP_SOCKET__NODE_BIND;
break; break;
case SECCLASS_SCTP_SOCKET:
node_perm = SCTP_SOCKET__NODE_BIND;
break;
default: default:
node_perm = RAWIP_SOCKET__NODE_BIND; node_perm = RAWIP_SOCKET__NODE_BIND;
break; break;
...@@ -4500,12 +4673,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ...@@ -4500,12 +4673,13 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
ad.u.net->sport = htons(snum); ad.u.net->sport = htons(snum);
ad.u.net->family = family; ad.u.net->family = family;
if (family == PF_INET) if (address->sa_family == AF_INET)
ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
else else
ad.u.net->v6info.saddr = addr6->sin6_addr; ad.u.net->v6info.saddr = addr6->sin6_addr;
err = avc_has_perm(sksec->sid, sid, err = avc_has_perm(&selinux_state,
sksec->sid, sid,
sksec->sclass, node_perm, &ad); sksec->sclass, node_perm, &ad);
if (err) if (err)
goto out; goto out;
...@@ -4514,7 +4688,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in ...@@ -4514,7 +4688,11 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
return err; return err;
} }
static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) /* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
* and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.txt
*/
static int selinux_socket_connect_helper(struct socket *sock,
struct sockaddr *address, int addrlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
...@@ -4525,10 +4703,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, ...@@ -4525,10 +4703,12 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
return err; return err;
/* /*
* If a TCP or DCCP socket, check name_connect permission for the port. * If a TCP, DCCP or SCTP socket, check name_connect permission
* for the port.
*/ */
if (sksec->sclass == SECCLASS_TCP_SOCKET || if (sksec->sclass == SECCLASS_TCP_SOCKET ||
sksec->sclass == SECCLASS_DCCP_SOCKET) { sksec->sclass == SECCLASS_DCCP_SOCKET ||
sksec->sclass == SECCLASS_SCTP_SOCKET) {
struct common_audit_data ad; struct common_audit_data ad;
struct lsm_network_audit net = {0,}; struct lsm_network_audit net = {0,};
struct sockaddr_in *addr4 = NULL; struct sockaddr_in *addr4 = NULL;
...@@ -4536,38 +4716,75 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, ...@@ -4536,38 +4716,75 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
unsigned short snum; unsigned short snum;
u32 sid, perm; u32 sid, perm;
if (sk->sk_family == PF_INET) { /* sctp_connectx(3) calls via selinux_sctp_bind_connect()
* that validates multiple connect addresses. Because of this
* need to check address->sa_family as it is possible to have
* sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
*/
switch (address->sa_family) {
case AF_INET:
addr4 = (struct sockaddr_in *)address; addr4 = (struct sockaddr_in *)address;
if (addrlen < sizeof(struct sockaddr_in)) if (addrlen < sizeof(struct sockaddr_in))
return -EINVAL; return -EINVAL;
snum = ntohs(addr4->sin_port); snum = ntohs(addr4->sin_port);
} else { break;
case AF_INET6:
addr6 = (struct sockaddr_in6 *)address; addr6 = (struct sockaddr_in6 *)address;
if (addrlen < SIN6_LEN_RFC2133) if (addrlen < SIN6_LEN_RFC2133)
return -EINVAL; return -EINVAL;
snum = ntohs(addr6->sin6_port); snum = ntohs(addr6->sin6_port);
break;
default:
/* Note that SCTP services expect -EINVAL, whereas
* others expect -EAFNOSUPPORT.
*/
if (sksec->sclass == SECCLASS_SCTP_SOCKET)
return -EINVAL;
else
return -EAFNOSUPPORT;
} }
err = sel_netport_sid(sk->sk_protocol, snum, &sid); err = sel_netport_sid(sk->sk_protocol, snum, &sid);
if (err) if (err)
goto out; return err;
perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? switch (sksec->sclass) {
TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; case SECCLASS_TCP_SOCKET:
perm = TCP_SOCKET__NAME_CONNECT;
break;
case SECCLASS_DCCP_SOCKET:
perm = DCCP_SOCKET__NAME_CONNECT;
break;
case SECCLASS_SCTP_SOCKET:
perm = SCTP_SOCKET__NAME_CONNECT;
break;
}
ad.type = LSM_AUDIT_DATA_NET; ad.type = LSM_AUDIT_DATA_NET;
ad.u.net = &net; ad.u.net = &net;
ad.u.net->dport = htons(snum); ad.u.net->dport = htons(snum);
ad.u.net->family = sk->sk_family; ad.u.net->family = sk->sk_family;
err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad); err = avc_has_perm(&selinux_state,
sksec->sid, sid, sksec->sclass, perm, &ad);
if (err) if (err)
goto out; return err;
} }
err = selinux_netlbl_socket_connect(sk, address); return 0;
}
out: /* Supports connect(2), see comments in selinux_socket_connect_helper() */
return err; static int selinux_socket_connect(struct socket *sock,
struct sockaddr *address, int addrlen)
{
int err;
struct sock *sk = sock->sk;
err = selinux_socket_connect_helper(sock, address, addrlen);
if (err)
return err;
return selinux_netlbl_socket_connect(sk, address);
} }
static int selinux_socket_listen(struct socket *sock, int backlog) static int selinux_socket_listen(struct socket *sock, int backlog)
...@@ -4660,7 +4877,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock, ...@@ -4660,7 +4877,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
ad.u.net = &net; ad.u.net = &net;
ad.u.net->sk = other; ad.u.net->sk = other;
err = avc_has_perm(sksec_sock->sid, sksec_other->sid, err = avc_has_perm(&selinux_state,
sksec_sock->sid, sksec_other->sid,
sksec_other->sclass, sksec_other->sclass,
UNIX_STREAM_SOCKET__CONNECTTO, &ad); UNIX_STREAM_SOCKET__CONNECTTO, &ad);
if (err) if (err)
...@@ -4668,8 +4886,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock, ...@@ -4668,8 +4886,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
/* server child socket */ /* server child socket */
sksec_new->peer_sid = sksec_sock->sid; sksec_new->peer_sid = sksec_sock->sid;
err = security_sid_mls_copy(sksec_other->sid, sksec_sock->sid, err = security_sid_mls_copy(&selinux_state, sksec_other->sid,
&sksec_new->sid); sksec_sock->sid, &sksec_new->sid);
if (err) if (err)
return err; return err;
...@@ -4691,7 +4909,8 @@ static int selinux_socket_unix_may_send(struct socket *sock, ...@@ -4691,7 +4909,8 @@ static int selinux_socket_unix_may_send(struct socket *sock,
ad.u.net = &net; ad.u.net = &net;
ad.u.net->sk = other->sk; ad.u.net->sk = other->sk;
return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO, return avc_has_perm(&selinux_state,
ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
&ad); &ad);
} }
...@@ -4706,7 +4925,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, ...@@ -4706,7 +4925,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netif_sid(ns, ifindex, &if_sid); err = sel_netif_sid(ns, ifindex, &if_sid);
if (err) if (err)
return err; return err;
err = avc_has_perm(peer_sid, if_sid, err = avc_has_perm(&selinux_state,
peer_sid, if_sid,
SECCLASS_NETIF, NETIF__INGRESS, ad); SECCLASS_NETIF, NETIF__INGRESS, ad);
if (err) if (err)
return err; return err;
...@@ -4714,7 +4934,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, ...@@ -4714,7 +4934,8 @@ static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
err = sel_netnode_sid(addrp, family, &node_sid); err = sel_netnode_sid(addrp, family, &node_sid);
if (err) if (err)
return err; return err;
return avc_has_perm(peer_sid, node_sid, return avc_has_perm(&selinux_state,
peer_sid, node_sid,
SECCLASS_NODE, NODE__RECVFROM, ad); SECCLASS_NODE, NODE__RECVFROM, ad);
} }
...@@ -4737,7 +4958,8 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, ...@@ -4737,7 +4958,8 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
return err; return err;
if (selinux_secmark_enabled()) { if (selinux_secmark_enabled()) {
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, err = avc_has_perm(&selinux_state,
sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad); PACKET__RECV, &ad);
if (err) if (err)
return err; return err;
...@@ -4774,7 +4996,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -4774,7 +4996,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* to the selinux_sock_rcv_skb_compat() function to deal with the * to the selinux_sock_rcv_skb_compat() function to deal with the
* special handling. We do this in an attempt to keep this function * special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */ * as fast and as clean as possible. */
if (!selinux_policycap_netpeer) if (!selinux_policycap_netpeer())
return selinux_sock_rcv_skb_compat(sk, skb, family); return selinux_sock_rcv_skb_compat(sk, skb, family);
secmark_active = selinux_secmark_enabled(); secmark_active = selinux_secmark_enabled();
...@@ -4802,7 +5024,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -4802,7 +5024,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
selinux_netlbl_err(skb, family, err, 0); selinux_netlbl_err(skb, family, err, 0);
return err; return err;
} }
err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, err = avc_has_perm(&selinux_state,
sk_sid, peer_sid, SECCLASS_PEER,
PEER__RECV, &ad); PEER__RECV, &ad);
if (err) { if (err) {
selinux_netlbl_err(skb, family, err, 0); selinux_netlbl_err(skb, family, err, 0);
...@@ -4811,7 +5034,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) ...@@ -4811,7 +5034,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
} }
if (secmark_active) { if (secmark_active) {
err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, err = avc_has_perm(&selinux_state,
sk_sid, skb->secmark, SECCLASS_PACKET,
PACKET__RECV, &ad); PACKET__RECV, &ad);
if (err) if (err)
return err; return err;
...@@ -4830,12 +5054,14 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op ...@@ -4830,12 +5054,14 @@ static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *op
u32 peer_sid = SECSID_NULL; u32 peer_sid = SECSID_NULL;
if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET || if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
sksec->sclass == SECCLASS_TCP_SOCKET) sksec->sclass == SECCLASS_TCP_SOCKET ||
sksec->sclass == SECCLASS_SCTP_SOCKET)
peer_sid = sksec->peer_sid; peer_sid = sksec->peer_sid;
if (peer_sid == SECSID_NULL) if (peer_sid == SECSID_NULL)
return -ENOPROTOOPT; return -ENOPROTOOPT;
err = security_sid_to_context(peer_sid, &scontext, &scontext_len); err = security_sid_to_context(&selinux_state, peer_sid, &scontext,
&scontext_len);
if (err) if (err)
return err; return err;
...@@ -4943,6 +5169,172 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent) ...@@ -4943,6 +5169,172 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
sksec->sclass = isec->sclass; sksec->sclass = isec->sclass;
} }
/* Called whenever SCTP receives an INIT chunk. This happens when an incoming
* connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association
* already present).
*/
static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
struct sk_buff *skb)
{
struct sk_security_struct *sksec = ep->base.sk->sk_security;
struct common_audit_data ad;
struct lsm_network_audit net = {0,};
u8 peerlbl_active;
u32 peer_sid = SECINITSID_UNLABELED;
u32 conn_sid;
int err = 0;
if (!selinux_policycap_extsockclass())
return 0;
peerlbl_active = selinux_peerlbl_enabled();
if (peerlbl_active) {
/* This will return peer_sid = SECSID_NULL if there are
* no peer labels, see security_net_peersid_resolve().
*/
err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family,
&peer_sid);
if (err)
return err;
if (peer_sid == SECSID_NULL)
peer_sid = SECINITSID_UNLABELED;
}
if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
sksec->sctp_assoc_state = SCTP_ASSOC_SET;
/* Here as first association on socket. As the peer SID
* was allowed by peer recv (and the netif/node checks),
* then it is approved by policy and used as the primary
* peer SID for getpeercon(3).
*/
sksec->peer_sid = peer_sid;
} else if (sksec->peer_sid != peer_sid) {
/* Other association peer SIDs are checked to enforce
* consistency among the peer SIDs.
*/
ad.type = LSM_AUDIT_DATA_NET;
ad.u.net = &net;
ad.u.net->sk = ep->base.sk;
err = avc_has_perm(&selinux_state,
sksec->peer_sid, peer_sid, sksec->sclass,
SCTP_SOCKET__ASSOCIATION, &ad);
if (err)
return err;
}
/* Compute the MLS component for the connection and store
* the information in ep. This will be used by SCTP TCP type
* sockets and peeled off connections as they cause a new
* socket to be generated. selinux_sctp_sk_clone() will then
* plug this into the new socket.
*/
err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid);
if (err)
return err;
ep->secid = conn_sid;
ep->peer_secid = peer_sid;
/* Set any NetLabel labels including CIPSO/CALIPSO options. */
return selinux_netlbl_sctp_assoc_request(ep, skb);
}
/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
* based on their @optname.
*/
static int selinux_sctp_bind_connect(struct sock *sk, int optname,
struct sockaddr *address,
int addrlen)
{
int len, err = 0, walk_size = 0;
void *addr_buf;
struct sockaddr *addr;
struct socket *sock;
if (!selinux_policycap_extsockclass())
return 0;
/* Process one or more addresses that may be IPv4 or IPv6 */
sock = sk->sk_socket;
addr_buf = address;
while (walk_size < addrlen) {
addr = addr_buf;
switch (addr->sa_family) {
case AF_INET:
len = sizeof(struct sockaddr_in);
break;
case AF_INET6:
len = sizeof(struct sockaddr_in6);
break;
default:
return -EAFNOSUPPORT;
}
err = -EINVAL;
switch (optname) {
/* Bind checks */
case SCTP_PRIMARY_ADDR:
case SCTP_SET_PEER_PRIMARY_ADDR:
case SCTP_SOCKOPT_BINDX_ADD:
err = selinux_socket_bind(sock, addr, len);
break;
/* Connect checks */
case SCTP_SOCKOPT_CONNECTX:
case SCTP_PARAM_SET_PRIMARY:
case SCTP_PARAM_ADD_IP:
case SCTP_SENDMSG_CONNECT:
err = selinux_socket_connect_helper(sock, addr, len);
if (err)
return err;
/* As selinux_sctp_bind_connect() is called by the
* SCTP protocol layer, the socket is already locked,
* therefore selinux_netlbl_socket_connect_locked() is
* is called here. The situations handled are:
* sctp_connectx(3), sctp_sendmsg(3), sendmsg(2),
* whenever a new IP address is added or when a new
* primary address is selected.
* Note that an SCTP connect(2) call happens before
* the SCTP protocol layer and is handled via
* selinux_socket_connect().
*/
err = selinux_netlbl_socket_connect_locked(sk, addr);
break;
}
if (err)
return err;
addr_buf += len;
walk_size += len;
}
return 0;
}
/* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */
static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
struct sock *newsk)
{
struct sk_security_struct *sksec = sk->sk_security;
struct sk_security_struct *newsksec = newsk->sk_security;
/* If policy does not support SECCLASS_SCTP_SOCKET then call
* the non-sctp clone version.
*/
if (!selinux_policycap_extsockclass())
return selinux_sk_clone_security(sk, newsk);
newsksec->sid = ep->secid;
newsksec->peer_sid = ep->peer_secid;
newsksec->sclass = sksec->sclass;
selinux_netlbl_sctp_sk_clone(sk, newsk);
}
static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct request_sock *req) struct request_sock *req)
{ {
...@@ -5001,7 +5393,9 @@ static int selinux_secmark_relabel_packet(u32 sid) ...@@ -5001,7 +5393,9 @@ static int selinux_secmark_relabel_packet(u32 sid)
__tsec = current_security(); __tsec = current_security();
tsid = __tsec->sid; tsid = __tsec->sid;
return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL); return avc_has_perm(&selinux_state,
tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
NULL);
} }
static void selinux_secmark_refcount_inc(void) static void selinux_secmark_refcount_inc(void)
...@@ -5049,7 +5443,8 @@ static int selinux_tun_dev_create(void) ...@@ -5049,7 +5443,8 @@ static int selinux_tun_dev_create(void)
* connections unlike traditional sockets - check the TUN driver to * connections unlike traditional sockets - check the TUN driver to
* get a better understanding of why this socket is special */ * get a better understanding of why this socket is special */
return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, return avc_has_perm(&selinux_state,
sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
NULL); NULL);
} }
...@@ -5057,7 +5452,8 @@ static int selinux_tun_dev_attach_queue(void *security) ...@@ -5057,7 +5452,8 @@ static int selinux_tun_dev_attach_queue(void *security)
{ {
struct tun_security_struct *tunsec = security; struct tun_security_struct *tunsec = security;
return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET, return avc_has_perm(&selinux_state,
current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__ATTACH_QUEUE, NULL); TUN_SOCKET__ATTACH_QUEUE, NULL);
} }
...@@ -5085,11 +5481,13 @@ static int selinux_tun_dev_open(void *security) ...@@ -5085,11 +5481,13 @@ static int selinux_tun_dev_open(void *security)
u32 sid = current_sid(); u32 sid = current_sid();
int err; int err;
err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET, err = avc_has_perm(&selinux_state,
sid, tunsec->sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELFROM, NULL); TUN_SOCKET__RELABELFROM, NULL);
if (err) if (err)
return err; return err;
err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, err = avc_has_perm(&selinux_state,
sid, sid, SECCLASS_TUN_SOCKET,
TUN_SOCKET__RELABELTO, NULL); TUN_SOCKET__RELABELTO, NULL);
if (err) if (err)
return err; return err;
...@@ -5120,7 +5518,8 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) ...@@ -5120,7 +5518,8 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
sk->sk_protocol, nlh->nlmsg_type, sk->sk_protocol, nlh->nlmsg_type,
secclass_map[sksec->sclass - 1].name, secclass_map[sksec->sclass - 1].name,
task_pid_nr(current), current->comm); task_pid_nr(current), current->comm);
if (!selinux_enforcing || security_get_allow_unknown()) if (!enforcing_enabled(&selinux_state) ||
security_get_allow_unknown(&selinux_state))
err = 0; err = 0;
} }
...@@ -5150,7 +5549,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, ...@@ -5150,7 +5549,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
u8 netlbl_active; u8 netlbl_active;
u8 peerlbl_active; u8 peerlbl_active;
if (!selinux_policycap_netpeer) if (!selinux_policycap_netpeer())
return NF_ACCEPT; return NF_ACCEPT;
secmark_active = selinux_secmark_enabled(); secmark_active = selinux_secmark_enabled();
...@@ -5179,7 +5578,8 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, ...@@ -5179,7 +5578,8 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
} }
if (secmark_active) if (secmark_active)
if (avc_has_perm(peer_sid, skb->secmark, if (avc_has_perm(&selinux_state,
peer_sid, skb->secmark,
SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
return NF_DROP; return NF_DROP;
...@@ -5291,7 +5691,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, ...@@ -5291,7 +5691,8 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
return NF_DROP; return NF_DROP;
if (selinux_secmark_enabled()) if (selinux_secmark_enabled())
if (avc_has_perm(sksec->sid, skb->secmark, if (avc_has_perm(&selinux_state,
sksec->sid, skb->secmark,
SECCLASS_PACKET, PACKET__SEND, &ad)) SECCLASS_PACKET, PACKET__SEND, &ad))
return NF_DROP_ERR(-ECONNREFUSED); return NF_DROP_ERR(-ECONNREFUSED);
...@@ -5319,7 +5720,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, ...@@ -5319,7 +5720,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
* to the selinux_ip_postroute_compat() function to deal with the * to the selinux_ip_postroute_compat() function to deal with the
* special handling. We do this in an attempt to keep this function * special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */ * as fast and as clean as possible. */
if (!selinux_policycap_netpeer) if (!selinux_policycap_netpeer())
return selinux_ip_postroute_compat(skb, ifindex, family); return selinux_ip_postroute_compat(skb, ifindex, family);
secmark_active = selinux_secmark_enabled(); secmark_active = selinux_secmark_enabled();
...@@ -5414,7 +5815,8 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, ...@@ -5414,7 +5815,8 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
return NF_DROP; return NF_DROP;
if (secmark_active) if (secmark_active)
if (avc_has_perm(peer_sid, skb->secmark, if (avc_has_perm(&selinux_state,
peer_sid, skb->secmark,
SECCLASS_PACKET, secmark_perm, &ad)) SECCLASS_PACKET, secmark_perm, &ad))
return NF_DROP_ERR(-ECONNREFUSED); return NF_DROP_ERR(-ECONNREFUSED);
...@@ -5424,13 +5826,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, ...@@ -5424,13 +5826,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid)) if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
return NF_DROP; return NF_DROP;
if (avc_has_perm(peer_sid, if_sid, if (avc_has_perm(&selinux_state,
peer_sid, if_sid,
SECCLASS_NETIF, NETIF__EGRESS, &ad)) SECCLASS_NETIF, NETIF__EGRESS, &ad))
return NF_DROP_ERR(-ECONNREFUSED); return NF_DROP_ERR(-ECONNREFUSED);
if (sel_netnode_sid(addrp, family, &node_sid)) if (sel_netnode_sid(addrp, family, &node_sid))
return NF_DROP; return NF_DROP;
if (avc_has_perm(peer_sid, node_sid, if (avc_has_perm(&selinux_state,
peer_sid, node_sid,
SECCLASS_NODE, NODE__SENDTO, &ad)) SECCLASS_NODE, NODE__SENDTO, &ad))
return NF_DROP_ERR(-ECONNREFUSED); return NF_DROP_ERR(-ECONNREFUSED);
} }
...@@ -5518,7 +5922,8 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, ...@@ -5518,7 +5922,8 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = ipc_perms->key; ad.u.ipc_id = ipc_perms->key;
return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); return avc_has_perm(&selinux_state,
sid, isec->sid, isec->sclass, perms, &ad);
} }
static int selinux_msg_msg_alloc_security(struct msg_msg *msg) static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
...@@ -5548,7 +5953,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) ...@@ -5548,7 +5953,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key; ad.u.ipc_id = msq->key;
rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, rc = avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_MSGQ,
MSGQ__CREATE, &ad); MSGQ__CREATE, &ad);
if (rc) { if (rc) {
ipc_free_security(msq); ipc_free_security(msq);
...@@ -5573,7 +5979,8 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) ...@@ -5573,7 +5979,8 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key; ad.u.ipc_id = msq->key;
return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, return avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ASSOCIATE, &ad); MSGQ__ASSOCIATE, &ad);
} }
...@@ -5586,7 +5993,8 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd) ...@@ -5586,7 +5993,8 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
case IPC_INFO: case IPC_INFO:
case MSG_INFO: case MSG_INFO:
/* No specific object, just general system-wide information. */ /* No specific object, just general system-wide information. */
return avc_has_perm(current_sid(), SECINITSID_KERNEL, return avc_has_perm(&selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT: case IPC_STAT:
case MSG_STAT: case MSG_STAT:
...@@ -5625,8 +6033,8 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m ...@@ -5625,8 +6033,8 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
* Compute new sid based on current process and * Compute new sid based on current process and
* message queue this message will be stored in * message queue this message will be stored in
*/ */
rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, rc = security_transition_sid(&selinux_state, sid, isec->sid,
NULL, &msec->sid); SECCLASS_MSG, NULL, &msec->sid);
if (rc) if (rc)
return rc; return rc;
} }
...@@ -5635,15 +6043,18 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m ...@@ -5635,15 +6043,18 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
ad.u.ipc_id = msq->key; ad.u.ipc_id = msq->key;
/* Can this process write to the queue? */ /* Can this process write to the queue? */
rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, rc = avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_MSGQ,
MSGQ__WRITE, &ad); MSGQ__WRITE, &ad);
if (!rc) if (!rc)
/* Can this process send the message */ /* Can this process send the message */
rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG, rc = avc_has_perm(&selinux_state,
sid, msec->sid, SECCLASS_MSG,
MSG__SEND, &ad); MSG__SEND, &ad);
if (!rc) if (!rc)
/* Can the message be put in the queue? */ /* Can the message be put in the queue? */
rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ, rc = avc_has_perm(&selinux_state,
msec->sid, isec->sid, SECCLASS_MSGQ,
MSGQ__ENQUEUE, &ad); MSGQ__ENQUEUE, &ad);
return rc; return rc;
...@@ -5665,10 +6076,12 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m ...@@ -5665,10 +6076,12 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key; ad.u.ipc_id = msq->key;
rc = avc_has_perm(sid, isec->sid, rc = avc_has_perm(&selinux_state,
sid, isec->sid,
SECCLASS_MSGQ, MSGQ__READ, &ad); SECCLASS_MSGQ, MSGQ__READ, &ad);
if (!rc) if (!rc)
rc = avc_has_perm(sid, msec->sid, rc = avc_has_perm(&selinux_state,
sid, msec->sid,
SECCLASS_MSG, MSG__RECEIVE, &ad); SECCLASS_MSG, MSG__RECEIVE, &ad);
return rc; return rc;
} }
...@@ -5690,7 +6103,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp) ...@@ -5690,7 +6103,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key; ad.u.ipc_id = shp->key;
rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, rc = avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_SHM,
SHM__CREATE, &ad); SHM__CREATE, &ad);
if (rc) { if (rc) {
ipc_free_security(shp); ipc_free_security(shp);
...@@ -5715,7 +6129,8 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg) ...@@ -5715,7 +6129,8 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key; ad.u.ipc_id = shp->key;
return avc_has_perm(sid, isec->sid, SECCLASS_SHM, return avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_SHM,
SHM__ASSOCIATE, &ad); SHM__ASSOCIATE, &ad);
} }
...@@ -5729,7 +6144,8 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd) ...@@ -5729,7 +6144,8 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
case IPC_INFO: case IPC_INFO:
case SHM_INFO: case SHM_INFO:
/* No specific object, just general system-wide information. */ /* No specific object, just general system-wide information. */
return avc_has_perm(current_sid(), SECINITSID_KERNEL, return avc_has_perm(&selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case IPC_STAT: case IPC_STAT:
case SHM_STAT: case SHM_STAT:
...@@ -5783,7 +6199,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma) ...@@ -5783,7 +6199,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key; ad.u.ipc_id = sma->key;
rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, rc = avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_SEM,
SEM__CREATE, &ad); SEM__CREATE, &ad);
if (rc) { if (rc) {
ipc_free_security(sma); ipc_free_security(sma);
...@@ -5808,7 +6225,8 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg) ...@@ -5808,7 +6225,8 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
ad.type = LSM_AUDIT_DATA_IPC; ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key; ad.u.ipc_id = sma->key;
return avc_has_perm(sid, isec->sid, SECCLASS_SEM, return avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_SEM,
SEM__ASSOCIATE, &ad); SEM__ASSOCIATE, &ad);
} }
...@@ -5822,7 +6240,8 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd) ...@@ -5822,7 +6240,8 @@ static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
case IPC_INFO: case IPC_INFO:
case SEM_INFO: case SEM_INFO:
/* No specific object, just general system-wide information. */ /* No specific object, just general system-wide information. */
return avc_has_perm(current_sid(), SECINITSID_KERNEL, return avc_has_perm(&selinux_state,
current_sid(), SECINITSID_KERNEL,
SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
case GETPID: case GETPID:
case GETNCNT: case GETNCNT:
...@@ -5908,7 +6327,8 @@ static int selinux_getprocattr(struct task_struct *p, ...@@ -5908,7 +6327,8 @@ static int selinux_getprocattr(struct task_struct *p,
__tsec = __task_cred(p)->security; __tsec = __task_cred(p)->security;
if (current != p) { if (current != p) {
error = avc_has_perm(current_sid(), __tsec->sid, error = avc_has_perm(&selinux_state,
current_sid(), __tsec->sid,
SECCLASS_PROCESS, PROCESS__GETATTR, NULL); SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
if (error) if (error)
goto bad; goto bad;
...@@ -5935,7 +6355,7 @@ static int selinux_getprocattr(struct task_struct *p, ...@@ -5935,7 +6355,7 @@ static int selinux_getprocattr(struct task_struct *p,
if (!sid) if (!sid)
return 0; return 0;
error = security_sid_to_context(sid, value, &len); error = security_sid_to_context(&selinux_state, sid, value, &len);
if (error) if (error)
return error; return error;
return len; return len;
...@@ -5957,19 +6377,24 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) ...@@ -5957,19 +6377,24 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
* Basic control over ability to set these attributes at all. * Basic control over ability to set these attributes at all.
*/ */
if (!strcmp(name, "exec")) if (!strcmp(name, "exec"))
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETEXEC, NULL); PROCESS__SETEXEC, NULL);
else if (!strcmp(name, "fscreate")) else if (!strcmp(name, "fscreate"))
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETFSCREATE, NULL); PROCESS__SETFSCREATE, NULL);
else if (!strcmp(name, "keycreate")) else if (!strcmp(name, "keycreate"))
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETKEYCREATE, NULL); PROCESS__SETKEYCREATE, NULL);
else if (!strcmp(name, "sockcreate")) else if (!strcmp(name, "sockcreate"))
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETSOCKCREATE, NULL); PROCESS__SETSOCKCREATE, NULL);
else if (!strcmp(name, "current")) else if (!strcmp(name, "current"))
error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS, error = avc_has_perm(&selinux_state,
mysid, mysid, SECCLASS_PROCESS,
PROCESS__SETCURRENT, NULL); PROCESS__SETCURRENT, NULL);
else else
error = -EINVAL; error = -EINVAL;
...@@ -5982,7 +6407,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) ...@@ -5982,7 +6407,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
str[size-1] = 0; str[size-1] = 0;
size--; size--;
} }
error = security_context_to_sid(value, size, &sid, GFP_KERNEL); error = security_context_to_sid(&selinux_state, value, size,
&sid, GFP_KERNEL);
if (error == -EINVAL && !strcmp(name, "fscreate")) { if (error == -EINVAL && !strcmp(name, "fscreate")) {
if (!has_cap_mac_admin(true)) { if (!has_cap_mac_admin(true)) {
struct audit_buffer *ab; struct audit_buffer *ab;
...@@ -6001,8 +6427,9 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) ...@@ -6001,8 +6427,9 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
return error; return error;
} }
error = security_context_to_sid_force(value, size, error = security_context_to_sid_force(
&sid); &selinux_state,
value, size, &sid);
} }
if (error) if (error)
return error; return error;
...@@ -6024,7 +6451,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) ...@@ -6024,7 +6451,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
} else if (!strcmp(name, "fscreate")) { } else if (!strcmp(name, "fscreate")) {
tsec->create_sid = sid; tsec->create_sid = sid;
} else if (!strcmp(name, "keycreate")) { } else if (!strcmp(name, "keycreate")) {
error = avc_has_perm(mysid, sid, SECCLASS_KEY, KEY__CREATE, error = avc_has_perm(&selinux_state,
mysid, sid, SECCLASS_KEY, KEY__CREATE,
NULL); NULL);
if (error) if (error)
goto abort_change; goto abort_change;
...@@ -6039,13 +6467,15 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) ...@@ -6039,13 +6467,15 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
/* Only allow single threaded processes to change context */ /* Only allow single threaded processes to change context */
error = -EPERM; error = -EPERM;
if (!current_is_single_threaded()) { if (!current_is_single_threaded()) {
error = security_bounded_transition(tsec->sid, sid); error = security_bounded_transition(&selinux_state,
tsec->sid, sid);
if (error) if (error)
goto abort_change; goto abort_change;
} }
/* Check permissions for the transition. */ /* Check permissions for the transition. */
error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, error = avc_has_perm(&selinux_state,
tsec->sid, sid, SECCLASS_PROCESS,
PROCESS__DYNTRANSITION, NULL); PROCESS__DYNTRANSITION, NULL);
if (error) if (error)
goto abort_change; goto abort_change;
...@@ -6054,7 +6484,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size) ...@@ -6054,7 +6484,8 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
Otherwise, leave SID unchanged and fail. */ Otherwise, leave SID unchanged and fail. */
ptsid = ptrace_parent_sid(); ptsid = ptrace_parent_sid();
if (ptsid != 0) { if (ptsid != 0) {
error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, error = avc_has_perm(&selinux_state,
ptsid, sid, SECCLASS_PROCESS,
PROCESS__PTRACE, NULL); PROCESS__PTRACE, NULL);
if (error) if (error)
goto abort_change; goto abort_change;
...@@ -6081,12 +6512,14 @@ static int selinux_ismaclabel(const char *name) ...@@ -6081,12 +6512,14 @@ static int selinux_ismaclabel(const char *name)
static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{ {
return security_sid_to_context(secid, secdata, seclen); return security_sid_to_context(&selinux_state, secid,
secdata, seclen);
} }
static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{ {
return security_context_to_sid(secdata, seclen, secid, GFP_KERNEL); return security_context_to_sid(&selinux_state, secdata, seclen,
secid, GFP_KERNEL);
} }
static void selinux_release_secctx(char *secdata, u32 seclen) static void selinux_release_secctx(char *secdata, u32 seclen)
...@@ -6178,7 +6611,8 @@ static int selinux_key_permission(key_ref_t key_ref, ...@@ -6178,7 +6611,8 @@ static int selinux_key_permission(key_ref_t key_ref,
key = key_ref_to_ptr(key_ref); key = key_ref_to_ptr(key_ref);
ksec = key->security; ksec = key->security;
return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL); return avc_has_perm(&selinux_state,
sid, ksec->sid, SECCLASS_KEY, perm, NULL);
} }
static int selinux_key_getsecurity(struct key *key, char **_buffer) static int selinux_key_getsecurity(struct key *key, char **_buffer)
...@@ -6188,7 +6622,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer) ...@@ -6188,7 +6622,8 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
unsigned len; unsigned len;
int rc; int rc;
rc = security_sid_to_context(ksec->sid, &context, &len); rc = security_sid_to_context(&selinux_state, ksec->sid,
&context, &len);
if (!rc) if (!rc)
rc = len; rc = len;
*_buffer = context; *_buffer = context;
...@@ -6213,7 +6648,8 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val) ...@@ -6213,7 +6648,8 @@ static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
ibpkey.subnet_prefix = subnet_prefix; ibpkey.subnet_prefix = subnet_prefix;
ibpkey.pkey = pkey_val; ibpkey.pkey = pkey_val;
ad.u.ibpkey = &ibpkey; ad.u.ibpkey = &ibpkey;
return avc_has_perm(sec->sid, sid, return avc_has_perm(&selinux_state,
sec->sid, sid,
SECCLASS_INFINIBAND_PKEY, SECCLASS_INFINIBAND_PKEY,
INFINIBAND_PKEY__ACCESS, &ad); INFINIBAND_PKEY__ACCESS, &ad);
} }
...@@ -6227,7 +6663,8 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name, ...@@ -6227,7 +6663,8 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
struct ib_security_struct *sec = ib_sec; struct ib_security_struct *sec = ib_sec;
struct lsm_ibendport_audit ibendport; struct lsm_ibendport_audit ibendport;
err = security_ib_endport_sid(dev_name, port_num, &sid); err = security_ib_endport_sid(&selinux_state, dev_name, port_num,
&sid);
if (err) if (err)
return err; return err;
...@@ -6236,7 +6673,8 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name, ...@@ -6236,7 +6673,8 @@ static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name)); strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name));
ibendport.port = port_num; ibendport.port = port_num;
ad.u.ibendport = &ibendport; ad.u.ibendport = &ibendport;
return avc_has_perm(sec->sid, sid, return avc_has_perm(&selinux_state,
sec->sid, sid,
SECCLASS_INFINIBAND_ENDPORT, SECCLASS_INFINIBAND_ENDPORT,
INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad); INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
} }
...@@ -6269,11 +6707,13 @@ static int selinux_bpf(int cmd, union bpf_attr *attr, ...@@ -6269,11 +6707,13 @@ static int selinux_bpf(int cmd, union bpf_attr *attr,
switch (cmd) { switch (cmd) {
case BPF_MAP_CREATE: case BPF_MAP_CREATE:
ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, ret = avc_has_perm(&selinux_state,
sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
NULL); NULL);
break; break;
case BPF_PROG_LOAD: case BPF_PROG_LOAD:
ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, ret = avc_has_perm(&selinux_state,
sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
NULL); NULL);
break; break;
default: default:
...@@ -6313,14 +6753,16 @@ static int bpf_fd_pass(struct file *file, u32 sid) ...@@ -6313,14 +6753,16 @@ static int bpf_fd_pass(struct file *file, u32 sid)
if (file->f_op == &bpf_map_fops) { if (file->f_op == &bpf_map_fops) {
map = file->private_data; map = file->private_data;
bpfsec = map->security; bpfsec = map->security;
ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, ret = avc_has_perm(&selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(file->f_mode), NULL); bpf_map_fmode_to_av(file->f_mode), NULL);
if (ret) if (ret)
return ret; return ret;
} else if (file->f_op == &bpf_prog_fops) { } else if (file->f_op == &bpf_prog_fops) {
prog = file->private_data; prog = file->private_data;
bpfsec = prog->aux->security; bpfsec = prog->aux->security;
ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, ret = avc_has_perm(&selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL); BPF__PROG_RUN, NULL);
if (ret) if (ret)
return ret; return ret;
...@@ -6334,7 +6776,8 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) ...@@ -6334,7 +6776,8 @@ static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
struct bpf_security_struct *bpfsec; struct bpf_security_struct *bpfsec;
bpfsec = map->security; bpfsec = map->security;
return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, return avc_has_perm(&selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
bpf_map_fmode_to_av(fmode), NULL); bpf_map_fmode_to_av(fmode), NULL);
} }
...@@ -6344,7 +6787,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog) ...@@ -6344,7 +6787,8 @@ static int selinux_bpf_prog(struct bpf_prog *prog)
struct bpf_security_struct *bpfsec; struct bpf_security_struct *bpfsec;
bpfsec = prog->aux->security; bpfsec = prog->aux->security;
return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, return avc_has_perm(&selinux_state,
sid, bpfsec->sid, SECCLASS_BPF,
BPF__PROG_RUN, NULL); BPF__PROG_RUN, NULL);
} }
...@@ -6563,6 +7007,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { ...@@ -6563,6 +7007,9 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security), LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid), LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
LSM_HOOK_INIT(sock_graft, selinux_sock_graft), LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request), LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone), LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established), LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
...@@ -6638,6 +7085,12 @@ static __init int selinux_init(void) ...@@ -6638,6 +7085,12 @@ static __init int selinux_init(void)
printk(KERN_INFO "SELinux: Initializing.\n"); printk(KERN_INFO "SELinux: Initializing.\n");
memset(&selinux_state, 0, sizeof(selinux_state));
enforcing_set(&selinux_state, selinux_enforcing_boot);
selinux_state.checkreqprot = selinux_checkreqprot_boot;
selinux_ss_init(&selinux_state.ss);
selinux_avc_init(&selinux_state.avc);
/* Set the security state for the initial task. */ /* Set the security state for the initial task. */
cred_init_security(); cred_init_security();
...@@ -6651,6 +7104,12 @@ static __init int selinux_init(void) ...@@ -6651,6 +7104,12 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
avc_init(); avc_init();
avtab_cache_init();
ebitmap_cache_init();
hashtab_cache_init();
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
...@@ -6659,7 +7118,7 @@ static __init int selinux_init(void) ...@@ -6659,7 +7118,7 @@ static __init int selinux_init(void)
if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET)) if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC LSM notifier callback\n"); panic("SELinux: Unable to register AVC LSM notifier callback\n");
if (selinux_enforcing) if (selinux_enforcing_boot)
printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n");
else else
printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
...@@ -6780,23 +7239,22 @@ static void selinux_nf_ip_exit(void) ...@@ -6780,23 +7239,22 @@ static void selinux_nf_ip_exit(void)
#endif /* CONFIG_NETFILTER */ #endif /* CONFIG_NETFILTER */
#ifdef CONFIG_SECURITY_SELINUX_DISABLE #ifdef CONFIG_SECURITY_SELINUX_DISABLE
static int selinux_disabled; int selinux_disable(struct selinux_state *state)
int selinux_disable(void)
{ {
if (ss_initialized) { if (state->initialized) {
/* Not permitted after initial policy load. */ /* Not permitted after initial policy load. */
return -EINVAL; return -EINVAL;
} }
if (selinux_disabled) { if (state->disabled) {
/* Only do this once. */ /* Only do this once. */
return -EINVAL; return -EINVAL;
} }
state->disabled = 1;
printk(KERN_INFO "SELinux: Disabled at runtime.\n"); printk(KERN_INFO "SELinux: Disabled at runtime.\n");
selinux_disabled = 1;
selinux_enabled = 0; selinux_enabled = 0;
security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks)); security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
......
...@@ -152,7 +152,8 @@ static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid) ...@@ -152,7 +152,8 @@ static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
return 0; return 0;
} }
ret = security_ib_pkey_sid(subnet_prefix, pkey_num, sid); ret = security_ib_pkey_sid(&selinux_state, subnet_prefix, pkey_num,
sid);
if (ret) if (ret)
goto out; goto out;
......
...@@ -20,12 +20,6 @@ ...@@ -20,12 +20,6 @@
#include "av_permissions.h" #include "av_permissions.h"
#include "security.h" #include "security.h"
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
extern int selinux_enforcing;
#else
#define selinux_enforcing 1
#endif
/* /*
* An entry in the AVC. * An entry in the AVC.
*/ */
...@@ -58,6 +52,7 @@ struct selinux_audit_data { ...@@ -58,6 +52,7 @@ struct selinux_audit_data {
u32 audited; u32 audited;
u32 denied; u32 denied;
int result; int result;
struct selinux_state *state;
}; };
/* /*
...@@ -102,7 +97,8 @@ static inline u32 avc_audit_required(u32 requested, ...@@ -102,7 +97,8 @@ static inline u32 avc_audit_required(u32 requested,
return audited; return audited;
} }
int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, int slow_avc_audit(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
u32 requested, u32 audited, u32 denied, int result, u32 requested, u32 audited, u32 denied, int result,
struct common_audit_data *a, struct common_audit_data *a,
unsigned flags); unsigned flags);
...@@ -127,7 +123,8 @@ int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, ...@@ -127,7 +123,8 @@ int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
* be performed under a lock, to allow the lock to be released * be performed under a lock, to allow the lock to be released
* before calling the auditing code. * before calling the auditing code.
*/ */
static inline int avc_audit(u32 ssid, u32 tsid, static inline int avc_audit(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, u32 requested,
struct av_decision *avd, struct av_decision *avd,
int result, int result,
...@@ -138,31 +135,35 @@ static inline int avc_audit(u32 ssid, u32 tsid, ...@@ -138,31 +135,35 @@ static inline int avc_audit(u32 ssid, u32 tsid,
audited = avc_audit_required(requested, avd, result, 0, &denied); audited = avc_audit_required(requested, avd, result, 0, &denied);
if (likely(!audited)) if (likely(!audited))
return 0; return 0;
return slow_avc_audit(ssid, tsid, tclass, return slow_avc_audit(state, ssid, tsid, tclass,
requested, audited, denied, result, requested, audited, denied, result,
a, flags); a, flags);
} }
#define AVC_STRICT 1 /* Ignore permissive mode. */ #define AVC_STRICT 1 /* Ignore permissive mode. */
#define AVC_EXTENDED_PERMS 2 /* update extended permissions */ #define AVC_EXTENDED_PERMS 2 /* update extended permissions */
int avc_has_perm_noaudit(u32 ssid, u32 tsid, int avc_has_perm_noaudit(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, u32 requested,
unsigned flags, unsigned flags,
struct av_decision *avd); struct av_decision *avd);
int avc_has_perm(u32 ssid, u32 tsid, int avc_has_perm(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, u32 requested,
struct common_audit_data *auditdata); struct common_audit_data *auditdata);
int avc_has_perm_flags(u32 ssid, u32 tsid, int avc_has_perm_flags(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested, u16 tclass, u32 requested,
struct common_audit_data *auditdata, struct common_audit_data *auditdata,
int flags); int flags);
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, int avc_has_extended_perms(struct selinux_state *state,
u8 driver, u8 perm, struct common_audit_data *ad); u32 ssid, u32 tsid, u16 tclass, u32 requested,
u8 driver, u8 perm, struct common_audit_data *ad);
u32 avc_policy_seqno(void); u32 avc_policy_seqno(struct selinux_state *state);
#define AVC_CALLBACK_GRANT 1 #define AVC_CALLBACK_GRANT 1
#define AVC_CALLBACK_TRY_REVOKE 2 #define AVC_CALLBACK_TRY_REVOKE 2
...@@ -177,8 +178,11 @@ u32 avc_policy_seqno(void); ...@@ -177,8 +178,11 @@ u32 avc_policy_seqno(void);
int avc_add_callback(int (*callback)(u32 event), u32 events); int avc_add_callback(int (*callback)(u32 event), u32 events);
/* Exported to selinuxfs */ /* Exported to selinuxfs */
int avc_get_hash_stats(char *page); struct selinux_avc;
extern unsigned int avc_cache_threshold; int avc_get_hash_stats(struct selinux_avc *avc, char *page);
unsigned int avc_get_cache_threshold(struct selinux_avc *avc);
void avc_set_cache_threshold(struct selinux_avc *avc,
unsigned int cache_threshold);
/* Attempt to free avc node cache */ /* Attempt to free avc node cache */
void avc_disable(void); void avc_disable(void);
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
#include "flask.h" #include "flask.h"
int avc_ss_reset(u32 seqno); struct selinux_avc;
int avc_ss_reset(struct selinux_avc *avc, u32 seqno);
/* Class/perm mapping support */ /* Class/perm mapping support */
struct security_class_mapping { struct security_class_mapping {
...@@ -19,11 +20,5 @@ struct security_class_mapping { ...@@ -19,11 +20,5 @@ struct security_class_mapping {
extern struct security_class_mapping secclass_map[]; extern struct security_class_mapping secclass_map[];
/*
* The security server must be initialized before
* any labeling or access decisions can be provided.
*/
extern int ss_initialized;
#endif /* _SELINUX_AVC_SS_H_ */ #endif /* _SELINUX_AVC_SS_H_ */
...@@ -176,7 +176,7 @@ struct security_class_mapping secclass_map[] = { ...@@ -176,7 +176,7 @@ struct security_class_mapping secclass_map[] = {
{ COMMON_CAP2_PERMS, NULL } }, { COMMON_CAP2_PERMS, NULL } },
{ "sctp_socket", { "sctp_socket",
{ COMMON_SOCK_PERMS, { COMMON_SOCK_PERMS,
"node_bind", NULL } }, "node_bind", "name_connect", "association", NULL } },
{ "icmp_socket", { "icmp_socket",
{ COMMON_SOCK_PERMS, { COMMON_SOCK_PERMS,
"node_bind", NULL } }, "node_bind", NULL } },
......
...@@ -13,10 +13,15 @@ ...@@ -13,10 +13,15 @@
#ifndef _SELINUX_CONDITIONAL_H_ #ifndef _SELINUX_CONDITIONAL_H_
#define _SELINUX_CONDITIONAL_H_ #define _SELINUX_CONDITIONAL_H_
int security_get_bools(int *len, char ***names, int **values); #include "security.h"
int security_set_bools(int len, int *values); int security_get_bools(struct selinux_state *state,
int *len, char ***names, int **values);
int security_get_bool_value(int index); int security_set_bools(struct selinux_state *state,
int len, int *values);
int security_get_bool_value(struct selinux_state *state,
int index);
#endif #endif
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/request_sock.h> #include <net/request_sock.h>
#include <net/sctp/structs.h>
#include "avc.h" #include "avc.h"
#include "objsec.h" #include "objsec.h"
...@@ -52,9 +53,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb, ...@@ -52,9 +53,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
u16 family, u16 family,
u32 sid); u32 sid);
int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
struct sk_buff *skb);
int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family); int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family);
void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family); void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family);
void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk);
int selinux_netlbl_socket_post_create(struct sock *sk, u16 family); int selinux_netlbl_socket_post_create(struct sock *sk, u16 family);
int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
struct sk_buff *skb, struct sk_buff *skb,
...@@ -64,6 +67,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, ...@@ -64,6 +67,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
int level, int level,
int optname); int optname);
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr); int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr);
int selinux_netlbl_socket_connect_locked(struct sock *sk,
struct sockaddr *addr);
#else #else
static inline void selinux_netlbl_cache_invalidate(void) static inline void selinux_netlbl_cache_invalidate(void)
...@@ -113,6 +118,11 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk, ...@@ -113,6 +118,11 @@ static inline int selinux_netlbl_conn_setsid(struct sock *sk,
return 0; return 0;
} }
static inline int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
struct sk_buff *skb)
{
return 0;
}
static inline int selinux_netlbl_inet_conn_request(struct request_sock *req, static inline int selinux_netlbl_inet_conn_request(struct request_sock *req,
u16 family) u16 family)
{ {
...@@ -122,6 +132,11 @@ static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) ...@@ -122,6 +132,11 @@ static inline void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
{ {
return; return;
} }
static inline void selinux_netlbl_sctp_sk_clone(struct sock *sk,
struct sock *newsk)
{
return;
}
static inline int selinux_netlbl_socket_post_create(struct sock *sk, static inline int selinux_netlbl_socket_post_create(struct sock *sk,
u16 family) u16 family)
{ {
...@@ -145,6 +160,11 @@ static inline int selinux_netlbl_socket_connect(struct sock *sk, ...@@ -145,6 +160,11 @@ static inline int selinux_netlbl_socket_connect(struct sock *sk,
{ {
return 0; return 0;
} }
static inline int selinux_netlbl_socket_connect_locked(struct sock *sk,
struct sockaddr *addr)
{
return 0;
}
#endif /* CONFIG_NETLABEL */ #endif /* CONFIG_NETLABEL */
#endif #endif
...@@ -130,6 +130,10 @@ struct sk_security_struct { ...@@ -130,6 +130,10 @@ struct sk_security_struct {
u32 sid; /* SID of this object */ u32 sid; /* SID of this object */
u32 peer_sid; /* SID of peer */ u32 peer_sid; /* SID of peer */
u16 sclass; /* sock security class */ u16 sclass; /* sock security class */
enum { /* SCTP association state */
SCTP_ASSOC_UNSET = 0,
SCTP_ASSOC_SET,
} sctp_assoc_state;
}; };
struct tun_security_struct { struct tun_security_struct {
...@@ -154,6 +158,4 @@ struct bpf_security_struct { ...@@ -154,6 +158,4 @@ struct bpf_security_struct {
u32 sid; /*SID of bpf obj creater*/ u32 sid; /*SID of bpf obj creater*/
}; };
extern unsigned int selinux_checkreqprot;
#endif /* _SELINUX_OBJSEC_H_ */ #endif /* _SELINUX_OBJSEC_H_ */
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <linux/dcache.h> #include <linux/dcache.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/refcount.h>
#include <linux/workqueue.h>
#include "flask.h" #include "flask.h"
#define SECSID_NULL 0x00000000 /* unspecified SID */ #define SECSID_NULL 0x00000000 /* unspecified SID */
...@@ -81,13 +83,6 @@ enum { ...@@ -81,13 +83,6 @@ enum {
extern char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX]; extern char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX];
extern int selinux_policycap_netpeer;
extern int selinux_policycap_openperm;
extern int selinux_policycap_extsockclass;
extern int selinux_policycap_alwaysnetwork;
extern int selinux_policycap_cgroupseclabel;
extern int selinux_policycap_nnp_nosuid_transition;
/* /*
* type_datum properties * type_datum properties
* available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
...@@ -98,13 +93,98 @@ extern int selinux_policycap_nnp_nosuid_transition; ...@@ -98,13 +93,98 @@ extern int selinux_policycap_nnp_nosuid_transition;
/* limitation of boundary depth */ /* limitation of boundary depth */
#define POLICYDB_BOUNDS_MAXDEPTH 4 #define POLICYDB_BOUNDS_MAXDEPTH 4
int security_mls_enabled(void); struct selinux_avc;
struct selinux_ss;
struct selinux_state {
bool disabled;
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
bool enforcing;
#endif
bool checkreqprot;
bool initialized;
bool policycap[__POLICYDB_CAPABILITY_MAX];
struct selinux_avc *avc;
struct selinux_ss *ss;
};
void selinux_ss_init(struct selinux_ss **ss);
void selinux_avc_init(struct selinux_avc **avc);
extern struct selinux_state selinux_state;
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
static inline bool enforcing_enabled(struct selinux_state *state)
{
return state->enforcing;
}
static inline void enforcing_set(struct selinux_state *state, bool value)
{
state->enforcing = value;
}
#else
static inline bool enforcing_enabled(struct selinux_state *state)
{
return true;
}
static inline void enforcing_set(struct selinux_state *state, bool value)
{
}
#endif
static inline bool selinux_policycap_netpeer(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_NETPEER];
}
static inline bool selinux_policycap_openperm(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_OPENPERM];
}
int security_load_policy(void *data, size_t len); static inline bool selinux_policycap_extsockclass(void)
int security_read_policy(void **data, size_t *len); {
size_t security_policydb_len(void); struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_EXTSOCKCLASS];
}
int security_policycap_supported(unsigned int req_cap); static inline bool selinux_policycap_alwaysnetwork(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_ALWAYSNETWORK];
}
static inline bool selinux_policycap_cgroupseclabel(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_CGROUPSECLABEL];
}
static inline bool selinux_policycap_nnp_nosuid_transition(void)
{
struct selinux_state *state = &selinux_state;
return state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION];
}
int security_mls_enabled(struct selinux_state *state);
int security_load_policy(struct selinux_state *state,
void *data, size_t len);
int security_read_policy(struct selinux_state *state,
void **data, size_t *len);
size_t security_policydb_len(struct selinux_state *state);
int security_policycap_supported(struct selinux_state *state,
unsigned int req_cap);
#define SEL_VEC_MAX 32 #define SEL_VEC_MAX 32
struct av_decision { struct av_decision {
...@@ -141,76 +221,100 @@ struct extended_perms { ...@@ -141,76 +221,100 @@ struct extended_perms {
/* definitions of av_decision.flags */ /* definitions of av_decision.flags */
#define AVD_FLAGS_PERMISSIVE 0x0001 #define AVD_FLAGS_PERMISSIVE 0x0001
void security_compute_av(u32 ssid, u32 tsid, void security_compute_av(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, struct av_decision *avd, u16 tclass, struct av_decision *avd,
struct extended_perms *xperms); struct extended_perms *xperms);
void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, void security_compute_xperms_decision(struct selinux_state *state,
u8 driver, struct extended_perms_decision *xpermd); u32 ssid, u32 tsid, u16 tclass,
u8 driver,
struct extended_perms_decision *xpermd);
void security_compute_av_user(u32 ssid, u32 tsid, void security_compute_av_user(struct selinux_state *state,
u16 tclass, struct av_decision *avd); u32 ssid, u32 tsid,
u16 tclass, struct av_decision *avd);
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, int security_transition_sid(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid); const struct qstr *qstr, u32 *out_sid);
int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, int security_transition_sid_user(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
const char *objname, u32 *out_sid); const char *objname, u32 *out_sid);
int security_member_sid(u32 ssid, u32 tsid, int security_member_sid(struct selinux_state *state, u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid); u16 tclass, u32 *out_sid);
int security_change_sid(u32 ssid, u32 tsid, int security_change_sid(struct selinux_state *state, u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid); u16 tclass, u32 *out_sid);
int security_sid_to_context(u32 sid, char **scontext, int security_sid_to_context(struct selinux_state *state, u32 sid,
u32 *scontext_len); char **scontext, u32 *scontext_len);
int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len); int security_sid_to_context_force(struct selinux_state *state,
u32 sid, char **scontext, u32 *scontext_len);
int security_context_to_sid(const char *scontext, u32 scontext_len, int security_context_to_sid(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *out_sid, gfp_t gfp); u32 *out_sid, gfp_t gfp);
int security_context_str_to_sid(const char *scontext, u32 *out_sid, gfp_t gfp); int security_context_str_to_sid(struct selinux_state *state,
const char *scontext, u32 *out_sid, gfp_t gfp);
int security_context_to_sid_default(const char *scontext, u32 scontext_len, int security_context_to_sid_default(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags); u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
int security_context_to_sid_force(const char *scontext, u32 scontext_len, int security_context_to_sid_force(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *sid); u32 *sid);
int security_get_user_sids(u32 callsid, char *username, int security_get_user_sids(struct selinux_state *state,
u32 callsid, char *username,
u32 **sids, u32 *nel); u32 **sids, u32 *nel);
int security_port_sid(u8 protocol, u16 port, u32 *out_sid); int security_port_sid(struct selinux_state *state,
u8 protocol, u16 port, u32 *out_sid);
int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid); int security_ib_pkey_sid(struct selinux_state *state,
u64 subnet_prefix, u16 pkey_num, u32 *out_sid);
int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid); int security_ib_endport_sid(struct selinux_state *state,
const char *dev_name, u8 port_num, u32 *out_sid);
int security_netif_sid(char *name, u32 *if_sid); int security_netif_sid(struct selinux_state *state,
char *name, u32 *if_sid);
int security_node_sid(u16 domain, void *addr, u32 addrlen, int security_node_sid(struct selinux_state *state,
u32 *out_sid); u16 domain, void *addr, u32 addrlen,
u32 *out_sid);
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, int security_validate_transition(struct selinux_state *state,
u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass); u16 tclass);
int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid, int security_validate_transition_user(struct selinux_state *state,
u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass); u16 tclass);
int security_bounded_transition(u32 oldsid, u32 newsid); int security_bounded_transition(struct selinux_state *state,
u32 oldsid, u32 newsid);
int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid); int security_sid_mls_copy(struct selinux_state *state,
u32 sid, u32 mls_sid, u32 *new_sid);
int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, int security_net_peersid_resolve(struct selinux_state *state,
u32 nlbl_sid, u32 nlbl_type,
u32 xfrm_sid, u32 xfrm_sid,
u32 *peer_sid); u32 *peer_sid);
int security_get_classes(char ***classes, int *nclasses); int security_get_classes(struct selinux_state *state,
int security_get_permissions(char *class, char ***perms, int *nperms); char ***classes, int *nclasses);
int security_get_reject_unknown(void); int security_get_permissions(struct selinux_state *state,
int security_get_allow_unknown(void); char *class, char ***perms, int *nperms);
int security_get_reject_unknown(struct selinux_state *state);
int security_get_allow_unknown(struct selinux_state *state);
#define SECURITY_FS_USE_XATTR 1 /* use xattr */ #define SECURITY_FS_USE_XATTR 1 /* use xattr */
#define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */ #define SECURITY_FS_USE_TRANS 2 /* use transition SIDs, e.g. devpts/tmpfs */
...@@ -221,27 +325,31 @@ int security_get_allow_unknown(void); ...@@ -221,27 +325,31 @@ int security_get_allow_unknown(void);
#define SECURITY_FS_USE_NATIVE 7 /* use native label support */ #define SECURITY_FS_USE_NATIVE 7 /* use native label support */
#define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */ #define SECURITY_FS_USE_MAX 7 /* Highest SECURITY_FS_USE_XXX */
int security_fs_use(struct super_block *sb); int security_fs_use(struct selinux_state *state, struct super_block *sb);
int security_genfs_sid(const char *fstype, char *name, u16 sclass, int security_genfs_sid(struct selinux_state *state,
u32 *sid); const char *fstype, char *name, u16 sclass,
u32 *sid);
#ifdef CONFIG_NETLABEL #ifdef CONFIG_NETLABEL
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, int security_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr,
u32 *sid); u32 *sid);
int security_netlbl_sid_to_secattr(u32 sid, int security_netlbl_sid_to_secattr(struct selinux_state *state,
u32 sid,
struct netlbl_lsm_secattr *secattr); struct netlbl_lsm_secattr *secattr);
#else #else
static inline int security_netlbl_secattr_to_sid( static inline int security_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr, struct netlbl_lsm_secattr *secattr,
u32 *sid) u32 *sid)
{ {
return -EIDRM; return -EIDRM;
} }
static inline int security_netlbl_sid_to_secattr(u32 sid, static inline int security_netlbl_sid_to_secattr(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr) u32 sid,
struct netlbl_lsm_secattr *secattr)
{ {
return -ENOENT; return -ENOENT;
} }
...@@ -252,7 +360,7 @@ const char *security_get_initial_sid_context(u32 sid); ...@@ -252,7 +360,7 @@ const char *security_get_initial_sid_context(u32 sid);
/* /*
* status notifier using mmap interface * status notifier using mmap interface
*/ */
extern struct page *selinux_kernel_status_page(void); extern struct page *selinux_kernel_status_page(struct selinux_state *state);
#define SELINUX_KERNEL_STATUS_VERSION 1 #define SELINUX_KERNEL_STATUS_VERSION 1
struct selinux_kernel_status { struct selinux_kernel_status {
...@@ -266,10 +374,12 @@ struct selinux_kernel_status { ...@@ -266,10 +374,12 @@ struct selinux_kernel_status {
*/ */
} __packed; } __packed;
extern void selinux_status_update_setenforce(int enforcing); extern void selinux_status_update_setenforce(struct selinux_state *state,
extern void selinux_status_update_policyload(int seqno); int enforcing);
extern void selinux_status_update_policyload(struct selinux_state *state,
int seqno);
extern void selinux_complete_init(void); extern void selinux_complete_init(void);
extern int selinux_disable(void); extern int selinux_disable(struct selinux_state *state);
extern void exit_sel_fs(void); extern void exit_sel_fs(void);
extern struct path selinux_null; extern struct path selinux_null;
extern struct vfsmount *selinuxfs_mount; extern struct vfsmount *selinuxfs_mount;
...@@ -277,5 +387,8 @@ extern void selnl_notify_setenforce(int val); ...@@ -277,5 +387,8 @@ extern void selnl_notify_setenforce(int val);
extern void selnl_notify_policyload(u32 seqno); extern void selnl_notify_policyload(u32 seqno);
extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
#endif /* _SELINUX_SECURITY_H_ */ extern void avtab_cache_init(void);
extern void ebitmap_cache_init(void);
extern void hashtab_cache_init(void);
#endif /* _SELINUX_SECURITY_H_ */
...@@ -163,7 +163,7 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid) ...@@ -163,7 +163,7 @@ static int sel_netif_sid_slow(struct net *ns, int ifindex, u32 *sid)
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
} }
ret = security_netif_sid(dev->name, &new->nsec.sid); ret = security_netif_sid(&selinux_state, dev->name, &new->nsec.sid);
if (ret != 0) if (ret != 0)
goto out; goto out;
new->nsec.ns = ns; new->nsec.ns = ns;
......
...@@ -59,7 +59,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb, ...@@ -59,7 +59,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
{ {
int rc; int rc;
rc = security_netlbl_secattr_to_sid(secattr, sid); rc = security_netlbl_secattr_to_sid(&selinux_state, secattr, sid);
if (rc == 0 && if (rc == 0 &&
(secattr->flags & NETLBL_SECATTR_CACHEABLE) && (secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
(secattr->flags & NETLBL_SECATTR_CACHE)) (secattr->flags & NETLBL_SECATTR_CACHE))
...@@ -90,7 +90,8 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) ...@@ -90,7 +90,8 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
secattr = netlbl_secattr_alloc(GFP_ATOMIC); secattr = netlbl_secattr_alloc(GFP_ATOMIC);
if (secattr == NULL) if (secattr == NULL)
return NULL; return NULL;
rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); rc = security_netlbl_sid_to_secattr(&selinux_state, sksec->sid,
secattr);
if (rc != 0) { if (rc != 0) {
netlbl_secattr_free(secattr); netlbl_secattr_free(secattr);
return NULL; return NULL;
...@@ -249,6 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, ...@@ -249,6 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
sk = skb_to_full_sk(skb); sk = skb_to_full_sk(skb);
if (sk != NULL) { if (sk != NULL) {
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
if (sksec->nlbl_state != NLBL_REQSKB) if (sksec->nlbl_state != NLBL_REQSKB)
return 0; return 0;
secattr = selinux_netlbl_sock_getattr(sk, sid); secattr = selinux_netlbl_sock_getattr(sk, sid);
...@@ -256,7 +258,8 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, ...@@ -256,7 +258,8 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
if (secattr == NULL) { if (secattr == NULL) {
secattr = &secattr_storage; secattr = &secattr_storage;
netlbl_secattr_init(secattr); netlbl_secattr_init(secattr);
rc = security_netlbl_sid_to_secattr(sid, secattr); rc = security_netlbl_sid_to_secattr(&selinux_state, sid,
secattr);
if (rc != 0) if (rc != 0)
goto skbuff_setsid_return; goto skbuff_setsid_return;
} }
...@@ -269,6 +272,62 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb, ...@@ -269,6 +272,62 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
return rc; return rc;
} }
/**
* 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 *addr;
struct sockaddr_in addr4;
#if IS_ENABLED(CONFIG_IPV6)
struct sockaddr_in6 addr6;
#endif
if (ep->base.sk->sk_family != PF_INET &&
ep->base.sk->sk_family != PF_INET6)
return 0;
netlbl_secattr_init(&secattr);
rc = security_netlbl_sid_to_secattr(&selinux_state,
ep->secid, &secattr);
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;
addr = (struct sockaddr *)&addr4;
#if IS_ENABLED(CONFIG_IPV6)
} else {
addr6.sin6_family = AF_INET6;
addr6.sin6_addr = ipv6_hdr(skb)->saddr;
addr = (struct sockaddr *)&addr6;
#endif
}
rc = netlbl_conn_setattr(ep->base.sk, addr, &secattr);
if (rc == 0)
sksec->nlbl_state = NLBL_LABELED;
assoc_request_return:
netlbl_secattr_destroy(&secattr);
return rc;
}
/** /**
* selinux_netlbl_inet_conn_request - Label an incoming stream connection * selinux_netlbl_inet_conn_request - Label an incoming stream connection
* @req: incoming connection request socket * @req: incoming connection request socket
...@@ -289,7 +348,8 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family) ...@@ -289,7 +348,8 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
return 0; return 0;
netlbl_secattr_init(&secattr); netlbl_secattr_init(&secattr);
rc = security_netlbl_sid_to_secattr(req->secid, &secattr); rc = security_netlbl_sid_to_secattr(&selinux_state, req->secid,
&secattr);
if (rc != 0) if (rc != 0)
goto inet_conn_request_return; goto inet_conn_request_return;
rc = netlbl_req_setattr(req, &secattr); rc = netlbl_req_setattr(req, &secattr);
...@@ -318,6 +378,22 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family) ...@@ -318,6 +378,22 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
sksec->nlbl_state = NLBL_UNSET; sksec->nlbl_state = NLBL_UNSET;
} }
/**
* 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;
}
/** /**
* selinux_netlbl_socket_post_create - Label a socket using NetLabel * selinux_netlbl_socket_post_create - Label a socket using NetLabel
* @sock: the socket to label * @sock: the socket to label
...@@ -402,7 +478,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec, ...@@ -402,7 +478,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
perm = RAWIP_SOCKET__RECVFROM; perm = RAWIP_SOCKET__RECVFROM;
} }
rc = avc_has_perm(sksec->sid, nlbl_sid, sksec->sclass, perm, ad); rc = avc_has_perm(&selinux_state,
sksec->sid, nlbl_sid, sksec->sclass, perm, ad);
if (rc == 0) if (rc == 0)
return 0; return 0;
...@@ -469,7 +546,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, ...@@ -469,7 +546,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
} }
/** /**
* selinux_netlbl_socket_connect - Label a client-side socket on connect * selinux_netlbl_socket_connect_helper - Help label a client-side socket on
* connect
* @sk: the socket to label * @sk: the socket to label
* @addr: the destination address * @addr: the destination address
* *
...@@ -478,18 +556,13 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock, ...@@ -478,18 +556,13 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
* Returns zero values on success, negative values on failure. * Returns zero values on success, negative values on failure.
* *
*/ */
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) static int selinux_netlbl_socket_connect_helper(struct sock *sk,
struct sockaddr *addr)
{ {
int rc; int rc;
struct sk_security_struct *sksec = sk->sk_security; struct sk_security_struct *sksec = sk->sk_security;
struct netlbl_lsm_secattr *secattr; struct netlbl_lsm_secattr *secattr;
if (sksec->nlbl_state != NLBL_REQSKB &&
sksec->nlbl_state != NLBL_CONNLABELED)
return 0;
lock_sock(sk);
/* connected sockets are allowed to disconnect when the address family /* 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 * is set to AF_UNSPEC, if that is what is happening we want to reset
* the socket */ * the socket */
...@@ -497,18 +570,61 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr) ...@@ -497,18 +570,61 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
netlbl_sock_delattr(sk); netlbl_sock_delattr(sk);
sksec->nlbl_state = NLBL_REQSKB; sksec->nlbl_state = NLBL_REQSKB;
rc = 0; rc = 0;
goto socket_connect_return; return rc;
} }
secattr = selinux_netlbl_sock_genattr(sk); secattr = selinux_netlbl_sock_genattr(sk);
if (secattr == NULL) { if (secattr == NULL) {
rc = -ENOMEM; rc = -ENOMEM;
goto socket_connect_return; return rc;
} }
rc = netlbl_conn_setattr(sk, addr, secattr); rc = netlbl_conn_setattr(sk, addr, secattr);
if (rc == 0) if (rc == 0)
sksec->nlbl_state = NLBL_CONNLABELED; sksec->nlbl_state = NLBL_CONNLABELED;
socket_connect_return: 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);
release_sock(sk); release_sock(sk);
return rc; return rc;
} }
...@@ -215,12 +215,12 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid) ...@@ -215,12 +215,12 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
goto out; goto out;
switch (family) { switch (family) {
case PF_INET: case PF_INET:
ret = security_node_sid(PF_INET, ret = security_node_sid(&selinux_state, PF_INET,
addr, sizeof(struct in_addr), sid); addr, sizeof(struct in_addr), sid);
new->nsec.addr.ipv4 = *(__be32 *)addr; new->nsec.addr.ipv4 = *(__be32 *)addr;
break; break;
case PF_INET6: case PF_INET6:
ret = security_node_sid(PF_INET6, ret = security_node_sid(&selinux_state, PF_INET6,
addr, sizeof(struct in6_addr), sid); addr, sizeof(struct in6_addr), sid);
new->nsec.addr.ipv6 = *(struct in6_addr *)addr; new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
break; break;
......
...@@ -161,7 +161,7 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid) ...@@ -161,7 +161,7 @@ static int sel_netport_sid_slow(u8 protocol, u16 pnum, u32 *sid)
new = kzalloc(sizeof(*new), GFP_ATOMIC); new = kzalloc(sizeof(*new), GFP_ATOMIC);
if (new == NULL) if (new == NULL)
goto out; goto out;
ret = security_port_sid(protocol, pnum, sid); ret = security_port_sid(&selinux_state, protocol, pnum, sid);
if (ret != 0) if (ret != 0)
goto out; goto out;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mount.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -41,34 +42,6 @@ ...@@ -41,34 +42,6 @@
#include "objsec.h" #include "objsec.h"
#include "conditional.h" #include "conditional.h"
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
static int __init checkreqprot_setup(char *str)
{
unsigned long checkreqprot;
if (!kstrtoul(str, 0, &checkreqprot))
selinux_checkreqprot = checkreqprot ? 1 : 0;
return 1;
}
__setup("checkreqprot=", checkreqprot_setup);
static DEFINE_MUTEX(sel_mutex);
/* global data for booleans */
static struct dentry *bool_dir;
static int bool_num;
static char **bool_pending_names;
static int *bool_pending_values;
/* global data for classes */
static struct dentry *class_dir;
static unsigned long last_class_ino;
static char policy_opened;
/* global data for policy capabilities */
static struct dentry *policycap_dir;
enum sel_inos { enum sel_inos {
SEL_ROOT_INO = 2, SEL_ROOT_INO = 2,
SEL_LOAD, /* load policy */ SEL_LOAD, /* load policy */
...@@ -93,7 +66,51 @@ enum sel_inos { ...@@ -93,7 +66,51 @@ enum sel_inos {
SEL_INO_NEXT, /* The next inode number to use */ SEL_INO_NEXT, /* The next inode number to use */
}; };
static unsigned long sel_last_ino = SEL_INO_NEXT - 1; struct selinux_fs_info {
struct dentry *bool_dir;
unsigned int bool_num;
char **bool_pending_names;
unsigned int *bool_pending_values;
struct dentry *class_dir;
unsigned long last_class_ino;
bool policy_opened;
struct dentry *policycap_dir;
struct mutex mutex;
unsigned long last_ino;
struct selinux_state *state;
struct super_block *sb;
};
static int selinux_fs_info_create(struct super_block *sb)
{
struct selinux_fs_info *fsi;
fsi = kzalloc(sizeof(*fsi), GFP_KERNEL);
if (!fsi)
return -ENOMEM;
mutex_init(&fsi->mutex);
fsi->last_ino = SEL_INO_NEXT - 1;
fsi->state = &selinux_state;
fsi->sb = sb;
sb->s_fs_info = fsi;
return 0;
}
static void selinux_fs_info_free(struct super_block *sb)
{
struct selinux_fs_info *fsi = sb->s_fs_info;
int i;
if (fsi) {
for (i = 0; i < fsi->bool_num; i++)
kfree(fsi->bool_pending_names[i]);
kfree(fsi->bool_pending_names);
kfree(fsi->bool_pending_values);
}
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
}
#define SEL_INITCON_INO_OFFSET 0x01000000 #define SEL_INITCON_INO_OFFSET 0x01000000
#define SEL_BOOL_INO_OFFSET 0x02000000 #define SEL_BOOL_INO_OFFSET 0x02000000
...@@ -105,10 +122,12 @@ static unsigned long sel_last_ino = SEL_INO_NEXT - 1; ...@@ -105,10 +122,12 @@ static unsigned long sel_last_ino = SEL_INO_NEXT - 1;
static ssize_t sel_read_enforce(struct file *filp, char __user *buf, static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_enforcing); length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
enforcing_enabled(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
} }
...@@ -117,9 +136,11 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, ...@@ -117,9 +136,11 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *page = NULL; char *page = NULL;
ssize_t length; ssize_t length;
int new_value; int old_value, new_value;
if (count >= PAGE_SIZE) if (count >= PAGE_SIZE)
return -ENOMEM; return -ENOMEM;
...@@ -138,23 +159,25 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf, ...@@ -138,23 +159,25 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
new_value = !!new_value; new_value = !!new_value;
if (new_value != selinux_enforcing) { old_value = enforcing_enabled(state);
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, if (new_value != old_value) {
length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETENFORCE, SECCLASS_SECURITY, SECURITY__SETENFORCE,
NULL); NULL);
if (length) if (length)
goto out; goto out;
audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
"enforcing=%d old_enforcing=%d auid=%u ses=%u", "enforcing=%d old_enforcing=%d auid=%u ses=%u",
new_value, selinux_enforcing, new_value, old_value,
from_kuid(&init_user_ns, audit_get_loginuid(current)), from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current)); audit_get_sessionid(current));
selinux_enforcing = new_value; enforcing_set(state, new_value);
if (selinux_enforcing) if (new_value)
avc_ss_reset(0); avc_ss_reset(state->avc, 0);
selnl_notify_setenforce(selinux_enforcing); selnl_notify_setenforce(new_value);
selinux_status_update_setenforce(selinux_enforcing); selinux_status_update_setenforce(state, new_value);
if (!selinux_enforcing) if (!new_value)
call_lsm_notifier(LSM_POLICY_CHANGE, NULL); call_lsm_notifier(LSM_POLICY_CHANGE, NULL);
} }
length = count; length = count;
...@@ -175,11 +198,14 @@ static const struct file_operations sel_enforce_ops = { ...@@ -175,11 +198,14 @@ static const struct file_operations sel_enforce_ops = {
static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf, static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
ino_t ino = file_inode(filp)->i_ino; ino_t ino = file_inode(filp)->i_ino;
int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ? int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
security_get_reject_unknown() : !security_get_allow_unknown(); security_get_reject_unknown(state) :
!security_get_allow_unknown(state);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown); length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
...@@ -192,7 +218,8 @@ static const struct file_operations sel_handle_unknown_ops = { ...@@ -192,7 +218,8 @@ static const struct file_operations sel_handle_unknown_ops = {
static int sel_open_handle_status(struct inode *inode, struct file *filp) static int sel_open_handle_status(struct inode *inode, struct file *filp)
{ {
struct page *status = selinux_kernel_status_page(); struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct page *status = selinux_kernel_status_page(fsi->state);
if (!status) if (!status)
return -ENOMEM; return -ENOMEM;
...@@ -248,6 +275,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, ...@@ -248,6 +275,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
char *page; char *page;
ssize_t length; ssize_t length;
int new_value; int new_value;
...@@ -268,7 +296,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf, ...@@ -268,7 +296,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
goto out; goto out;
if (new_value) { if (new_value) {
length = selinux_disable(); length = selinux_disable(fsi->state);
if (length) if (length)
goto out; goto out;
audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS, audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
...@@ -307,9 +335,9 @@ static const struct file_operations sel_policyvers_ops = { ...@@ -307,9 +335,9 @@ static const struct file_operations sel_policyvers_ops = {
}; };
/* declaration for sel_write_load */ /* declaration for sel_write_load */
static int sel_make_bools(void); static int sel_make_bools(struct selinux_fs_info *fsi);
static int sel_make_classes(void); static int sel_make_classes(struct selinux_fs_info *fsi);
static int sel_make_policycap(void); static int sel_make_policycap(struct selinux_fs_info *fsi);
/* declaration for sel_make_class_dirs */ /* declaration for sel_make_class_dirs */
static struct dentry *sel_make_dir(struct dentry *dir, const char *name, static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
...@@ -318,11 +346,12 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name, ...@@ -318,11 +346,12 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
static ssize_t sel_read_mls(struct file *filp, char __user *buf, static ssize_t sel_read_mls(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
security_mls_enabled()); security_mls_enabled(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
} }
...@@ -338,20 +367,23 @@ struct policy_load_memory { ...@@ -338,20 +367,23 @@ struct policy_load_memory {
static int sel_open_policy(struct inode *inode, struct file *filp) static int sel_open_policy(struct inode *inode, struct file *filp)
{ {
struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
struct policy_load_memory *plm = NULL; struct policy_load_memory *plm = NULL;
int rc; int rc;
BUG_ON(filp->private_data); BUG_ON(filp->private_data);
mutex_lock(&sel_mutex); mutex_lock(&fsi->mutex);
rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, rc = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (rc) if (rc)
goto err; goto err;
rc = -EBUSY; rc = -EBUSY;
if (policy_opened) if (fsi->policy_opened)
goto err; goto err;
rc = -ENOMEM; rc = -ENOMEM;
...@@ -359,25 +391,25 @@ static int sel_open_policy(struct inode *inode, struct file *filp) ...@@ -359,25 +391,25 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
if (!plm) if (!plm)
goto err; goto err;
if (i_size_read(inode) != security_policydb_len()) { if (i_size_read(inode) != security_policydb_len(state)) {
inode_lock(inode); inode_lock(inode);
i_size_write(inode, security_policydb_len()); i_size_write(inode, security_policydb_len(state));
inode_unlock(inode); inode_unlock(inode);
} }
rc = security_read_policy(&plm->data, &plm->len); rc = security_read_policy(state, &plm->data, &plm->len);
if (rc) if (rc)
goto err; goto err;
policy_opened = 1; fsi->policy_opened = 1;
filp->private_data = plm; filp->private_data = plm;
mutex_unlock(&sel_mutex); mutex_unlock(&fsi->mutex);
return 0; return 0;
err: err:
mutex_unlock(&sel_mutex); mutex_unlock(&fsi->mutex);
if (plm) if (plm)
vfree(plm->data); vfree(plm->data);
...@@ -387,11 +419,12 @@ static int sel_open_policy(struct inode *inode, struct file *filp) ...@@ -387,11 +419,12 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
static int sel_release_policy(struct inode *inode, struct file *filp) static int sel_release_policy(struct inode *inode, struct file *filp)
{ {
struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
struct policy_load_memory *plm = filp->private_data; struct policy_load_memory *plm = filp->private_data;
BUG_ON(!plm); BUG_ON(!plm);
policy_opened = 0; fsi->policy_opened = 0;
vfree(plm->data); vfree(plm->data);
kfree(plm); kfree(plm);
...@@ -402,19 +435,21 @@ static int sel_release_policy(struct inode *inode, struct file *filp) ...@@ -402,19 +435,21 @@ static int sel_release_policy(struct inode *inode, struct file *filp)
static ssize_t sel_read_policy(struct file *filp, char __user *buf, static ssize_t sel_read_policy(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct policy_load_memory *plm = filp->private_data; struct policy_load_memory *plm = filp->private_data;
int ret; int ret;
mutex_lock(&sel_mutex); mutex_lock(&fsi->mutex);
ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, ret = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL); SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
if (ret) if (ret)
goto out; goto out;
ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len); ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
out: out:
mutex_unlock(&sel_mutex); mutex_unlock(&fsi->mutex);
return ret; return ret;
} }
...@@ -468,16 +503,43 @@ static const struct file_operations sel_policy_ops = { ...@@ -468,16 +503,43 @@ static const struct file_operations sel_policy_ops = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
}; };
static int sel_make_policy_nodes(struct selinux_fs_info *fsi)
{
int ret;
ret = sel_make_bools(fsi);
if (ret) {
pr_err("SELinux: failed to load policy booleans\n");
return ret;
}
ret = sel_make_classes(fsi);
if (ret) {
pr_err("SELinux: failed to load policy classes\n");
return ret;
}
ret = sel_make_policycap(fsi);
if (ret) {
pr_err("SELinux: failed to load policy capabilities\n");
return ret;
}
return 0;
}
static ssize_t sel_write_load(struct file *file, const char __user *buf, static ssize_t sel_write_load(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
ssize_t length; ssize_t length;
void *data = NULL; void *data = NULL;
mutex_lock(&sel_mutex); mutex_lock(&fsi->mutex);
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL); SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
if (length) if (length)
goto out; goto out;
...@@ -500,29 +562,15 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, ...@@ -500,29 +562,15 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (copy_from_user(data, buf, count) != 0) if (copy_from_user(data, buf, count) != 0)
goto out; goto out;
length = security_load_policy(data, count); length = security_load_policy(fsi->state, data, count);
if (length) { if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n"); pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out; goto out;
} }
length = sel_make_bools(); length = sel_make_policy_nodes(fsi);
if (length) { if (length)
pr_err("SELinux: failed to load policy booleans\n");
goto out1;
}
length = sel_make_classes();
if (length) {
pr_err("SELinux: failed to load policy classes\n");
goto out1;
}
length = sel_make_policycap();
if (length) {
pr_err("SELinux: failed to load policy capabilities\n");
goto out1; goto out1;
}
length = count; length = count;
...@@ -532,7 +580,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf, ...@@ -532,7 +580,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
from_kuid(&init_user_ns, audit_get_loginuid(current)), from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current)); audit_get_sessionid(current));
out: out:
mutex_unlock(&sel_mutex); mutex_unlock(&fsi->mutex);
vfree(data); vfree(data);
return length; return length;
} }
...@@ -544,20 +592,23 @@ static const struct file_operations sel_load_ops = { ...@@ -544,20 +592,23 @@ static const struct file_operations sel_load_ops = {
static ssize_t sel_write_context(struct file *file, char *buf, size_t size) static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *canon = NULL; char *canon = NULL;
u32 sid, len; u32 sid, len;
ssize_t length; ssize_t length;
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL); SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
if (length) if (length)
goto out; goto out;
length = security_context_to_sid(buf, size, &sid, GFP_KERNEL); length = security_context_to_sid(state, buf, size, &sid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_sid_to_context(sid, &canon, &len); length = security_sid_to_context(state, sid, &canon, &len);
if (length) if (length)
goto out; goto out;
...@@ -578,21 +629,24 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size) ...@@ -578,21 +629,24 @@ static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_checkreqprot); length = scnprintf(tmpbuf, TMPBUFLEN, "%u", fsi->state->checkreqprot);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
} }
static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
char *page; char *page;
ssize_t length; ssize_t length;
unsigned int new_value; unsigned int new_value;
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT, SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
NULL); NULL);
if (length) if (length)
...@@ -613,7 +667,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, ...@@ -613,7 +667,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
if (sscanf(page, "%u", &new_value) != 1) if (sscanf(page, "%u", &new_value) != 1)
goto out; goto out;
selinux_checkreqprot = new_value ? 1 : 0; fsi->state->checkreqprot = new_value ? 1 : 0;
length = count; length = count;
out: out:
kfree(page); kfree(page);
...@@ -629,13 +683,16 @@ static ssize_t sel_write_validatetrans(struct file *file, ...@@ -629,13 +683,16 @@ static ssize_t sel_write_validatetrans(struct file *file,
const char __user *buf, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *oldcon = NULL, *newcon = NULL, *taskcon = NULL; char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
char *req = NULL; char *req = NULL;
u32 osid, nsid, tsid; u32 osid, nsid, tsid;
u16 tclass; u16 tclass;
int rc; int rc;
rc = avc_has_perm(current_sid(), SECINITSID_SECURITY, rc = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL); SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
if (rc) if (rc)
goto out; goto out;
...@@ -673,19 +730,19 @@ static ssize_t sel_write_validatetrans(struct file *file, ...@@ -673,19 +730,19 @@ static ssize_t sel_write_validatetrans(struct file *file,
if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4) if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
goto out; goto out;
rc = security_context_str_to_sid(oldcon, &osid, GFP_KERNEL); rc = security_context_str_to_sid(state, oldcon, &osid, GFP_KERNEL);
if (rc) if (rc)
goto out; goto out;
rc = security_context_str_to_sid(newcon, &nsid, GFP_KERNEL); rc = security_context_str_to_sid(state, newcon, &nsid, GFP_KERNEL);
if (rc) if (rc)
goto out; goto out;
rc = security_context_str_to_sid(taskcon, &tsid, GFP_KERNEL); rc = security_context_str_to_sid(state, taskcon, &tsid, GFP_KERNEL);
if (rc) if (rc)
goto out; goto out;
rc = security_validate_transition_user(osid, nsid, tsid, tclass); rc = security_validate_transition_user(state, osid, nsid, tsid, tclass);
if (!rc) if (!rc)
rc = count; rc = count;
out: out:
...@@ -755,13 +812,16 @@ static const struct file_operations transaction_ops = { ...@@ -755,13 +812,16 @@ static const struct file_operations transaction_ops = {
static ssize_t sel_write_access(struct file *file, char *buf, size_t size) static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL; char *scon = NULL, *tcon = NULL;
u32 ssid, tsid; u32 ssid, tsid;
u16 tclass; u16 tclass;
struct av_decision avd; struct av_decision avd;
ssize_t length; ssize_t length;
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL); SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
if (length) if (length)
goto out; goto out;
...@@ -780,15 +840,15 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) ...@@ -780,15 +840,15 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out; goto out;
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
security_compute_av_user(ssid, tsid, tclass, &avd); security_compute_av_user(state, ssid, tsid, tclass, &avd);
length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
"%x %x %x %x %u %x", "%x %x %x %x %u %x",
...@@ -803,6 +863,8 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size) ...@@ -803,6 +863,8 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
static ssize_t sel_write_create(struct file *file, char *buf, size_t size) static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL; char *scon = NULL, *tcon = NULL;
char *namebuf = NULL, *objname = NULL; char *namebuf = NULL, *objname = NULL;
u32 ssid, tsid, newsid; u32 ssid, tsid, newsid;
...@@ -812,7 +874,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) ...@@ -812,7 +874,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
u32 len; u32 len;
int nargs; int nargs;
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
NULL); NULL);
if (length) if (length)
...@@ -868,20 +931,20 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) ...@@ -868,20 +931,20 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
objname = namebuf; objname = namebuf;
} }
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_transition_sid_user(ssid, tsid, tclass, length = security_transition_sid_user(state, ssid, tsid, tclass,
objname, &newsid); objname, &newsid);
if (length) if (length)
goto out; goto out;
length = security_sid_to_context(newsid, &newcon, &len); length = security_sid_to_context(state, newsid, &newcon, &len);
if (length) if (length)
goto out; goto out;
...@@ -904,6 +967,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size) ...@@ -904,6 +967,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL; char *scon = NULL, *tcon = NULL;
u32 ssid, tsid, newsid; u32 ssid, tsid, newsid;
u16 tclass; u16 tclass;
...@@ -911,7 +976,8 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) ...@@ -911,7 +976,8 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
char *newcon = NULL; char *newcon = NULL;
u32 len; u32 len;
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL, SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
NULL); NULL);
if (length) if (length)
...@@ -931,19 +997,19 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) ...@@ -931,19 +997,19 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out; goto out;
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_change_sid(ssid, tsid, tclass, &newsid); length = security_change_sid(state, ssid, tsid, tclass, &newsid);
if (length) if (length)
goto out; goto out;
length = security_sid_to_context(newsid, &newcon, &len); length = security_sid_to_context(state, newsid, &newcon, &len);
if (length) if (length)
goto out; goto out;
...@@ -962,6 +1028,8 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size) ...@@ -962,6 +1028,8 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
static ssize_t sel_write_user(struct file *file, char *buf, size_t size) static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *con = NULL, *user = NULL, *ptr; char *con = NULL, *user = NULL, *ptr;
u32 sid, *sids = NULL; u32 sid, *sids = NULL;
ssize_t length; ssize_t length;
...@@ -969,7 +1037,8 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) ...@@ -969,7 +1037,8 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
int i, rc; int i, rc;
u32 len, nsids; u32 len, nsids;
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER, SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
NULL); NULL);
if (length) if (length)
...@@ -989,18 +1058,18 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) ...@@ -989,18 +1058,18 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s", con, user) != 2) if (sscanf(buf, "%s %s", con, user) != 2)
goto out; goto out;
length = security_context_str_to_sid(con, &sid, GFP_KERNEL); length = security_context_str_to_sid(state, con, &sid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_get_user_sids(sid, user, &sids, &nsids); length = security_get_user_sids(state, sid, user, &sids, &nsids);
if (length) if (length)
goto out; goto out;
length = sprintf(buf, "%u", nsids) + 1; length = sprintf(buf, "%u", nsids) + 1;
ptr = buf + length; ptr = buf + length;
for (i = 0; i < nsids; i++) { for (i = 0; i < nsids; i++) {
rc = security_sid_to_context(sids[i], &newcon, &len); rc = security_sid_to_context(state, sids[i], &newcon, &len);
if (rc) { if (rc) {
length = rc; length = rc;
goto out; goto out;
...@@ -1024,6 +1093,8 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size) ...@@ -1024,6 +1093,8 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
static ssize_t sel_write_member(struct file *file, char *buf, size_t size) static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *scon = NULL, *tcon = NULL; char *scon = NULL, *tcon = NULL;
u32 ssid, tsid, newsid; u32 ssid, tsid, newsid;
u16 tclass; u16 tclass;
...@@ -1031,7 +1102,8 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) ...@@ -1031,7 +1102,8 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
char *newcon = NULL; char *newcon = NULL;
u32 len; u32 len;
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER, SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
NULL); NULL);
if (length) if (length)
...@@ -1051,19 +1123,19 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size) ...@@ -1051,19 +1123,19 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3) if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
goto out; goto out;
length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL); length = security_context_str_to_sid(state, scon, &ssid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL); length = security_context_str_to_sid(state, tcon, &tsid, GFP_KERNEL);
if (length) if (length)
goto out; goto out;
length = security_member_sid(ssid, tsid, tclass, &newsid); length = security_member_sid(state, ssid, tsid, tclass, &newsid);
if (length) if (length)
goto out; goto out;
length = security_sid_to_context(newsid, &newcon, &len); length = security_sid_to_context(state, newsid, &newcon, &len);
if (length) if (length)
goto out; goto out;
...@@ -1097,6 +1169,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode) ...@@ -1097,6 +1169,7 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
static ssize_t sel_read_bool(struct file *filep, char __user *buf, static ssize_t sel_read_bool(struct file *filep, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filep)->i_sb->s_fs_info;
char *page = NULL; char *page = NULL;
ssize_t length; ssize_t length;
ssize_t ret; ssize_t ret;
...@@ -1104,10 +1177,11 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, ...@@ -1104,10 +1177,11 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK; unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
const char *name = filep->f_path.dentry->d_name.name; const char *name = filep->f_path.dentry->d_name.name;
mutex_lock(&sel_mutex); mutex_lock(&fsi->mutex);
ret = -EINVAL; ret = -EINVAL;
if (index >= bool_num || strcmp(name, bool_pending_names[index])) if (index >= fsi->bool_num || strcmp(name,
fsi->bool_pending_names[index]))
goto out; goto out;
ret = -ENOMEM; ret = -ENOMEM;
...@@ -1115,16 +1189,16 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, ...@@ -1115,16 +1189,16 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
if (!page) if (!page)
goto out; goto out;
cur_enforcing = security_get_bool_value(index); cur_enforcing = security_get_bool_value(fsi->state, index);
if (cur_enforcing < 0) { if (cur_enforcing < 0) {
ret = cur_enforcing; ret = cur_enforcing;
goto out; goto out;
} }
length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing, length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
bool_pending_values[index]); fsi->bool_pending_values[index]);
ret = simple_read_from_buffer(buf, count, ppos, page, length); ret = simple_read_from_buffer(buf, count, ppos, page, length);
out: out:
mutex_unlock(&sel_mutex); mutex_unlock(&fsi->mutex);
free_page((unsigned long)page); free_page((unsigned long)page);
return ret; return ret;
} }
...@@ -1132,22 +1206,25 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf, ...@@ -1132,22 +1206,25 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
static ssize_t sel_write_bool(struct file *filep, const char __user *buf, static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filep)->i_sb->s_fs_info;
char *page = NULL; char *page = NULL;
ssize_t length; ssize_t length;
int new_value; int new_value;
unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK; unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
const char *name = filep->f_path.dentry->d_name.name; const char *name = filep->f_path.dentry->d_name.name;
mutex_lock(&sel_mutex); mutex_lock(&fsi->mutex);
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL, SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL); NULL);
if (length) if (length)
goto out; goto out;
length = -EINVAL; length = -EINVAL;
if (index >= bool_num || strcmp(name, bool_pending_names[index])) if (index >= fsi->bool_num || strcmp(name,
fsi->bool_pending_names[index]))
goto out; goto out;
length = -ENOMEM; length = -ENOMEM;
...@@ -1173,11 +1250,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf, ...@@ -1173,11 +1250,11 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
if (new_value) if (new_value)
new_value = 1; new_value = 1;
bool_pending_values[index] = new_value; fsi->bool_pending_values[index] = new_value;
length = count; length = count;
out: out:
mutex_unlock(&sel_mutex); mutex_unlock(&fsi->mutex);
kfree(page); kfree(page);
return length; return length;
} }
...@@ -1192,13 +1269,15 @@ static ssize_t sel_commit_bools_write(struct file *filep, ...@@ -1192,13 +1269,15 @@ static ssize_t sel_commit_bools_write(struct file *filep,
const char __user *buf, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filep)->i_sb->s_fs_info;
char *page = NULL; char *page = NULL;
ssize_t length; ssize_t length;
int new_value; int new_value;
mutex_lock(&sel_mutex); mutex_lock(&fsi->mutex);
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETBOOL, SECCLASS_SECURITY, SECURITY__SETBOOL,
NULL); NULL);
if (length) if (length)
...@@ -1225,14 +1304,15 @@ static ssize_t sel_commit_bools_write(struct file *filep, ...@@ -1225,14 +1304,15 @@ static ssize_t sel_commit_bools_write(struct file *filep,
goto out; goto out;
length = 0; length = 0;
if (new_value && bool_pending_values) if (new_value && fsi->bool_pending_values)
length = security_set_bools(bool_num, bool_pending_values); length = security_set_bools(fsi->state, fsi->bool_num,
fsi->bool_pending_values);
if (!length) if (!length)
length = count; length = count;
out: out:
mutex_unlock(&sel_mutex); mutex_unlock(&fsi->mutex);
kfree(page); kfree(page);
return length; return length;
} }
...@@ -1250,12 +1330,12 @@ static void sel_remove_entries(struct dentry *de) ...@@ -1250,12 +1330,12 @@ static void sel_remove_entries(struct dentry *de)
#define BOOL_DIR_NAME "booleans" #define BOOL_DIR_NAME "booleans"
static int sel_make_bools(void) static int sel_make_bools(struct selinux_fs_info *fsi)
{ {
int i, ret; int i, ret;
ssize_t len; ssize_t len;
struct dentry *dentry = NULL; struct dentry *dentry = NULL;
struct dentry *dir = bool_dir; struct dentry *dir = fsi->bool_dir;
struct inode *inode = NULL; struct inode *inode = NULL;
struct inode_security_struct *isec; struct inode_security_struct *isec;
char **names = NULL, *page; char **names = NULL, *page;
...@@ -1264,13 +1344,13 @@ static int sel_make_bools(void) ...@@ -1264,13 +1344,13 @@ static int sel_make_bools(void)
u32 sid; u32 sid;
/* remove any existing files */ /* remove any existing files */
for (i = 0; i < bool_num; i++) for (i = 0; i < fsi->bool_num; i++)
kfree(bool_pending_names[i]); kfree(fsi->bool_pending_names[i]);
kfree(bool_pending_names); kfree(fsi->bool_pending_names);
kfree(bool_pending_values); kfree(fsi->bool_pending_values);
bool_num = 0; fsi->bool_num = 0;
bool_pending_names = NULL; fsi->bool_pending_names = NULL;
bool_pending_values = NULL; fsi->bool_pending_values = NULL;
sel_remove_entries(dir); sel_remove_entries(dir);
...@@ -1279,7 +1359,7 @@ static int sel_make_bools(void) ...@@ -1279,7 +1359,7 @@ static int sel_make_bools(void)
if (!page) if (!page)
goto out; goto out;
ret = security_get_bools(&num, &names, &values); ret = security_get_bools(fsi->state, &num, &names, &values);
if (ret) if (ret)
goto out; goto out;
...@@ -1300,7 +1380,8 @@ static int sel_make_bools(void) ...@@ -1300,7 +1380,8 @@ static int sel_make_bools(void)
goto out; goto out;
isec = (struct inode_security_struct *)inode->i_security; isec = (struct inode_security_struct *)inode->i_security;
ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid); ret = security_genfs_sid(fsi->state, "selinuxfs", page,
SECCLASS_FILE, &sid);
if (ret) { if (ret) {
pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n", pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
page); page);
...@@ -1313,9 +1394,9 @@ static int sel_make_bools(void) ...@@ -1313,9 +1394,9 @@ static int sel_make_bools(void)
inode->i_ino = i|SEL_BOOL_INO_OFFSET; inode->i_ino = i|SEL_BOOL_INO_OFFSET;
d_add(dentry, inode); d_add(dentry, inode);
} }
bool_num = num; fsi->bool_num = num;
bool_pending_names = names; fsi->bool_pending_names = names;
bool_pending_values = values; fsi->bool_pending_values = values;
free_page((unsigned long)page); free_page((unsigned long)page);
return 0; return 0;
...@@ -1333,17 +1414,16 @@ static int sel_make_bools(void) ...@@ -1333,17 +1414,16 @@ static int sel_make_bools(void)
return ret; return ret;
} }
#define NULL_FILE_NAME "null"
struct path selinux_null;
static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf, static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
length = scnprintf(tmpbuf, TMPBUFLEN, "%u", avc_cache_threshold); length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
avc_get_cache_threshold(state->avc));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
} }
...@@ -1352,11 +1432,14 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, ...@@ -1352,11 +1432,14 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *page; char *page;
ssize_t ret; ssize_t ret;
unsigned int new_value; unsigned int new_value;
ret = avc_has_perm(current_sid(), SECINITSID_SECURITY, ret = avc_has_perm(&selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__SETSECPARAM, SECCLASS_SECURITY, SECURITY__SETSECPARAM,
NULL); NULL);
if (ret) if (ret)
...@@ -1377,7 +1460,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, ...@@ -1377,7 +1460,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
if (sscanf(page, "%u", &new_value) != 1) if (sscanf(page, "%u", &new_value) != 1)
goto out; goto out;
avc_cache_threshold = new_value; avc_set_cache_threshold(state->avc, new_value);
ret = count; ret = count;
out: out:
...@@ -1388,6 +1471,8 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file, ...@@ -1388,6 +1471,8 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *page; char *page;
ssize_t length; ssize_t length;
...@@ -1395,7 +1480,7 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf, ...@@ -1395,7 +1480,7 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
length = avc_get_hash_stats(page); length = avc_get_hash_stats(state->avc, page);
if (length >= 0) if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, page, length); length = simple_read_from_buffer(buf, count, ppos, page, length);
free_page((unsigned long)page); free_page((unsigned long)page);
...@@ -1486,6 +1571,8 @@ static const struct file_operations sel_avc_cache_stats_ops = { ...@@ -1486,6 +1571,8 @@ static const struct file_operations sel_avc_cache_stats_ops = {
static int sel_make_avc_files(struct dentry *dir) static int sel_make_avc_files(struct dentry *dir)
{ {
struct super_block *sb = dir->d_sb;
struct selinux_fs_info *fsi = sb->s_fs_info;
int i; int i;
static const struct tree_descr files[] = { static const struct tree_descr files[] = {
{ "cache_threshold", { "cache_threshold",
...@@ -1509,7 +1596,7 @@ static int sel_make_avc_files(struct dentry *dir) ...@@ -1509,7 +1596,7 @@ static int sel_make_avc_files(struct dentry *dir)
return -ENOMEM; return -ENOMEM;
inode->i_fop = files[i].ops; inode->i_fop = files[i].ops;
inode->i_ino = ++sel_last_ino; inode->i_ino = ++fsi->last_ino;
d_add(dentry, inode); d_add(dentry, inode);
} }
...@@ -1519,12 +1606,13 @@ static int sel_make_avc_files(struct dentry *dir) ...@@ -1519,12 +1606,13 @@ static int sel_make_avc_files(struct dentry *dir)
static ssize_t sel_read_initcon(struct file *file, char __user *buf, static ssize_t sel_read_initcon(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
char *con; char *con;
u32 sid, len; u32 sid, len;
ssize_t ret; ssize_t ret;
sid = file_inode(file)->i_ino&SEL_INO_MASK; sid = file_inode(file)->i_ino&SEL_INO_MASK;
ret = security_sid_to_context(sid, &con, &len); ret = security_sid_to_context(fsi->state, sid, &con, &len);
if (ret) if (ret)
return ret; return ret;
...@@ -1612,12 +1700,13 @@ static const struct file_operations sel_perm_ops = { ...@@ -1612,12 +1700,13 @@ static const struct file_operations sel_perm_ops = {
static ssize_t sel_read_policycap(struct file *file, char __user *buf, static ssize_t sel_read_policycap(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
int value; int value;
char tmpbuf[TMPBUFLEN]; char tmpbuf[TMPBUFLEN];
ssize_t length; ssize_t length;
unsigned long i_ino = file_inode(file)->i_ino; unsigned long i_ino = file_inode(file)->i_ino;
value = security_policycap_supported(i_ino & SEL_INO_MASK); value = security_policycap_supported(fsi->state, i_ino & SEL_INO_MASK);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value); length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
...@@ -1631,10 +1720,11 @@ static const struct file_operations sel_policycap_ops = { ...@@ -1631,10 +1720,11 @@ static const struct file_operations sel_policycap_ops = {
static int sel_make_perm_files(char *objclass, int classvalue, static int sel_make_perm_files(char *objclass, int classvalue,
struct dentry *dir) struct dentry *dir)
{ {
struct selinux_fs_info *fsi = dir->d_sb->s_fs_info;
int i, rc, nperms; int i, rc, nperms;
char **perms; char **perms;
rc = security_get_permissions(objclass, &perms, &nperms); rc = security_get_permissions(fsi->state, objclass, &perms, &nperms);
if (rc) if (rc)
return rc; return rc;
...@@ -1668,6 +1758,8 @@ static int sel_make_perm_files(char *objclass, int classvalue, ...@@ -1668,6 +1758,8 @@ static int sel_make_perm_files(char *objclass, int classvalue,
static int sel_make_class_dir_entries(char *classname, int index, static int sel_make_class_dir_entries(char *classname, int index,
struct dentry *dir) struct dentry *dir)
{ {
struct super_block *sb = dir->d_sb;
struct selinux_fs_info *fsi = sb->s_fs_info;
struct dentry *dentry = NULL; struct dentry *dentry = NULL;
struct inode *inode = NULL; struct inode *inode = NULL;
int rc; int rc;
...@@ -1684,7 +1776,7 @@ static int sel_make_class_dir_entries(char *classname, int index, ...@@ -1684,7 +1776,7 @@ static int sel_make_class_dir_entries(char *classname, int index,
inode->i_ino = sel_class_to_ino(index); inode->i_ino = sel_class_to_ino(index);
d_add(dentry, inode); d_add(dentry, inode);
dentry = sel_make_dir(dir, "perms", &last_class_ino); dentry = sel_make_dir(dir, "perms", &fsi->last_class_ino);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return PTR_ERR(dentry); return PTR_ERR(dentry);
...@@ -1693,26 +1785,27 @@ static int sel_make_class_dir_entries(char *classname, int index, ...@@ -1693,26 +1785,27 @@ static int sel_make_class_dir_entries(char *classname, int index,
return rc; return rc;
} }
static int sel_make_classes(void) static int sel_make_classes(struct selinux_fs_info *fsi)
{ {
int rc, nclasses, i; int rc, nclasses, i;
char **classes; char **classes;
/* delete any existing entries */ /* delete any existing entries */
sel_remove_entries(class_dir); sel_remove_entries(fsi->class_dir);
rc = security_get_classes(&classes, &nclasses); rc = security_get_classes(fsi->state, &classes, &nclasses);
if (rc) if (rc)
return rc; return rc;
/* +2 since classes are 1-indexed */ /* +2 since classes are 1-indexed */
last_class_ino = sel_class_to_ino(nclasses + 2); fsi->last_class_ino = sel_class_to_ino(nclasses + 2);
for (i = 0; i < nclasses; i++) { for (i = 0; i < nclasses; i++) {
struct dentry *class_name_dir; struct dentry *class_name_dir;
class_name_dir = sel_make_dir(class_dir, classes[i], class_name_dir = sel_make_dir(fsi->class_dir, classes[i],
&last_class_ino); &fsi->last_class_ino);
if (IS_ERR(class_name_dir)) { if (IS_ERR(class_name_dir)) {
rc = PTR_ERR(class_name_dir); rc = PTR_ERR(class_name_dir);
goto out; goto out;
...@@ -1732,25 +1825,25 @@ static int sel_make_classes(void) ...@@ -1732,25 +1825,25 @@ static int sel_make_classes(void)
return rc; return rc;
} }
static int sel_make_policycap(void) static int sel_make_policycap(struct selinux_fs_info *fsi)
{ {
unsigned int iter; unsigned int iter;
struct dentry *dentry = NULL; struct dentry *dentry = NULL;
struct inode *inode = NULL; struct inode *inode = NULL;
sel_remove_entries(policycap_dir); sel_remove_entries(fsi->policycap_dir);
for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) { for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
if (iter < ARRAY_SIZE(selinux_policycap_names)) if (iter < ARRAY_SIZE(selinux_policycap_names))
dentry = d_alloc_name(policycap_dir, dentry = d_alloc_name(fsi->policycap_dir,
selinux_policycap_names[iter]); selinux_policycap_names[iter]);
else else
dentry = d_alloc_name(policycap_dir, "unknown"); dentry = d_alloc_name(fsi->policycap_dir, "unknown");
if (dentry == NULL) if (dentry == NULL)
return -ENOMEM; return -ENOMEM;
inode = sel_make_inode(policycap_dir->d_sb, S_IFREG | S_IRUGO); inode = sel_make_inode(fsi->sb, S_IFREG | 0444);
if (inode == NULL) if (inode == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -1789,8 +1882,11 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name, ...@@ -1789,8 +1882,11 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
return dentry; return dentry;
} }
#define NULL_FILE_NAME "null"
static int sel_fill_super(struct super_block *sb, void *data, int silent) static int sel_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct selinux_fs_info *fsi;
int ret; int ret;
struct dentry *dentry; struct dentry *dentry;
struct inode *inode; struct inode *inode;
...@@ -1818,14 +1914,20 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1818,14 +1914,20 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
S_IWUGO}, S_IWUGO},
/* last one */ {""} /* last one */ {""}
}; };
ret = selinux_fs_info_create(sb);
if (ret)
goto err;
ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
if (ret) if (ret)
goto err; goto err;
bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &sel_last_ino); fsi = sb->s_fs_info;
if (IS_ERR(bool_dir)) { fsi->bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &fsi->last_ino);
ret = PTR_ERR(bool_dir); if (IS_ERR(fsi->bool_dir)) {
bool_dir = NULL; ret = PTR_ERR(fsi->bool_dir);
fsi->bool_dir = NULL;
goto err; goto err;
} }
...@@ -1839,7 +1941,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1839,7 +1941,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
if (!inode) if (!inode)
goto err; goto err;
inode->i_ino = ++sel_last_ino; inode->i_ino = ++fsi->last_ino;
isec = (struct inode_security_struct *)inode->i_security; isec = (struct inode_security_struct *)inode->i_security;
isec->sid = SECINITSID_DEVNULL; isec->sid = SECINITSID_DEVNULL;
isec->sclass = SECCLASS_CHR_FILE; isec->sclass = SECCLASS_CHR_FILE;
...@@ -1847,9 +1949,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1847,9 +1949,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3)); init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
d_add(dentry, inode); d_add(dentry, inode);
selinux_null.dentry = dentry;
dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino); dentry = sel_make_dir(sb->s_root, "avc", &fsi->last_ino);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry); ret = PTR_ERR(dentry);
goto err; goto err;
...@@ -1859,7 +1960,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1859,7 +1960,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
if (ret) if (ret)
goto err; goto err;
dentry = sel_make_dir(sb->s_root, "initial_contexts", &sel_last_ino); dentry = sel_make_dir(sb->s_root, "initial_contexts", &fsi->last_ino);
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry); ret = PTR_ERR(dentry);
goto err; goto err;
...@@ -1869,23 +1970,31 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) ...@@ -1869,23 +1970,31 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
if (ret) if (ret)
goto err; goto err;
class_dir = sel_make_dir(sb->s_root, "class", &sel_last_ino); fsi->class_dir = sel_make_dir(sb->s_root, "class", &fsi->last_ino);
if (IS_ERR(class_dir)) { if (IS_ERR(fsi->class_dir)) {
ret = PTR_ERR(class_dir); ret = PTR_ERR(fsi->class_dir);
class_dir = NULL; fsi->class_dir = NULL;
goto err; goto err;
} }
policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities", &sel_last_ino); fsi->policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities",
if (IS_ERR(policycap_dir)) { &fsi->last_ino);
ret = PTR_ERR(policycap_dir); if (IS_ERR(fsi->policycap_dir)) {
policycap_dir = NULL; ret = PTR_ERR(fsi->policycap_dir);
fsi->policycap_dir = NULL;
goto err; goto err;
} }
ret = sel_make_policy_nodes(fsi);
if (ret)
goto err;
return 0; return 0;
err: err:
printk(KERN_ERR "SELinux: %s: failed while creating inodes\n", printk(KERN_ERR "SELinux: %s: failed while creating inodes\n",
__func__); __func__);
selinux_fs_info_free(sb);
return ret; return ret;
} }
...@@ -1895,16 +2004,25 @@ static struct dentry *sel_mount(struct file_system_type *fs_type, ...@@ -1895,16 +2004,25 @@ static struct dentry *sel_mount(struct file_system_type *fs_type,
return mount_single(fs_type, flags, data, sel_fill_super); return mount_single(fs_type, flags, data, sel_fill_super);
} }
static void sel_kill_sb(struct super_block *sb)
{
selinux_fs_info_free(sb);
kill_litter_super(sb);
}
static struct file_system_type sel_fs_type = { static struct file_system_type sel_fs_type = {
.name = "selinuxfs", .name = "selinuxfs",
.mount = sel_mount, .mount = sel_mount,
.kill_sb = kill_litter_super, .kill_sb = sel_kill_sb,
}; };
struct vfsmount *selinuxfs_mount; struct vfsmount *selinuxfs_mount;
struct path selinux_null;
static int __init init_sel_fs(void) static int __init init_sel_fs(void)
{ {
struct qstr null_name = QSTR_INIT(NULL_FILE_NAME,
sizeof(NULL_FILE_NAME)-1);
int err; int err;
if (!selinux_enabled) if (!selinux_enabled)
...@@ -1926,6 +2044,13 @@ static int __init init_sel_fs(void) ...@@ -1926,6 +2044,13 @@ static int __init init_sel_fs(void)
err = PTR_ERR(selinuxfs_mount); err = PTR_ERR(selinuxfs_mount);
selinuxfs_mount = NULL; selinuxfs_mount = NULL;
} }
selinux_null.dentry = d_hash_and_lookup(selinux_null.mnt->mnt_root,
&null_name);
if (IS_ERR(selinux_null.dentry)) {
pr_err("selinuxfs: could not lookup null!\n");
err = PTR_ERR(selinux_null.dentry);
selinux_null.dentry = NULL;
}
return err; return err;
} }
......
...@@ -655,7 +655,8 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp) ...@@ -655,7 +655,8 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp)
return rc; return rc;
} }
void avtab_cache_init(void)
void __init avtab_cache_init(void)
{ {
avtab_node_cachep = kmem_cache_create("avtab_node", avtab_node_cachep = kmem_cache_create("avtab_node",
sizeof(struct avtab_node), sizeof(struct avtab_node),
...@@ -664,9 +665,3 @@ void avtab_cache_init(void) ...@@ -664,9 +665,3 @@ void avtab_cache_init(void)
sizeof(struct avtab_extended_perms), sizeof(struct avtab_extended_perms),
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
} }
void avtab_cache_destroy(void)
{
kmem_cache_destroy(avtab_node_cachep);
kmem_cache_destroy(avtab_xperms_cachep);
}
...@@ -114,9 +114,6 @@ struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key); ...@@ -114,9 +114,6 @@ struct avtab_node *avtab_search_node(struct avtab *h, struct avtab_key *key);
struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified); struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified);
void avtab_cache_init(void);
void avtab_cache_destroy(void);
#define MAX_AVTAB_HASH_BITS 16 #define MAX_AVTAB_HASH_BITS 16
#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS) #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
......
...@@ -523,14 +523,9 @@ int ebitmap_write(struct ebitmap *e, void *fp) ...@@ -523,14 +523,9 @@ int ebitmap_write(struct ebitmap *e, void *fp)
return 0; return 0;
} }
void ebitmap_cache_init(void) void __init ebitmap_cache_init(void)
{ {
ebitmap_node_cachep = kmem_cache_create("ebitmap_node", ebitmap_node_cachep = kmem_cache_create("ebitmap_node",
sizeof(struct ebitmap_node), sizeof(struct ebitmap_node),
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
} }
void ebitmap_cache_destroy(void)
{
kmem_cache_destroy(ebitmap_node_cachep);
}
...@@ -131,9 +131,6 @@ void ebitmap_destroy(struct ebitmap *e); ...@@ -131,9 +131,6 @@ void ebitmap_destroy(struct ebitmap *e);
int ebitmap_read(struct ebitmap *e, void *fp); int ebitmap_read(struct ebitmap *e, void *fp);
int ebitmap_write(struct ebitmap *e, void *fp); int ebitmap_write(struct ebitmap *e, void *fp);
void ebitmap_cache_init(void);
void ebitmap_cache_destroy(void);
#ifdef CONFIG_NETLABEL #ifdef CONFIG_NETLABEL
int ebitmap_netlbl_export(struct ebitmap *ebmap, int ebitmap_netlbl_export(struct ebitmap *ebmap,
struct netlbl_lsm_catmap **catmap); struct netlbl_lsm_catmap **catmap);
......
...@@ -169,14 +169,10 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info) ...@@ -169,14 +169,10 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
info->slots_used = slots_used; info->slots_used = slots_used;
info->max_chain_len = max_chain_len; info->max_chain_len = max_chain_len;
} }
void hashtab_cache_init(void)
void __init hashtab_cache_init(void)
{ {
hashtab_node_cachep = kmem_cache_create("hashtab_node", hashtab_node_cachep = kmem_cache_create("hashtab_node",
sizeof(struct hashtab_node), sizeof(struct hashtab_node),
0, SLAB_PANIC, NULL); 0, SLAB_PANIC, NULL);
} }
void hashtab_cache_destroy(void)
{
kmem_cache_destroy(hashtab_node_cachep);
}
...@@ -85,8 +85,4 @@ int hashtab_map(struct hashtab *h, ...@@ -85,8 +85,4 @@ int hashtab_map(struct hashtab *h,
/* Fill info with some hash table statistics */ /* Fill info with some hash table statistics */
void hashtab_stat(struct hashtab *h, struct hashtab_info *info); void hashtab_stat(struct hashtab *h, struct hashtab_info *info);
/* Use kmem_cache for hashtab_node */
void hashtab_cache_init(void);
void hashtab_cache_destroy(void);
#endif /* _SS_HASHTAB_H */ #endif /* _SS_HASHTAB_H */
...@@ -33,20 +33,20 @@ ...@@ -33,20 +33,20 @@
* Return the length in bytes for the MLS fields of the * Return the length in bytes for the MLS fields of the
* security context string representation of `context'. * security context string representation of `context'.
*/ */
int mls_compute_context_len(struct context *context) int mls_compute_context_len(struct policydb *p, struct context *context)
{ {
int i, l, len, head, prev; int i, l, len, head, prev;
char *nm; char *nm;
struct ebitmap *e; struct ebitmap *e;
struct ebitmap_node *node; struct ebitmap_node *node;
if (!policydb.mls_enabled) if (!p->mls_enabled)
return 0; return 0;
len = 1; /* for the beginning ":" */ len = 1; /* for the beginning ":" */
for (l = 0; l < 2; l++) { for (l = 0; l < 2; l++) {
int index_sens = context->range.level[l].sens; int index_sens = context->range.level[l].sens;
len += strlen(sym_name(&policydb, SYM_LEVELS, index_sens - 1)); len += strlen(sym_name(p, SYM_LEVELS, index_sens - 1));
/* categories */ /* categories */
head = -2; head = -2;
...@@ -56,17 +56,17 @@ int mls_compute_context_len(struct context *context) ...@@ -56,17 +56,17 @@ int mls_compute_context_len(struct context *context)
if (i - prev > 1) { if (i - prev > 1) {
/* one or more negative bits are skipped */ /* one or more negative bits are skipped */
if (head != prev) { if (head != prev) {
nm = sym_name(&policydb, SYM_CATS, prev); nm = sym_name(p, SYM_CATS, prev);
len += strlen(nm) + 1; len += strlen(nm) + 1;
} }
nm = sym_name(&policydb, SYM_CATS, i); nm = sym_name(p, SYM_CATS, i);
len += strlen(nm) + 1; len += strlen(nm) + 1;
head = i; head = i;
} }
prev = i; prev = i;
} }
if (prev != head) { if (prev != head) {
nm = sym_name(&policydb, SYM_CATS, prev); nm = sym_name(p, SYM_CATS, prev);
len += strlen(nm) + 1; len += strlen(nm) + 1;
} }
if (l == 0) { if (l == 0) {
...@@ -86,7 +86,8 @@ int mls_compute_context_len(struct context *context) ...@@ -86,7 +86,8 @@ int mls_compute_context_len(struct context *context)
* the MLS fields of `context' into the string `*scontext'. * the MLS fields of `context' into the string `*scontext'.
* Update `*scontext' to point to the end of the MLS fields. * Update `*scontext' to point to the end of the MLS fields.
*/ */
void mls_sid_to_context(struct context *context, void mls_sid_to_context(struct policydb *p,
struct context *context,
char **scontext) char **scontext)
{ {
char *scontextp, *nm; char *scontextp, *nm;
...@@ -94,7 +95,7 @@ void mls_sid_to_context(struct context *context, ...@@ -94,7 +95,7 @@ void mls_sid_to_context(struct context *context,
struct ebitmap *e; struct ebitmap *e;
struct ebitmap_node *node; struct ebitmap_node *node;
if (!policydb.mls_enabled) if (!p->mls_enabled)
return; return;
scontextp = *scontext; scontextp = *scontext;
...@@ -103,7 +104,7 @@ void mls_sid_to_context(struct context *context, ...@@ -103,7 +104,7 @@ void mls_sid_to_context(struct context *context,
scontextp++; scontextp++;
for (l = 0; l < 2; l++) { for (l = 0; l < 2; l++) {
strcpy(scontextp, sym_name(&policydb, SYM_LEVELS, strcpy(scontextp, sym_name(p, SYM_LEVELS,
context->range.level[l].sens - 1)); context->range.level[l].sens - 1));
scontextp += strlen(scontextp); scontextp += strlen(scontextp);
...@@ -119,7 +120,7 @@ void mls_sid_to_context(struct context *context, ...@@ -119,7 +120,7 @@ void mls_sid_to_context(struct context *context,
*scontextp++ = '.'; *scontextp++ = '.';
else else
*scontextp++ = ','; *scontextp++ = ',';
nm = sym_name(&policydb, SYM_CATS, prev); nm = sym_name(p, SYM_CATS, prev);
strcpy(scontextp, nm); strcpy(scontextp, nm);
scontextp += strlen(nm); scontextp += strlen(nm);
} }
...@@ -127,7 +128,7 @@ void mls_sid_to_context(struct context *context, ...@@ -127,7 +128,7 @@ void mls_sid_to_context(struct context *context,
*scontextp++ = ':'; *scontextp++ = ':';
else else
*scontextp++ = ','; *scontextp++ = ',';
nm = sym_name(&policydb, SYM_CATS, i); nm = sym_name(p, SYM_CATS, i);
strcpy(scontextp, nm); strcpy(scontextp, nm);
scontextp += strlen(nm); scontextp += strlen(nm);
head = i; head = i;
...@@ -140,7 +141,7 @@ void mls_sid_to_context(struct context *context, ...@@ -140,7 +141,7 @@ void mls_sid_to_context(struct context *context,
*scontextp++ = '.'; *scontextp++ = '.';
else else
*scontextp++ = ','; *scontextp++ = ',';
nm = sym_name(&policydb, SYM_CATS, prev); nm = sym_name(p, SYM_CATS, prev);
strcpy(scontextp, nm); strcpy(scontextp, nm);
scontextp += strlen(nm); scontextp += strlen(nm);
} }
...@@ -375,12 +376,13 @@ int mls_context_to_sid(struct policydb *pol, ...@@ -375,12 +376,13 @@ int mls_context_to_sid(struct policydb *pol,
* the string `str'. This function will allocate temporary memory with the * the string `str'. This function will allocate temporary memory with the
* given constraints of gfp_mask. * given constraints of gfp_mask.
*/ */
int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) int mls_from_string(struct policydb *p, char *str, struct context *context,
gfp_t gfp_mask)
{ {
char *tmpstr, *freestr; char *tmpstr, *freestr;
int rc; int rc;
if (!policydb.mls_enabled) if (!p->mls_enabled)
return -EINVAL; return -EINVAL;
/* we need freestr because mls_context_to_sid will change /* we need freestr because mls_context_to_sid will change
...@@ -389,7 +391,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask) ...@@ -389,7 +391,7 @@ int mls_from_string(char *str, struct context *context, gfp_t gfp_mask)
if (!tmpstr) { if (!tmpstr) {
rc = -ENOMEM; rc = -ENOMEM;
} else { } else {
rc = mls_context_to_sid(&policydb, ':', &tmpstr, context, rc = mls_context_to_sid(p, ':', &tmpstr, context,
NULL, SECSID_NULL); NULL, SECSID_NULL);
kfree(freestr); kfree(freestr);
} }
...@@ -417,10 +419,11 @@ int mls_range_set(struct context *context, ...@@ -417,10 +419,11 @@ int mls_range_set(struct context *context,
return rc; return rc;
} }
int mls_setup_user_range(struct context *fromcon, struct user_datum *user, int mls_setup_user_range(struct policydb *p,
struct context *fromcon, struct user_datum *user,
struct context *usercon) struct context *usercon)
{ {
if (policydb.mls_enabled) { if (p->mls_enabled) {
struct mls_level *fromcon_sen = &(fromcon->range.level[0]); struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
struct mls_level *fromcon_clr = &(fromcon->range.level[1]); struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
struct mls_level *user_low = &(user->range.level[0]); struct mls_level *user_low = &(user->range.level[0]);
...@@ -470,7 +473,7 @@ int mls_convert_context(struct policydb *oldp, ...@@ -470,7 +473,7 @@ int mls_convert_context(struct policydb *oldp,
struct ebitmap_node *node; struct ebitmap_node *node;
int l, i; int l, i;
if (!policydb.mls_enabled) if (!oldp->mls_enabled || !newp->mls_enabled)
return 0; return 0;
for (l = 0; l < 2; l++) { for (l = 0; l < 2; l++) {
...@@ -503,7 +506,8 @@ int mls_convert_context(struct policydb *oldp, ...@@ -503,7 +506,8 @@ int mls_convert_context(struct policydb *oldp,
return 0; return 0;
} }
int mls_compute_sid(struct context *scontext, int mls_compute_sid(struct policydb *p,
struct context *scontext,
struct context *tcontext, struct context *tcontext,
u16 tclass, u16 tclass,
u32 specified, u32 specified,
...@@ -515,7 +519,7 @@ int mls_compute_sid(struct context *scontext, ...@@ -515,7 +519,7 @@ int mls_compute_sid(struct context *scontext,
struct class_datum *cladatum; struct class_datum *cladatum;
int default_range = 0; int default_range = 0;
if (!policydb.mls_enabled) if (!p->mls_enabled)
return 0; return 0;
switch (specified) { switch (specified) {
...@@ -524,12 +528,12 @@ int mls_compute_sid(struct context *scontext, ...@@ -524,12 +528,12 @@ int mls_compute_sid(struct context *scontext,
rtr.source_type = scontext->type; rtr.source_type = scontext->type;
rtr.target_type = tcontext->type; rtr.target_type = tcontext->type;
rtr.target_class = tclass; rtr.target_class = tclass;
r = hashtab_search(policydb.range_tr, &rtr); r = hashtab_search(p->range_tr, &rtr);
if (r) if (r)
return mls_range_set(newcontext, r); return mls_range_set(newcontext, r);
if (tclass && tclass <= policydb.p_classes.nprim) { if (tclass && tclass <= p->p_classes.nprim) {
cladatum = policydb.class_val_to_struct[tclass - 1]; cladatum = p->class_val_to_struct[tclass - 1];
if (cladatum) if (cladatum)
default_range = cladatum->default_range; default_range = cladatum->default_range;
} }
...@@ -551,7 +555,7 @@ int mls_compute_sid(struct context *scontext, ...@@ -551,7 +555,7 @@ int mls_compute_sid(struct context *scontext,
/* Fallthrough */ /* Fallthrough */
case AVTAB_CHANGE: case AVTAB_CHANGE:
if ((tclass == policydb.process_class) || (sock == true)) if ((tclass == p->process_class) || (sock == true))
/* Use the process MLS attributes. */ /* Use the process MLS attributes. */
return mls_context_cpy(newcontext, scontext); return mls_context_cpy(newcontext, scontext);
else else
...@@ -577,10 +581,11 @@ int mls_compute_sid(struct context *scontext, ...@@ -577,10 +581,11 @@ int mls_compute_sid(struct context *scontext,
* NetLabel MLS sensitivity level field. * NetLabel MLS sensitivity level field.
* *
*/ */
void mls_export_netlbl_lvl(struct context *context, void mls_export_netlbl_lvl(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
if (!policydb.mls_enabled) if (!p->mls_enabled)
return; return;
secattr->attr.mls.lvl = context->range.level[0].sens - 1; secattr->attr.mls.lvl = context->range.level[0].sens - 1;
...@@ -597,10 +602,11 @@ void mls_export_netlbl_lvl(struct context *context, ...@@ -597,10 +602,11 @@ void mls_export_netlbl_lvl(struct context *context,
* NetLabel MLS sensitivity level into the context. * NetLabel MLS sensitivity level into the context.
* *
*/ */
void mls_import_netlbl_lvl(struct context *context, void mls_import_netlbl_lvl(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
if (!policydb.mls_enabled) if (!p->mls_enabled)
return; return;
context->range.level[0].sens = secattr->attr.mls.lvl + 1; context->range.level[0].sens = secattr->attr.mls.lvl + 1;
...@@ -617,12 +623,13 @@ void mls_import_netlbl_lvl(struct context *context, ...@@ -617,12 +623,13 @@ void mls_import_netlbl_lvl(struct context *context,
* MLS category field. Returns zero on success, negative values on failure. * MLS category field. Returns zero on success, negative values on failure.
* *
*/ */
int mls_export_netlbl_cat(struct context *context, int mls_export_netlbl_cat(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
int rc; int rc;
if (!policydb.mls_enabled) if (!p->mls_enabled)
return 0; return 0;
rc = ebitmap_netlbl_export(&context->range.level[0].cat, rc = ebitmap_netlbl_export(&context->range.level[0].cat,
...@@ -645,12 +652,13 @@ int mls_export_netlbl_cat(struct context *context, ...@@ -645,12 +652,13 @@ int mls_export_netlbl_cat(struct context *context,
* negative values on failure. * negative values on failure.
* *
*/ */
int mls_import_netlbl_cat(struct context *context, int mls_import_netlbl_cat(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
int rc; int rc;
if (!policydb.mls_enabled) if (!p->mls_enabled)
return 0; return 0;
rc = ebitmap_netlbl_import(&context->range.level[0].cat, rc = ebitmap_netlbl_import(&context->range.level[0].cat,
......
...@@ -25,8 +25,9 @@ ...@@ -25,8 +25,9 @@
#include "context.h" #include "context.h"
#include "policydb.h" #include "policydb.h"
int mls_compute_context_len(struct context *context); int mls_compute_context_len(struct policydb *p, struct context *context);
void mls_sid_to_context(struct context *context, char **scontext); void mls_sid_to_context(struct policydb *p, struct context *context,
char **scontext);
int mls_context_isvalid(struct policydb *p, struct context *c); int mls_context_isvalid(struct policydb *p, struct context *c);
int mls_range_isvalid(struct policydb *p, struct mls_range *r); int mls_range_isvalid(struct policydb *p, struct mls_range *r);
int mls_level_isvalid(struct policydb *p, struct mls_level *l); int mls_level_isvalid(struct policydb *p, struct mls_level *l);
...@@ -38,7 +39,8 @@ int mls_context_to_sid(struct policydb *p, ...@@ -38,7 +39,8 @@ int mls_context_to_sid(struct policydb *p,
struct sidtab *s, struct sidtab *s,
u32 def_sid); u32 def_sid);
int mls_from_string(char *str, struct context *context, gfp_t gfp_mask); int mls_from_string(struct policydb *p, char *str, struct context *context,
gfp_t gfp_mask);
int mls_range_set(struct context *context, struct mls_range *range); int mls_range_set(struct context *context, struct mls_range *range);
...@@ -46,42 +48,52 @@ int mls_convert_context(struct policydb *oldp, ...@@ -46,42 +48,52 @@ int mls_convert_context(struct policydb *oldp,
struct policydb *newp, struct policydb *newp,
struct context *context); struct context *context);
int mls_compute_sid(struct context *scontext, int mls_compute_sid(struct policydb *p,
struct context *scontext,
struct context *tcontext, struct context *tcontext,
u16 tclass, u16 tclass,
u32 specified, u32 specified,
struct context *newcontext, struct context *newcontext,
bool sock); bool sock);
int mls_setup_user_range(struct context *fromcon, struct user_datum *user, int mls_setup_user_range(struct policydb *p,
struct context *fromcon, struct user_datum *user,
struct context *usercon); struct context *usercon);
#ifdef CONFIG_NETLABEL #ifdef CONFIG_NETLABEL
void mls_export_netlbl_lvl(struct context *context, void mls_export_netlbl_lvl(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr); struct netlbl_lsm_secattr *secattr);
void mls_import_netlbl_lvl(struct context *context, void mls_import_netlbl_lvl(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr); struct netlbl_lsm_secattr *secattr);
int mls_export_netlbl_cat(struct context *context, int mls_export_netlbl_cat(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr); struct netlbl_lsm_secattr *secattr);
int mls_import_netlbl_cat(struct context *context, int mls_import_netlbl_cat(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr); struct netlbl_lsm_secattr *secattr);
#else #else
static inline void mls_export_netlbl_lvl(struct context *context, static inline void mls_export_netlbl_lvl(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
return; return;
} }
static inline void mls_import_netlbl_lvl(struct context *context, static inline void mls_import_netlbl_lvl(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
return; return;
} }
static inline int mls_export_netlbl_cat(struct context *context, static inline int mls_export_netlbl_cat(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
return -ENOMEM; return -ENOMEM;
} }
static inline int mls_import_netlbl_cat(struct context *context, static inline int mls_import_netlbl_cat(struct policydb *p,
struct context *context,
struct netlbl_lsm_secattr *secattr) struct netlbl_lsm_secattr *secattr)
{ {
return -ENOMEM; return -ENOMEM;
......
...@@ -80,53 +80,32 @@ char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { ...@@ -80,53 +80,32 @@ char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
"nnp_nosuid_transition" "nnp_nosuid_transition"
}; };
int selinux_policycap_netpeer; static struct selinux_ss selinux_ss;
int selinux_policycap_openperm;
int selinux_policycap_extsockclass;
int selinux_policycap_alwaysnetwork;
int selinux_policycap_cgroupseclabel;
int selinux_policycap_nnp_nosuid_transition;
static DEFINE_RWLOCK(policy_rwlock); void selinux_ss_init(struct selinux_ss **ss)
{
static struct sidtab sidtab; rwlock_init(&selinux_ss.policy_rwlock);
struct policydb policydb; mutex_init(&selinux_ss.status_lock);
int ss_initialized; *ss = &selinux_ss;
}
/*
* The largest sequence number that has been used when
* providing an access decision to the access vector cache.
* The sequence number only changes when a policy change
* occurs.
*/
static u32 latest_granting;
/* Forward declaration. */ /* Forward declaration. */
static int context_struct_to_string(struct context *context, char **scontext, static int context_struct_to_string(struct policydb *policydb,
struct context *context,
char **scontext,
u32 *scontext_len); u32 *scontext_len);
static void context_struct_compute_av(struct context *scontext, static void context_struct_compute_av(struct policydb *policydb,
struct context *tcontext, struct context *scontext,
u16 tclass, struct context *tcontext,
struct av_decision *avd, u16 tclass,
struct extended_perms *xperms); struct av_decision *avd,
struct extended_perms *xperms);
struct selinux_mapping {
u16 value; /* policy value */
unsigned num_perms;
u32 perms[sizeof(u32) * 8];
};
static struct selinux_mapping *current_mapping;
static u16 current_mapping_size;
static int selinux_set_mapping(struct policydb *pol, static int selinux_set_mapping(struct policydb *pol,
struct security_class_mapping *map, struct security_class_mapping *map,
struct selinux_mapping **out_map_p, struct selinux_map *out_map)
u16 *out_map_size)
{ {
struct selinux_mapping *out_map = NULL;
size_t size = sizeof(struct selinux_mapping);
u16 i, j; u16 i, j;
unsigned k; unsigned k;
bool print_unknown_handle = false; bool print_unknown_handle = false;
...@@ -139,15 +118,15 @@ static int selinux_set_mapping(struct policydb *pol, ...@@ -139,15 +118,15 @@ static int selinux_set_mapping(struct policydb *pol,
i++; i++;
/* Allocate space for the class records, plus one for class zero */ /* Allocate space for the class records, plus one for class zero */
out_map = kcalloc(++i, size, GFP_ATOMIC); out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
if (!out_map) if (!out_map->mapping)
return -ENOMEM; return -ENOMEM;
/* Store the raw class and permission values */ /* Store the raw class and permission values */
j = 0; j = 0;
while (map[j].name) { while (map[j].name) {
struct security_class_mapping *p_in = map + (j++); struct security_class_mapping *p_in = map + (j++);
struct selinux_mapping *p_out = out_map + j; struct selinux_mapping *p_out = out_map->mapping + j;
/* An empty class string skips ahead */ /* An empty class string skips ahead */
if (!strcmp(p_in->name, "")) { if (!strcmp(p_in->name, "")) {
...@@ -194,11 +173,11 @@ static int selinux_set_mapping(struct policydb *pol, ...@@ -194,11 +173,11 @@ static int selinux_set_mapping(struct policydb *pol,
printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n", printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
pol->allow_unknown ? "allowed" : "denied"); pol->allow_unknown ? "allowed" : "denied");
*out_map_p = out_map; out_map->size = i;
*out_map_size = i;
return 0; return 0;
err: err:
kfree(out_map); kfree(out_map->mapping);
out_map->mapping = NULL;
return -EINVAL; return -EINVAL;
} }
...@@ -206,10 +185,10 @@ static int selinux_set_mapping(struct policydb *pol, ...@@ -206,10 +185,10 @@ static int selinux_set_mapping(struct policydb *pol,
* Get real, policy values from mapped values * Get real, policy values from mapped values
*/ */
static u16 unmap_class(u16 tclass) static u16 unmap_class(struct selinux_map *map, u16 tclass)
{ {
if (tclass < current_mapping_size) if (tclass < map->size)
return current_mapping[tclass].value; return map->mapping[tclass].value;
return tclass; return tclass;
} }
...@@ -217,42 +196,44 @@ static u16 unmap_class(u16 tclass) ...@@ -217,42 +196,44 @@ static u16 unmap_class(u16 tclass)
/* /*
* Get kernel value for class from its policy value * Get kernel value for class from its policy value
*/ */
static u16 map_class(u16 pol_value) static u16 map_class(struct selinux_map *map, u16 pol_value)
{ {
u16 i; u16 i;
for (i = 1; i < current_mapping_size; i++) { for (i = 1; i < map->size; i++) {
if (current_mapping[i].value == pol_value) if (map->mapping[i].value == pol_value)
return i; return i;
} }
return SECCLASS_NULL; return SECCLASS_NULL;
} }
static void map_decision(u16 tclass, struct av_decision *avd, static void map_decision(struct selinux_map *map,
u16 tclass, struct av_decision *avd,
int allow_unknown) int allow_unknown)
{ {
if (tclass < current_mapping_size) { if (tclass < map->size) {
unsigned i, n = current_mapping[tclass].num_perms; struct selinux_mapping *mapping = &map->mapping[tclass];
unsigned int i, n = mapping->num_perms;
u32 result; u32 result;
for (i = 0, result = 0; i < n; i++) { for (i = 0, result = 0; i < n; i++) {
if (avd->allowed & current_mapping[tclass].perms[i]) if (avd->allowed & mapping->perms[i])
result |= 1<<i; result |= 1<<i;
if (allow_unknown && !current_mapping[tclass].perms[i]) if (allow_unknown && !mapping->perms[i])
result |= 1<<i; result |= 1<<i;
} }
avd->allowed = result; avd->allowed = result;
for (i = 0, result = 0; i < n; i++) for (i = 0, result = 0; i < n; i++)
if (avd->auditallow & current_mapping[tclass].perms[i]) if (avd->auditallow & mapping->perms[i])
result |= 1<<i; result |= 1<<i;
avd->auditallow = result; avd->auditallow = result;
for (i = 0, result = 0; i < n; i++) { for (i = 0, result = 0; i < n; i++) {
if (avd->auditdeny & current_mapping[tclass].perms[i]) if (avd->auditdeny & mapping->perms[i])
result |= 1<<i; result |= 1<<i;
if (!allow_unknown && !current_mapping[tclass].perms[i]) if (!allow_unknown && !mapping->perms[i])
result |= 1<<i; result |= 1<<i;
} }
/* /*
...@@ -266,9 +247,11 @@ static void map_decision(u16 tclass, struct av_decision *avd, ...@@ -266,9 +247,11 @@ static void map_decision(u16 tclass, struct av_decision *avd,
} }
} }
int security_mls_enabled(void) int security_mls_enabled(struct selinux_state *state)
{ {
return policydb.mls_enabled; struct policydb *p = &state->ss->policydb;
return p->mls_enabled;
} }
/* /*
...@@ -282,7 +265,8 @@ int security_mls_enabled(void) ...@@ -282,7 +265,8 @@ int security_mls_enabled(void)
* of the process performing the transition. All other callers of * of the process performing the transition. All other callers of
* constraint_expr_eval should pass in NULL for xcontext. * constraint_expr_eval should pass in NULL for xcontext.
*/ */
static int constraint_expr_eval(struct context *scontext, static int constraint_expr_eval(struct policydb *policydb,
struct context *scontext,
struct context *tcontext, struct context *tcontext,
struct context *xcontext, struct context *xcontext,
struct constraint_expr *cexpr) struct constraint_expr *cexpr)
...@@ -326,8 +310,8 @@ static int constraint_expr_eval(struct context *scontext, ...@@ -326,8 +310,8 @@ static int constraint_expr_eval(struct context *scontext,
case CEXPR_ROLE: case CEXPR_ROLE:
val1 = scontext->role; val1 = scontext->role;
val2 = tcontext->role; val2 = tcontext->role;
r1 = policydb.role_val_to_struct[val1 - 1]; r1 = policydb->role_val_to_struct[val1 - 1];
r2 = policydb.role_val_to_struct[val2 - 1]; r2 = policydb->role_val_to_struct[val2 - 1];
switch (e->op) { switch (e->op) {
case CEXPR_DOM: case CEXPR_DOM:
s[++sp] = ebitmap_get_bit(&r1->dominates, s[++sp] = ebitmap_get_bit(&r1->dominates,
...@@ -472,7 +456,8 @@ static int dump_masked_av_helper(void *k, void *d, void *args) ...@@ -472,7 +456,8 @@ static int dump_masked_av_helper(void *k, void *d, void *args)
return 0; return 0;
} }
static void security_dump_masked_av(struct context *scontext, static void security_dump_masked_av(struct policydb *policydb,
struct context *scontext,
struct context *tcontext, struct context *tcontext,
u16 tclass, u16 tclass,
u32 permissions, u32 permissions,
...@@ -492,8 +477,8 @@ static void security_dump_masked_av(struct context *scontext, ...@@ -492,8 +477,8 @@ static void security_dump_masked_av(struct context *scontext,
if (!permissions) if (!permissions)
return; return;
tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1); tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
tclass_dat = policydb.class_val_to_struct[tclass - 1]; tclass_dat = policydb->class_val_to_struct[tclass - 1];
common_dat = tclass_dat->comdatum; common_dat = tclass_dat->comdatum;
/* init permission_names */ /* init permission_names */
...@@ -507,11 +492,11 @@ static void security_dump_masked_av(struct context *scontext, ...@@ -507,11 +492,11 @@ static void security_dump_masked_av(struct context *scontext,
goto out; goto out;
/* get scontext/tcontext in text form */ /* get scontext/tcontext in text form */
if (context_struct_to_string(scontext, if (context_struct_to_string(policydb, scontext,
&scontext_name, &length) < 0) &scontext_name, &length) < 0)
goto out; goto out;
if (context_struct_to_string(tcontext, if (context_struct_to_string(policydb, tcontext,
&tcontext_name, &length) < 0) &tcontext_name, &length) < 0)
goto out; goto out;
...@@ -550,7 +535,8 @@ static void security_dump_masked_av(struct context *scontext, ...@@ -550,7 +535,8 @@ static void security_dump_masked_av(struct context *scontext,
* security_boundary_permission - drops violated permissions * security_boundary_permission - drops violated permissions
* on boundary constraint. * on boundary constraint.
*/ */
static void type_attribute_bounds_av(struct context *scontext, static void type_attribute_bounds_av(struct policydb *policydb,
struct context *scontext,
struct context *tcontext, struct context *tcontext,
u16 tclass, u16 tclass,
struct av_decision *avd) struct av_decision *avd)
...@@ -562,14 +548,14 @@ static void type_attribute_bounds_av(struct context *scontext, ...@@ -562,14 +548,14 @@ static void type_attribute_bounds_av(struct context *scontext,
struct type_datum *target; struct type_datum *target;
u32 masked = 0; u32 masked = 0;
source = flex_array_get_ptr(policydb.type_val_to_struct_array, source = flex_array_get_ptr(policydb->type_val_to_struct_array,
scontext->type - 1); scontext->type - 1);
BUG_ON(!source); BUG_ON(!source);
if (!source->bounds) if (!source->bounds)
return; return;
target = flex_array_get_ptr(policydb.type_val_to_struct_array, target = flex_array_get_ptr(policydb->type_val_to_struct_array,
tcontext->type - 1); tcontext->type - 1);
BUG_ON(!target); BUG_ON(!target);
...@@ -584,7 +570,7 @@ static void type_attribute_bounds_av(struct context *scontext, ...@@ -584,7 +570,7 @@ static void type_attribute_bounds_av(struct context *scontext,
tcontextp = &lo_tcontext; tcontextp = &lo_tcontext;
} }
context_struct_compute_av(&lo_scontext, context_struct_compute_av(policydb, &lo_scontext,
tcontextp, tcontextp,
tclass, tclass,
&lo_avd, &lo_avd,
...@@ -599,7 +585,7 @@ static void type_attribute_bounds_av(struct context *scontext, ...@@ -599,7 +585,7 @@ static void type_attribute_bounds_av(struct context *scontext,
avd->allowed &= ~masked; avd->allowed &= ~masked;
/* audit masked permissions */ /* audit masked permissions */
security_dump_masked_av(scontext, tcontext, security_dump_masked_av(policydb, scontext, tcontext,
tclass, masked, "bounds"); tclass, masked, "bounds");
} }
...@@ -632,11 +618,12 @@ void services_compute_xperms_drivers( ...@@ -632,11 +618,12 @@ void services_compute_xperms_drivers(
* Compute access vectors and extended permissions based on a context * Compute access vectors and extended permissions based on a context
* structure pair for the permissions in a particular class. * structure pair for the permissions in a particular class.
*/ */
static void context_struct_compute_av(struct context *scontext, static void context_struct_compute_av(struct policydb *policydb,
struct context *tcontext, struct context *scontext,
u16 tclass, struct context *tcontext,
struct av_decision *avd, u16 tclass,
struct extended_perms *xperms) struct av_decision *avd,
struct extended_perms *xperms)
{ {
struct constraint_node *constraint; struct constraint_node *constraint;
struct role_allow *ra; struct role_allow *ra;
...@@ -655,13 +642,13 @@ static void context_struct_compute_av(struct context *scontext, ...@@ -655,13 +642,13 @@ static void context_struct_compute_av(struct context *scontext,
xperms->len = 0; xperms->len = 0;
} }
if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass);
return; return;
} }
tclass_datum = policydb.class_val_to_struct[tclass - 1]; tclass_datum = policydb->class_val_to_struct[tclass - 1];
/* /*
* If a specific type enforcement rule was defined for * If a specific type enforcement rule was defined for
...@@ -669,15 +656,18 @@ static void context_struct_compute_av(struct context *scontext, ...@@ -669,15 +656,18 @@ static void context_struct_compute_av(struct context *scontext,
*/ */
avkey.target_class = tclass; avkey.target_class = tclass;
avkey.specified = AVTAB_AV | AVTAB_XPERMS; avkey.specified = AVTAB_AV | AVTAB_XPERMS;
sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); sattr = flex_array_get(policydb->type_attr_map_array,
scontext->type - 1);
BUG_ON(!sattr); BUG_ON(!sattr);
tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); tattr = flex_array_get(policydb->type_attr_map_array,
tcontext->type - 1);
BUG_ON(!tattr); BUG_ON(!tattr);
ebitmap_for_each_positive_bit(sattr, snode, i) { ebitmap_for_each_positive_bit(sattr, snode, i) {
ebitmap_for_each_positive_bit(tattr, tnode, j) { ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1; avkey.source_type = i + 1;
avkey.target_type = j + 1; avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey); for (node = avtab_search_node(&policydb->te_avtab,
&avkey);
node; node;
node = avtab_search_node_next(node, avkey.specified)) { node = avtab_search_node_next(node, avkey.specified)) {
if (node->key.specified == AVTAB_ALLOWED) if (node->key.specified == AVTAB_ALLOWED)
...@@ -691,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext, ...@@ -691,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext,
} }
/* Check conditional av table for additional permissions */ /* Check conditional av table for additional permissions */
cond_compute_av(&policydb.te_cond_avtab, &avkey, cond_compute_av(&policydb->te_cond_avtab, &avkey,
avd, xperms); avd, xperms);
} }
...@@ -704,7 +694,7 @@ static void context_struct_compute_av(struct context *scontext, ...@@ -704,7 +694,7 @@ static void context_struct_compute_av(struct context *scontext,
constraint = tclass_datum->constraints; constraint = tclass_datum->constraints;
while (constraint) { while (constraint) {
if ((constraint->permissions & (avd->allowed)) && if ((constraint->permissions & (avd->allowed)) &&
!constraint_expr_eval(scontext, tcontext, NULL, !constraint_expr_eval(policydb, scontext, tcontext, NULL,
constraint->expr)) { constraint->expr)) {
avd->allowed &= ~(constraint->permissions); avd->allowed &= ~(constraint->permissions);
} }
...@@ -716,16 +706,16 @@ static void context_struct_compute_av(struct context *scontext, ...@@ -716,16 +706,16 @@ static void context_struct_compute_av(struct context *scontext,
* role is changing, then check the (current_role, new_role) * role is changing, then check the (current_role, new_role)
* pair. * pair.
*/ */
if (tclass == policydb.process_class && if (tclass == policydb->process_class &&
(avd->allowed & policydb.process_trans_perms) && (avd->allowed & policydb->process_trans_perms) &&
scontext->role != tcontext->role) { scontext->role != tcontext->role) {
for (ra = policydb.role_allow; ra; ra = ra->next) { for (ra = policydb->role_allow; ra; ra = ra->next) {
if (scontext->role == ra->role && if (scontext->role == ra->role &&
tcontext->role == ra->new_role) tcontext->role == ra->new_role)
break; break;
} }
if (!ra) if (!ra)
avd->allowed &= ~policydb.process_trans_perms; avd->allowed &= ~policydb->process_trans_perms;
} }
/* /*
...@@ -733,41 +723,46 @@ static void context_struct_compute_av(struct context *scontext, ...@@ -733,41 +723,46 @@ static void context_struct_compute_av(struct context *scontext,
* constraint, lazy checks have to mask any violated * constraint, lazy checks have to mask any violated
* permission and notice it to userspace via audit. * permission and notice it to userspace via audit.
*/ */
type_attribute_bounds_av(scontext, tcontext, type_attribute_bounds_av(policydb, scontext, tcontext,
tclass, avd); tclass, avd);
} }
static int security_validtrans_handle_fail(struct context *ocontext, static int security_validtrans_handle_fail(struct selinux_state *state,
struct context *ocontext,
struct context *ncontext, struct context *ncontext,
struct context *tcontext, struct context *tcontext,
u16 tclass) u16 tclass)
{ {
struct policydb *p = &state->ss->policydb;
char *o = NULL, *n = NULL, *t = NULL; char *o = NULL, *n = NULL, *t = NULL;
u32 olen, nlen, tlen; u32 olen, nlen, tlen;
if (context_struct_to_string(ocontext, &o, &olen)) if (context_struct_to_string(p, ocontext, &o, &olen))
goto out; goto out;
if (context_struct_to_string(ncontext, &n, &nlen)) if (context_struct_to_string(p, ncontext, &n, &nlen))
goto out; goto out;
if (context_struct_to_string(tcontext, &t, &tlen)) if (context_struct_to_string(p, tcontext, &t, &tlen))
goto out; goto out;
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_validate_transition seresult=denied" "op=security_validate_transition seresult=denied"
" oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
out: out:
kfree(o); kfree(o);
kfree(n); kfree(n);
kfree(t); kfree(t);
if (!selinux_enforcing) if (!enforcing_enabled(state))
return 0; return 0;
return -EPERM; return -EPERM;
} }
static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, static int security_compute_validatetrans(struct selinux_state *state,
u32 oldsid, u32 newsid, u32 tasksid,
u16 orig_tclass, bool user) u16 orig_tclass, bool user)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct context *ocontext; struct context *ocontext;
struct context *ncontext; struct context *ncontext;
struct context *tcontext; struct context *tcontext;
...@@ -776,23 +771,27 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, ...@@ -776,23 +771,27 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass; u16 tclass;
int rc = 0; int rc = 0;
if (!ss_initialized)
if (!state->initialized)
return 0; return 0;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
if (!user) if (!user)
tclass = unmap_class(orig_tclass); tclass = unmap_class(&state->ss->map, orig_tclass);
else else
tclass = orig_tclass; tclass = orig_tclass;
if (!tclass || tclass > policydb.p_classes.nprim) { if (!tclass || tclass > policydb->p_classes.nprim) {
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
tclass_datum = policydb.class_val_to_struct[tclass - 1]; tclass_datum = policydb->class_val_to_struct[tclass - 1];
ocontext = sidtab_search(&sidtab, oldsid); ocontext = sidtab_search(sidtab, oldsid);
if (!ocontext) { if (!ocontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, oldsid); __func__, oldsid);
...@@ -800,7 +799,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, ...@@ -800,7 +799,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
goto out; goto out;
} }
ncontext = sidtab_search(&sidtab, newsid); ncontext = sidtab_search(sidtab, newsid);
if (!ncontext) { if (!ncontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, newsid); __func__, newsid);
...@@ -808,7 +807,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, ...@@ -808,7 +807,7 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
goto out; goto out;
} }
tcontext = sidtab_search(&sidtab, tasksid); tcontext = sidtab_search(sidtab, tasksid);
if (!tcontext) { if (!tcontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, tasksid); __func__, tasksid);
...@@ -818,12 +817,13 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, ...@@ -818,12 +817,13 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
constraint = tclass_datum->validatetrans; constraint = tclass_datum->validatetrans;
while (constraint) { while (constraint) {
if (!constraint_expr_eval(ocontext, ncontext, tcontext, if (!constraint_expr_eval(policydb, ocontext, ncontext,
constraint->expr)) { tcontext, constraint->expr)) {
if (user) if (user)
rc = -EPERM; rc = -EPERM;
else else
rc = security_validtrans_handle_fail(ocontext, rc = security_validtrans_handle_fail(state,
ocontext,
ncontext, ncontext,
tcontext, tcontext,
tclass); tclass);
...@@ -833,22 +833,24 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, ...@@ -833,22 +833,24 @@ static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
} }
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid, int security_validate_transition_user(struct selinux_state *state,
u16 tclass) u32 oldsid, u32 newsid, u32 tasksid,
u16 tclass)
{ {
return security_compute_validatetrans(oldsid, newsid, tasksid, return security_compute_validatetrans(state, oldsid, newsid, tasksid,
tclass, true); tclass, true);
} }
int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, int security_validate_transition(struct selinux_state *state,
u32 oldsid, u32 newsid, u32 tasksid,
u16 orig_tclass) u16 orig_tclass)
{ {
return security_compute_validatetrans(oldsid, newsid, tasksid, return security_compute_validatetrans(state, oldsid, newsid, tasksid,
orig_tclass, false); orig_tclass, false);
} }
/* /*
...@@ -860,20 +862,26 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, ...@@ -860,20 +862,26 @@ int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
* @oldsid : current security identifier * @oldsid : current security identifier
* @newsid : destinated security identifier * @newsid : destinated security identifier
*/ */
int security_bounded_transition(u32 old_sid, u32 new_sid) int security_bounded_transition(struct selinux_state *state,
u32 old_sid, u32 new_sid)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct context *old_context, *new_context; struct context *old_context, *new_context;
struct type_datum *type; struct type_datum *type;
int index; int index;
int rc; int rc;
if (!ss_initialized) if (!state->initialized)
return 0; return 0;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
rc = -EINVAL; rc = -EINVAL;
old_context = sidtab_search(&sidtab, old_sid); old_context = sidtab_search(sidtab, old_sid);
if (!old_context) { if (!old_context) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
__func__, old_sid); __func__, old_sid);
...@@ -881,7 +889,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) ...@@ -881,7 +889,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
} }
rc = -EINVAL; rc = -EINVAL;
new_context = sidtab_search(&sidtab, new_sid); new_context = sidtab_search(sidtab, new_sid);
if (!new_context) { if (!new_context) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
__func__, new_sid); __func__, new_sid);
...@@ -895,7 +903,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) ...@@ -895,7 +903,7 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
index = new_context->type; index = new_context->type;
while (true) { while (true) {
type = flex_array_get_ptr(policydb.type_val_to_struct_array, type = flex_array_get_ptr(policydb->type_val_to_struct_array,
index - 1); index - 1);
BUG_ON(!type); BUG_ON(!type);
...@@ -917,9 +925,9 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) ...@@ -917,9 +925,9 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
char *new_name = NULL; char *new_name = NULL;
u32 length; u32 length;
if (!context_struct_to_string(old_context, if (!context_struct_to_string(policydb, old_context,
&old_name, &length) && &old_name, &length) &&
!context_struct_to_string(new_context, !context_struct_to_string(policydb, new_context,
&new_name, &length)) { &new_name, &length)) {
audit_log(current->audit_context, audit_log(current->audit_context,
GFP_ATOMIC, AUDIT_SELINUX_ERR, GFP_ATOMIC, AUDIT_SELINUX_ERR,
...@@ -932,17 +940,17 @@ int security_bounded_transition(u32 old_sid, u32 new_sid) ...@@ -932,17 +940,17 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)
kfree(old_name); kfree(old_name);
} }
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
static void avd_init(struct av_decision *avd) static void avd_init(struct selinux_state *state, struct av_decision *avd)
{ {
avd->allowed = 0; avd->allowed = 0;
avd->auditallow = 0; avd->auditallow = 0;
avd->auditdeny = 0xffffffff; avd->auditdeny = 0xffffffff;
avd->seqno = latest_granting; avd->seqno = state->ss->latest_granting;
avd->flags = 0; avd->flags = 0;
} }
...@@ -1000,12 +1008,15 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd, ...@@ -1000,12 +1008,15 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
} }
} }
void security_compute_xperms_decision(u32 ssid, void security_compute_xperms_decision(struct selinux_state *state,
u32 tsid, u32 ssid,
u16 orig_tclass, u32 tsid,
u8 driver, u16 orig_tclass,
struct extended_perms_decision *xpermd) u8 driver,
struct extended_perms_decision *xpermd)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
u16 tclass; u16 tclass;
struct context *scontext, *tcontext; struct context *scontext, *tcontext;
struct avtab_key avkey; struct avtab_key avkey;
...@@ -1020,60 +1031,64 @@ void security_compute_xperms_decision(u32 ssid, ...@@ -1020,60 +1031,64 @@ void security_compute_xperms_decision(u32 ssid,
memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
if (!ss_initialized) if (!state->initialized)
goto allow; goto allow;
scontext = sidtab_search(&sidtab, ssid); policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) { if (!scontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, ssid); __func__, ssid);
goto out; goto out;
} }
tcontext = sidtab_search(&sidtab, tsid); tcontext = sidtab_search(sidtab, tsid);
if (!tcontext) { if (!tcontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, tsid); __func__, tsid);
goto out; goto out;
} }
tclass = unmap_class(orig_tclass); tclass = unmap_class(&state->ss->map, orig_tclass);
if (unlikely(orig_tclass && !tclass)) { if (unlikely(orig_tclass && !tclass)) {
if (policydb.allow_unknown) if (policydb->allow_unknown)
goto allow; goto allow;
goto out; goto out;
} }
if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass);
goto out; goto out;
} }
avkey.target_class = tclass; avkey.target_class = tclass;
avkey.specified = AVTAB_XPERMS; avkey.specified = AVTAB_XPERMS;
sattr = flex_array_get(policydb.type_attr_map_array, sattr = flex_array_get(policydb->type_attr_map_array,
scontext->type - 1); scontext->type - 1);
BUG_ON(!sattr); BUG_ON(!sattr);
tattr = flex_array_get(policydb.type_attr_map_array, tattr = flex_array_get(policydb->type_attr_map_array,
tcontext->type - 1); tcontext->type - 1);
BUG_ON(!tattr); BUG_ON(!tattr);
ebitmap_for_each_positive_bit(sattr, snode, i) { ebitmap_for_each_positive_bit(sattr, snode, i) {
ebitmap_for_each_positive_bit(tattr, tnode, j) { ebitmap_for_each_positive_bit(tattr, tnode, j) {
avkey.source_type = i + 1; avkey.source_type = i + 1;
avkey.target_type = j + 1; avkey.target_type = j + 1;
for (node = avtab_search_node(&policydb.te_avtab, &avkey); for (node = avtab_search_node(&policydb->te_avtab,
&avkey);
node; node;
node = avtab_search_node_next(node, avkey.specified)) node = avtab_search_node_next(node, avkey.specified))
services_compute_xperms_decision(xpermd, node); services_compute_xperms_decision(xpermd, node);
cond_compute_xperms(&policydb.te_cond_avtab, cond_compute_xperms(&policydb->te_cond_avtab,
&avkey, xpermd); &avkey, xpermd);
} }
} }
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return; return;
allow: allow:
memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
...@@ -1091,22 +1106,28 @@ void security_compute_xperms_decision(u32 ssid, ...@@ -1091,22 +1106,28 @@ void security_compute_xperms_decision(u32 ssid,
* Compute a set of access vector decisions based on the * Compute a set of access vector decisions based on the
* SID pair (@ssid, @tsid) for the permissions in @tclass. * SID pair (@ssid, @tsid) for the permissions in @tclass.
*/ */
void security_compute_av(u32 ssid, void security_compute_av(struct selinux_state *state,
u32 ssid,
u32 tsid, u32 tsid,
u16 orig_tclass, u16 orig_tclass,
struct av_decision *avd, struct av_decision *avd,
struct extended_perms *xperms) struct extended_perms *xperms)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
u16 tclass; u16 tclass;
struct context *scontext = NULL, *tcontext = NULL; struct context *scontext = NULL, *tcontext = NULL;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
avd_init(avd); avd_init(state, avd);
xperms->len = 0; xperms->len = 0;
if (!ss_initialized) if (!state->initialized)
goto allow; goto allow;
scontext = sidtab_search(&sidtab, ssid); policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) { if (!scontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, ssid); __func__, ssid);
...@@ -1114,45 +1135,53 @@ void security_compute_av(u32 ssid, ...@@ -1114,45 +1135,53 @@ void security_compute_av(u32 ssid,
} }
/* permissive domain? */ /* permissive domain? */
if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
avd->flags |= AVD_FLAGS_PERMISSIVE; avd->flags |= AVD_FLAGS_PERMISSIVE;
tcontext = sidtab_search(&sidtab, tsid); tcontext = sidtab_search(sidtab, tsid);
if (!tcontext) { if (!tcontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, tsid); __func__, tsid);
goto out; goto out;
} }
tclass = unmap_class(orig_tclass); tclass = unmap_class(&state->ss->map, orig_tclass);
if (unlikely(orig_tclass && !tclass)) { if (unlikely(orig_tclass && !tclass)) {
if (policydb.allow_unknown) if (policydb->allow_unknown)
goto allow; goto allow;
goto out; goto out;
} }
context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
map_decision(orig_tclass, avd, policydb.allow_unknown); xperms);
map_decision(&state->ss->map, orig_tclass, avd,
policydb->allow_unknown);
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return; return;
allow: allow:
avd->allowed = 0xffffffff; avd->allowed = 0xffffffff;
goto out; goto out;
} }
void security_compute_av_user(u32 ssid, void security_compute_av_user(struct selinux_state *state,
u32 ssid,
u32 tsid, u32 tsid,
u16 tclass, u16 tclass,
struct av_decision *avd) struct av_decision *avd)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct context *scontext = NULL, *tcontext = NULL; struct context *scontext = NULL, *tcontext = NULL;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
avd_init(avd); avd_init(state, avd);
if (!ss_initialized) if (!state->initialized)
goto allow; goto allow;
scontext = sidtab_search(&sidtab, ssid); policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) { if (!scontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, ssid); __func__, ssid);
...@@ -1160,10 +1189,10 @@ void security_compute_av_user(u32 ssid, ...@@ -1160,10 +1189,10 @@ void security_compute_av_user(u32 ssid,
} }
/* permissive domain? */ /* permissive domain? */
if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
avd->flags |= AVD_FLAGS_PERMISSIVE; avd->flags |= AVD_FLAGS_PERMISSIVE;
tcontext = sidtab_search(&sidtab, tsid); tcontext = sidtab_search(sidtab, tsid);
if (!tcontext) { if (!tcontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, tsid); __func__, tsid);
...@@ -1171,14 +1200,15 @@ void security_compute_av_user(u32 ssid, ...@@ -1171,14 +1200,15 @@ void security_compute_av_user(u32 ssid,
} }
if (unlikely(!tclass)) { if (unlikely(!tclass)) {
if (policydb.allow_unknown) if (policydb->allow_unknown)
goto allow; goto allow;
goto out; goto out;
} }
context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
NULL);
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return; return;
allow: allow:
avd->allowed = 0xffffffff; avd->allowed = 0xffffffff;
...@@ -1192,7 +1222,9 @@ void security_compute_av_user(u32 ssid, ...@@ -1192,7 +1222,9 @@ void security_compute_av_user(u32 ssid,
* to point to this string and set `*scontext_len' to * to point to this string and set `*scontext_len' to
* the length of the string. * the length of the string.
*/ */
static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len) static int context_struct_to_string(struct policydb *p,
struct context *context,
char **scontext, u32 *scontext_len)
{ {
char *scontextp; char *scontextp;
...@@ -1211,10 +1243,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 ...@@ -1211,10 +1243,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
} }
/* Compute the size of the context. */ /* Compute the size of the context. */
*scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1; *scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
*scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1; *scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
*scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1; *scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
*scontext_len += mls_compute_context_len(context); *scontext_len += mls_compute_context_len(p, context);
if (!scontext) if (!scontext)
return 0; return 0;
...@@ -1229,11 +1261,11 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 ...@@ -1229,11 +1261,11 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
* Copy the user name, role name and type name into the context. * Copy the user name, role name and type name into the context.
*/ */
scontextp += sprintf(scontextp, "%s:%s:%s", scontextp += sprintf(scontextp, "%s:%s:%s",
sym_name(&policydb, SYM_USERS, context->user - 1), sym_name(p, SYM_USERS, context->user - 1),
sym_name(&policydb, SYM_ROLES, context->role - 1), sym_name(p, SYM_ROLES, context->role - 1),
sym_name(&policydb, SYM_TYPES, context->type - 1)); sym_name(p, SYM_TYPES, context->type - 1));
mls_sid_to_context(context, &scontextp); mls_sid_to_context(p, context, &scontextp);
*scontextp = 0; *scontextp = 0;
...@@ -1249,9 +1281,12 @@ const char *security_get_initial_sid_context(u32 sid) ...@@ -1249,9 +1281,12 @@ const char *security_get_initial_sid_context(u32 sid)
return initial_sid_to_string[sid]; return initial_sid_to_string[sid];
} }
static int security_sid_to_context_core(u32 sid, char **scontext, static int security_sid_to_context_core(struct selinux_state *state,
u32 sid, char **scontext,
u32 *scontext_len, int force) u32 *scontext_len, int force)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct context *context; struct context *context;
int rc = 0; int rc = 0;
...@@ -1259,7 +1294,7 @@ static int security_sid_to_context_core(u32 sid, char **scontext, ...@@ -1259,7 +1294,7 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
*scontext = NULL; *scontext = NULL;
*scontext_len = 0; *scontext_len = 0;
if (!ss_initialized) { if (!state->initialized) {
if (sid <= SECINITSID_NUM) { if (sid <= SECINITSID_NUM) {
char *scontextp; char *scontextp;
...@@ -1280,20 +1315,23 @@ static int security_sid_to_context_core(u32 sid, char **scontext, ...@@ -1280,20 +1315,23 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
rc = -EINVAL; rc = -EINVAL;
goto out; goto out;
} }
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
if (force) if (force)
context = sidtab_search_force(&sidtab, sid); context = sidtab_search_force(sidtab, sid);
else else
context = sidtab_search(&sidtab, sid); context = sidtab_search(sidtab, sid);
if (!context) { if (!context) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, sid); __func__, sid);
rc = -EINVAL; rc = -EINVAL;
goto out_unlock; goto out_unlock;
} }
rc = context_struct_to_string(context, scontext, scontext_len); rc = context_struct_to_string(policydb, context, scontext,
scontext_len);
out_unlock: out_unlock:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
out: out:
return rc; return rc;
...@@ -1309,14 +1347,18 @@ static int security_sid_to_context_core(u32 sid, char **scontext, ...@@ -1309,14 +1347,18 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
* into a dynamically allocated string of the correct size. Set @scontext * into a dynamically allocated string of the correct size. Set @scontext
* to point to this string and set @scontext_len to the length of the string. * to point to this string and set @scontext_len to the length of the string.
*/ */
int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) int security_sid_to_context(struct selinux_state *state,
u32 sid, char **scontext, u32 *scontext_len)
{ {
return security_sid_to_context_core(sid, scontext, scontext_len, 0); return security_sid_to_context_core(state, sid, scontext,
scontext_len, 0);
} }
int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) int security_sid_to_context_force(struct selinux_state *state, u32 sid,
char **scontext, u32 *scontext_len)
{ {
return security_sid_to_context_core(sid, scontext, scontext_len, 1); return security_sid_to_context_core(state, sid, scontext,
scontext_len, 1);
} }
/* /*
...@@ -1404,10 +1446,13 @@ static int string_to_context_struct(struct policydb *pol, ...@@ -1404,10 +1446,13 @@ static int string_to_context_struct(struct policydb *pol,
return rc; return rc;
} }
static int security_context_to_sid_core(const char *scontext, u32 scontext_len, static int security_context_to_sid_core(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags, u32 *sid, u32 def_sid, gfp_t gfp_flags,
int force) int force)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
char *scontext2, *str = NULL; char *scontext2, *str = NULL;
struct context context; struct context context;
int rc = 0; int rc = 0;
...@@ -1421,7 +1466,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, ...@@ -1421,7 +1466,7 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
if (!scontext2) if (!scontext2)
return -ENOMEM; return -ENOMEM;
if (!ss_initialized) { if (!state->initialized) {
int i; int i;
for (i = 1; i < SECINITSID_NUM; i++) { for (i = 1; i < SECINITSID_NUM; i++) {
...@@ -1442,9 +1487,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, ...@@ -1442,9 +1487,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
if (!str) if (!str)
goto out; goto out;
} }
read_lock(&state->ss->policy_rwlock);
read_lock(&policy_rwlock); policydb = &state->ss->policydb;
rc = string_to_context_struct(&policydb, &sidtab, scontext2, sidtab = &state->ss->sidtab;
rc = string_to_context_struct(policydb, sidtab, scontext2,
scontext_len, &context, def_sid); scontext_len, &context, def_sid);
if (rc == -EINVAL && force) { if (rc == -EINVAL && force) {
context.str = str; context.str = str;
...@@ -1452,10 +1498,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, ...@@ -1452,10 +1498,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
str = NULL; str = NULL;
} else if (rc) } else if (rc)
goto out_unlock; goto out_unlock;
rc = sidtab_context_to_sid(&sidtab, &context, sid); rc = sidtab_context_to_sid(sidtab, &context, sid);
context_destroy(&context); context_destroy(&context);
out_unlock: out_unlock:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
out: out:
kfree(scontext2); kfree(scontext2);
kfree(str); kfree(str);
...@@ -1474,16 +1520,19 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len, ...@@ -1474,16 +1520,19 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success. * memory is available, or 0 on success.
*/ */
int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, int security_context_to_sid(struct selinux_state *state,
const char *scontext, u32 scontext_len, u32 *sid,
gfp_t gfp) gfp_t gfp)
{ {
return security_context_to_sid_core(scontext, scontext_len, return security_context_to_sid_core(state, scontext, scontext_len,
sid, SECSID_NULL, gfp, 0); sid, SECSID_NULL, gfp, 0);
} }
int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp) int security_context_str_to_sid(struct selinux_state *state,
const char *scontext, u32 *sid, gfp_t gfp)
{ {
return security_context_to_sid(scontext, strlen(scontext), sid, gfp); return security_context_to_sid(state, scontext, strlen(scontext),
sid, gfp);
} }
/** /**
...@@ -1504,51 +1553,56 @@ int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp) ...@@ -1504,51 +1553,56 @@ int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success. * memory is available, or 0 on success.
*/ */
int security_context_to_sid_default(const char *scontext, u32 scontext_len, int security_context_to_sid_default(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags) u32 *sid, u32 def_sid, gfp_t gfp_flags)
{ {
return security_context_to_sid_core(scontext, scontext_len, return security_context_to_sid_core(state, scontext, scontext_len,
sid, def_sid, gfp_flags, 1); sid, def_sid, gfp_flags, 1);
} }
int security_context_to_sid_force(const char *scontext, u32 scontext_len, int security_context_to_sid_force(struct selinux_state *state,
const char *scontext, u32 scontext_len,
u32 *sid) u32 *sid)
{ {
return security_context_to_sid_core(scontext, scontext_len, return security_context_to_sid_core(state, scontext, scontext_len,
sid, SECSID_NULL, GFP_KERNEL, 1); sid, SECSID_NULL, GFP_KERNEL, 1);
} }
static int compute_sid_handle_invalid_context( static int compute_sid_handle_invalid_context(
struct selinux_state *state,
struct context *scontext, struct context *scontext,
struct context *tcontext, struct context *tcontext,
u16 tclass, u16 tclass,
struct context *newcontext) struct context *newcontext)
{ {
struct policydb *policydb = &state->ss->policydb;
char *s = NULL, *t = NULL, *n = NULL; char *s = NULL, *t = NULL, *n = NULL;
u32 slen, tlen, nlen; u32 slen, tlen, nlen;
if (context_struct_to_string(scontext, &s, &slen)) if (context_struct_to_string(policydb, scontext, &s, &slen))
goto out; goto out;
if (context_struct_to_string(tcontext, &t, &tlen)) if (context_struct_to_string(policydb, tcontext, &t, &tlen))
goto out; goto out;
if (context_struct_to_string(newcontext, &n, &nlen)) if (context_struct_to_string(policydb, newcontext, &n, &nlen))
goto out; goto out;
audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_compute_sid invalid_context=%s" "op=security_compute_sid invalid_context=%s"
" scontext=%s" " scontext=%s"
" tcontext=%s" " tcontext=%s"
" tclass=%s", " tclass=%s",
n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); n, s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
out: out:
kfree(s); kfree(s);
kfree(t); kfree(t);
kfree(n); kfree(n);
if (!selinux_enforcing) if (!enforcing_enabled(state))
return 0; return 0;
return -EACCES; return -EACCES;
} }
static void filename_compute_type(struct policydb *p, struct context *newcontext, static void filename_compute_type(struct policydb *policydb,
struct context *newcontext,
u32 stype, u32 ttype, u16 tclass, u32 stype, u32 ttype, u16 tclass,
const char *objname) const char *objname)
{ {
...@@ -1560,7 +1614,7 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext ...@@ -1560,7 +1614,7 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
* like /dev or /var/run. This bitmap will quickly skip rule searches * like /dev or /var/run. This bitmap will quickly skip rule searches
* if the ttype does not contain any rules. * if the ttype does not contain any rules.
*/ */
if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
return; return;
ft.stype = stype; ft.stype = stype;
...@@ -1568,12 +1622,13 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext ...@@ -1568,12 +1622,13 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
ft.tclass = tclass; ft.tclass = tclass;
ft.name = objname; ft.name = objname;
otype = hashtab_search(p->filename_trans, &ft); otype = hashtab_search(policydb->filename_trans, &ft);
if (otype) if (otype)
newcontext->type = otype->otype; newcontext->type = otype->otype;
} }
static int security_compute_sid(u32 ssid, static int security_compute_sid(struct selinux_state *state,
u32 ssid,
u32 tsid, u32 tsid,
u16 orig_tclass, u16 orig_tclass,
u32 specified, u32 specified,
...@@ -1581,6 +1636,8 @@ static int security_compute_sid(u32 ssid, ...@@ -1581,6 +1636,8 @@ static int security_compute_sid(u32 ssid,
u32 *out_sid, u32 *out_sid,
bool kern) bool kern)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct class_datum *cladatum = NULL; struct class_datum *cladatum = NULL;
struct context *scontext = NULL, *tcontext = NULL, newcontext; struct context *scontext = NULL, *tcontext = NULL, newcontext;
struct role_trans *roletr = NULL; struct role_trans *roletr = NULL;
...@@ -1591,7 +1648,7 @@ static int security_compute_sid(u32 ssid, ...@@ -1591,7 +1648,7 @@ static int security_compute_sid(u32 ssid,
int rc = 0; int rc = 0;
bool sock; bool sock;
if (!ss_initialized) { if (!state->initialized) {
switch (orig_tclass) { switch (orig_tclass) {
case SECCLASS_PROCESS: /* kernel value */ case SECCLASS_PROCESS: /* kernel value */
*out_sid = ssid; *out_sid = ssid;
...@@ -1605,24 +1662,28 @@ static int security_compute_sid(u32 ssid, ...@@ -1605,24 +1662,28 @@ static int security_compute_sid(u32 ssid,
context_init(&newcontext); context_init(&newcontext);
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
if (kern) { if (kern) {
tclass = unmap_class(orig_tclass); tclass = unmap_class(&state->ss->map, orig_tclass);
sock = security_is_socket_class(orig_tclass); sock = security_is_socket_class(orig_tclass);
} else { } else {
tclass = orig_tclass; tclass = orig_tclass;
sock = security_is_socket_class(map_class(tclass)); sock = security_is_socket_class(map_class(&state->ss->map,
tclass));
} }
scontext = sidtab_search(&sidtab, ssid); policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
scontext = sidtab_search(sidtab, ssid);
if (!scontext) { if (!scontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, ssid); __func__, ssid);
rc = -EINVAL; rc = -EINVAL;
goto out_unlock; goto out_unlock;
} }
tcontext = sidtab_search(&sidtab, tsid); tcontext = sidtab_search(sidtab, tsid);
if (!tcontext) { if (!tcontext) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, tsid); __func__, tsid);
...@@ -1630,8 +1691,8 @@ static int security_compute_sid(u32 ssid, ...@@ -1630,8 +1691,8 @@ static int security_compute_sid(u32 ssid,
goto out_unlock; goto out_unlock;
} }
if (tclass && tclass <= policydb.p_classes.nprim) if (tclass && tclass <= policydb->p_classes.nprim)
cladatum = policydb.class_val_to_struct[tclass - 1]; cladatum = policydb->class_val_to_struct[tclass - 1];
/* Set the user identity. */ /* Set the user identity. */
switch (specified) { switch (specified) {
...@@ -1657,7 +1718,7 @@ static int security_compute_sid(u32 ssid, ...@@ -1657,7 +1718,7 @@ static int security_compute_sid(u32 ssid,
} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
newcontext.role = tcontext->role; newcontext.role = tcontext->role;
} else { } else {
if ((tclass == policydb.process_class) || (sock == true)) if ((tclass == policydb->process_class) || (sock == true))
newcontext.role = scontext->role; newcontext.role = scontext->role;
else else
newcontext.role = OBJECT_R_VAL; newcontext.role = OBJECT_R_VAL;
...@@ -1669,7 +1730,7 @@ static int security_compute_sid(u32 ssid, ...@@ -1669,7 +1730,7 @@ static int security_compute_sid(u32 ssid,
} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
newcontext.type = tcontext->type; newcontext.type = tcontext->type;
} else { } else {
if ((tclass == policydb.process_class) || (sock == true)) { if ((tclass == policydb->process_class) || (sock == true)) {
/* Use the type of process. */ /* Use the type of process. */
newcontext.type = scontext->type; newcontext.type = scontext->type;
} else { } else {
...@@ -1683,11 +1744,11 @@ static int security_compute_sid(u32 ssid, ...@@ -1683,11 +1744,11 @@ static int security_compute_sid(u32 ssid,
avkey.target_type = tcontext->type; avkey.target_type = tcontext->type;
avkey.target_class = tclass; avkey.target_class = tclass;
avkey.specified = specified; avkey.specified = specified;
avdatum = avtab_search(&policydb.te_avtab, &avkey); avdatum = avtab_search(&policydb->te_avtab, &avkey);
/* If no permanent rule, also check for enabled conditional rules */ /* If no permanent rule, also check for enabled conditional rules */
if (!avdatum) { if (!avdatum) {
node = avtab_search_node(&policydb.te_cond_avtab, &avkey); node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
for (; node; node = avtab_search_node_next(node, specified)) { for (; node; node = avtab_search_node_next(node, specified)) {
if (node->key.specified & AVTAB_ENABLED) { if (node->key.specified & AVTAB_ENABLED) {
avdatum = &node->datum; avdatum = &node->datum;
...@@ -1703,13 +1764,14 @@ static int security_compute_sid(u32 ssid, ...@@ -1703,13 +1764,14 @@ static int security_compute_sid(u32 ssid,
/* if we have a objname this is a file trans check so check those rules */ /* if we have a objname this is a file trans check so check those rules */
if (objname) if (objname)
filename_compute_type(&policydb, &newcontext, scontext->type, filename_compute_type(policydb, &newcontext, scontext->type,
tcontext->type, tclass, objname); tcontext->type, tclass, objname);
/* Check for class-specific changes. */ /* Check for class-specific changes. */
if (specified & AVTAB_TRANSITION) { if (specified & AVTAB_TRANSITION) {
/* Look for a role transition rule. */ /* Look for a role transition rule. */
for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { for (roletr = policydb->role_tr; roletr;
roletr = roletr->next) {
if ((roletr->role == scontext->role) && if ((roletr->role == scontext->role) &&
(roletr->type == tcontext->type) && (roletr->type == tcontext->type) &&
(roletr->tclass == tclass)) { (roletr->tclass == tclass)) {
...@@ -1722,14 +1784,14 @@ static int security_compute_sid(u32 ssid, ...@@ -1722,14 +1784,14 @@ static int security_compute_sid(u32 ssid,
/* Set the MLS attributes. /* Set the MLS attributes.
This is done last because it may allocate memory. */ This is done last because it may allocate memory. */
rc = mls_compute_sid(scontext, tcontext, tclass, specified, rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
&newcontext, sock); &newcontext, sock);
if (rc) if (rc)
goto out_unlock; goto out_unlock;
/* Check the validity of the context. */ /* Check the validity of the context. */
if (!policydb_context_isvalid(&policydb, &newcontext)) { if (!policydb_context_isvalid(policydb, &newcontext)) {
rc = compute_sid_handle_invalid_context(scontext, rc = compute_sid_handle_invalid_context(state, scontext,
tcontext, tcontext,
tclass, tclass,
&newcontext); &newcontext);
...@@ -1737,9 +1799,9 @@ static int security_compute_sid(u32 ssid, ...@@ -1737,9 +1799,9 @@ static int security_compute_sid(u32 ssid,
goto out_unlock; goto out_unlock;
} }
/* Obtain the sid for the context. */ /* Obtain the sid for the context. */
rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
out_unlock: out_unlock:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
context_destroy(&newcontext); context_destroy(&newcontext);
out: out:
return rc; return rc;
...@@ -1758,17 +1820,21 @@ static int security_compute_sid(u32 ssid, ...@@ -1758,17 +1820,21 @@ static int security_compute_sid(u32 ssid,
* if insufficient memory is available, or %0 if the new SID was * if insufficient memory is available, or %0 if the new SID was
* computed successfully. * computed successfully.
*/ */
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, int security_transition_sid(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid) const struct qstr *qstr, u32 *out_sid)
{ {
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, return security_compute_sid(state, ssid, tsid, tclass,
AVTAB_TRANSITION,
qstr ? qstr->name : NULL, out_sid, true); qstr ? qstr->name : NULL, out_sid, true);
} }
int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, int security_transition_sid_user(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
const char *objname, u32 *out_sid) const char *objname, u32 *out_sid)
{ {
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, return security_compute_sid(state, ssid, tsid, tclass,
AVTAB_TRANSITION,
objname, out_sid, false); objname, out_sid, false);
} }
...@@ -1785,12 +1851,14 @@ int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, ...@@ -1785,12 +1851,14 @@ int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
* if insufficient memory is available, or %0 if the SID was * if insufficient memory is available, or %0 if the SID was
* computed successfully. * computed successfully.
*/ */
int security_member_sid(u32 ssid, int security_member_sid(struct selinux_state *state,
u32 ssid,
u32 tsid, u32 tsid,
u16 tclass, u16 tclass,
u32 *out_sid) u32 *out_sid)
{ {
return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL, return security_compute_sid(state, ssid, tsid, tclass,
AVTAB_MEMBER, NULL,
out_sid, false); out_sid, false);
} }
...@@ -1807,12 +1875,14 @@ int security_member_sid(u32 ssid, ...@@ -1807,12 +1875,14 @@ int security_member_sid(u32 ssid,
* if insufficient memory is available, or %0 if the SID was * if insufficient memory is available, or %0 if the SID was
* computed successfully. * computed successfully.
*/ */
int security_change_sid(u32 ssid, int security_change_sid(struct selinux_state *state,
u32 ssid,
u32 tsid, u32 tsid,
u16 tclass, u16 tclass,
u32 *out_sid) u32 *out_sid)
{ {
return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, return security_compute_sid(state,
ssid, tsid, tclass, AVTAB_CHANGE, NULL,
out_sid, false); out_sid, false);
} }
...@@ -1829,15 +1899,18 @@ static int clone_sid(u32 sid, ...@@ -1829,15 +1899,18 @@ static int clone_sid(u32 sid,
return 0; return 0;
} }
static inline int convert_context_handle_invalid_context(struct context *context) static inline int convert_context_handle_invalid_context(
struct selinux_state *state,
struct context *context)
{ {
struct policydb *policydb = &state->ss->policydb;
char *s; char *s;
u32 len; u32 len;
if (selinux_enforcing) if (enforcing_enabled(state))
return -EINVAL; return -EINVAL;
if (!context_struct_to_string(context, &s, &len)) { if (!context_struct_to_string(policydb, context, &s, &len)) {
printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s); printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s);
kfree(s); kfree(s);
} }
...@@ -1845,6 +1918,7 @@ static inline int convert_context_handle_invalid_context(struct context *context ...@@ -1845,6 +1918,7 @@ static inline int convert_context_handle_invalid_context(struct context *context
} }
struct convert_context_args { struct convert_context_args {
struct selinux_state *state;
struct policydb *oldp; struct policydb *oldp;
struct policydb *newp; struct policydb *newp;
}; };
...@@ -1971,7 +2045,8 @@ static int convert_context(u32 key, ...@@ -1971,7 +2045,8 @@ static int convert_context(u32 key,
/* Check the validity of the new context. */ /* Check the validity of the new context. */
if (!policydb_context_isvalid(args->newp, c)) { if (!policydb_context_isvalid(args->newp, c)) {
rc = convert_context_handle_invalid_context(&oldc); rc = convert_context_handle_invalid_context(args->state,
&oldc);
if (rc) if (rc)
goto bad; goto bad;
} }
...@@ -1983,7 +2058,7 @@ static int convert_context(u32 key, ...@@ -1983,7 +2058,7 @@ static int convert_context(u32 key,
return rc; return rc;
bad: bad:
/* Map old representation to string and save it. */ /* Map old representation to string and save it. */
rc = context_struct_to_string(&oldc, &s, &len); rc = context_struct_to_string(args->oldp, &oldc, &s, &len);
if (rc) if (rc)
return rc; return rc;
context_destroy(&oldc); context_destroy(&oldc);
...@@ -1996,39 +2071,29 @@ static int convert_context(u32 key, ...@@ -1996,39 +2071,29 @@ static int convert_context(u32 key,
goto out; goto out;
} }
static void security_load_policycaps(void) static void security_load_policycaps(struct selinux_state *state)
{ {
struct policydb *p = &state->ss->policydb;
unsigned int i; unsigned int i;
struct ebitmap_node *node; struct ebitmap_node *node;
selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
POLICYDB_CAPABILITY_NETPEER); state->policycap[i] = ebitmap_get_bit(&p->policycaps, i);
selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_OPENPERM);
selinux_policycap_extsockclass = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_EXTSOCKCLASS);
selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_ALWAYSNETWORK);
selinux_policycap_cgroupseclabel =
ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_CGROUPSECLABEL);
selinux_policycap_nnp_nosuid_transition =
ebitmap_get_bit(&policydb.policycaps,
POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION);
for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
pr_info("SELinux: policy capability %s=%d\n", pr_info("SELinux: policy capability %s=%d\n",
selinux_policycap_names[i], selinux_policycap_names[i],
ebitmap_get_bit(&policydb.policycaps, i)); ebitmap_get_bit(&p->policycaps, i));
ebitmap_for_each_positive_bit(&policydb.policycaps, node, i) { ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
if (i >= ARRAY_SIZE(selinux_policycap_names)) if (i >= ARRAY_SIZE(selinux_policycap_names))
pr_info("SELinux: unknown policy capability %u\n", pr_info("SELinux: unknown policy capability %u\n",
i); i);
} }
} }
static int security_preserve_bools(struct policydb *p); static int security_preserve_bools(struct selinux_state *state,
struct policydb *newpolicydb);
/** /**
* security_load_policy - Load a security policy configuration. * security_load_policy - Load a security policy configuration.
...@@ -2040,14 +2105,16 @@ static int security_preserve_bools(struct policydb *p); ...@@ -2040,14 +2105,16 @@ static int security_preserve_bools(struct policydb *p);
* This function will flush the access vector cache after * This function will flush the access vector cache after
* loading the new policy. * loading the new policy.
*/ */
int security_load_policy(void *data, size_t len) int security_load_policy(struct selinux_state *state, void *data, size_t len)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct policydb *oldpolicydb, *newpolicydb; struct policydb *oldpolicydb, *newpolicydb;
struct sidtab oldsidtab, newsidtab; struct sidtab oldsidtab, newsidtab;
struct selinux_mapping *oldmap, *map = NULL; struct selinux_mapping *oldmapping;
struct selinux_map newmap;
struct convert_context_args args; struct convert_context_args args;
u32 seqno; u32 seqno;
u16 map_size;
int rc = 0; int rc = 0;
struct policy_file file = { data, len }, *fp = &file; struct policy_file file = { data, len }, *fp = &file;
...@@ -2058,53 +2125,42 @@ int security_load_policy(void *data, size_t len) ...@@ -2058,53 +2125,42 @@ int security_load_policy(void *data, size_t len)
} }
newpolicydb = oldpolicydb + 1; newpolicydb = oldpolicydb + 1;
if (!ss_initialized) { policydb = &state->ss->policydb;
avtab_cache_init(); sidtab = &state->ss->sidtab;
ebitmap_cache_init();
hashtab_cache_init(); if (!state->initialized) {
rc = policydb_read(&policydb, fp); rc = policydb_read(policydb, fp);
if (rc) { if (rc)
avtab_cache_destroy();
ebitmap_cache_destroy();
hashtab_cache_destroy();
goto out; goto out;
}
policydb.len = len; policydb->len = len;
rc = selinux_set_mapping(&policydb, secclass_map, rc = selinux_set_mapping(policydb, secclass_map,
&current_mapping, &state->ss->map);
&current_mapping_size);
if (rc) { if (rc) {
policydb_destroy(&policydb); policydb_destroy(policydb);
avtab_cache_destroy();
ebitmap_cache_destroy();
hashtab_cache_destroy();
goto out; goto out;
} }
rc = policydb_load_isids(&policydb, &sidtab); rc = policydb_load_isids(policydb, sidtab);
if (rc) { if (rc) {
policydb_destroy(&policydb); policydb_destroy(policydb);
avtab_cache_destroy();
ebitmap_cache_destroy();
hashtab_cache_destroy();
goto out; goto out;
} }
security_load_policycaps(); security_load_policycaps(state);
ss_initialized = 1; state->initialized = 1;
seqno = ++latest_granting; seqno = ++state->ss->latest_granting;
selinux_complete_init(); selinux_complete_init();
avc_ss_reset(seqno); avc_ss_reset(state->avc, seqno);
selnl_notify_policyload(seqno); selnl_notify_policyload(seqno);
selinux_status_update_policyload(seqno); selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate(); selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload(); selinux_xfrm_notify_policyload();
goto out; goto out;
} }
#if 0 #if 0
sidtab_hash_eval(&sidtab, "sids"); sidtab_hash_eval(sidtab, "sids");
#endif #endif
rc = policydb_read(newpolicydb, fp); rc = policydb_read(newpolicydb, fp);
...@@ -2113,9 +2169,9 @@ int security_load_policy(void *data, size_t len) ...@@ -2113,9 +2169,9 @@ int security_load_policy(void *data, size_t len)
newpolicydb->len = len; newpolicydb->len = len;
/* If switching between different policy types, log MLS status */ /* If switching between different policy types, log MLS status */
if (policydb.mls_enabled && !newpolicydb->mls_enabled) if (policydb->mls_enabled && !newpolicydb->mls_enabled)
printk(KERN_INFO "SELinux: Disabling MLS support...\n"); printk(KERN_INFO "SELinux: Disabling MLS support...\n");
else if (!policydb.mls_enabled && newpolicydb->mls_enabled) else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
printk(KERN_INFO "SELinux: Enabling MLS support...\n"); printk(KERN_INFO "SELinux: Enabling MLS support...\n");
rc = policydb_load_isids(newpolicydb, &newsidtab); rc = policydb_load_isids(newpolicydb, &newsidtab);
...@@ -2125,20 +2181,20 @@ int security_load_policy(void *data, size_t len) ...@@ -2125,20 +2181,20 @@ int security_load_policy(void *data, size_t len)
goto out; goto out;
} }
rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap);
if (rc) if (rc)
goto err; goto err;
rc = security_preserve_bools(newpolicydb); rc = security_preserve_bools(state, newpolicydb);
if (rc) { if (rc) {
printk(KERN_ERR "SELinux: unable to preserve booleans\n"); printk(KERN_ERR "SELinux: unable to preserve booleans\n");
goto err; goto err;
} }
/* Clone the SID table. */ /* Clone the SID table. */
sidtab_shutdown(&sidtab); sidtab_shutdown(sidtab);
rc = sidtab_map(&sidtab, clone_sid, &newsidtab); rc = sidtab_map(sidtab, clone_sid, &newsidtab);
if (rc) if (rc)
goto err; goto err;
...@@ -2146,7 +2202,8 @@ int security_load_policy(void *data, size_t len) ...@@ -2146,7 +2202,8 @@ int security_load_policy(void *data, size_t len)
* Convert the internal representations of contexts * Convert the internal representations of contexts
* in the new SID table. * in the new SID table.
*/ */
args.oldp = &policydb; args.state = state;
args.oldp = policydb;
args.newp = newpolicydb; args.newp = newpolicydb;
rc = sidtab_map(&newsidtab, convert_context, &args); rc = sidtab_map(&newsidtab, convert_context, &args);
if (rc) { if (rc) {
...@@ -2157,28 +2214,28 @@ int security_load_policy(void *data, size_t len) ...@@ -2157,28 +2214,28 @@ int security_load_policy(void *data, size_t len)
} }
/* Save the old policydb and SID table to free later. */ /* Save the old policydb and SID table to free later. */
memcpy(oldpolicydb, &policydb, sizeof(policydb)); memcpy(oldpolicydb, policydb, sizeof(*policydb));
sidtab_set(&oldsidtab, &sidtab); sidtab_set(&oldsidtab, sidtab);
/* Install the new policydb and SID table. */ /* Install the new policydb and SID table. */
write_lock_irq(&policy_rwlock); write_lock_irq(&state->ss->policy_rwlock);
memcpy(&policydb, newpolicydb, sizeof(policydb)); memcpy(policydb, newpolicydb, sizeof(*policydb));
sidtab_set(&sidtab, &newsidtab); sidtab_set(sidtab, &newsidtab);
security_load_policycaps(); security_load_policycaps(state);
oldmap = current_mapping; oldmapping = state->ss->map.mapping;
current_mapping = map; state->ss->map.mapping = newmap.mapping;
current_mapping_size = map_size; state->ss->map.size = newmap.size;
seqno = ++latest_granting; seqno = ++state->ss->latest_granting;
write_unlock_irq(&policy_rwlock); write_unlock_irq(&state->ss->policy_rwlock);
/* Free the old policydb and SID table. */ /* Free the old policydb and SID table. */
policydb_destroy(oldpolicydb); policydb_destroy(oldpolicydb);
sidtab_destroy(&oldsidtab); sidtab_destroy(&oldsidtab);
kfree(oldmap); kfree(oldmapping);
avc_ss_reset(seqno); avc_ss_reset(state->avc, seqno);
selnl_notify_policyload(seqno); selnl_notify_policyload(seqno);
selinux_status_update_policyload(seqno); selinux_status_update_policyload(state, seqno);
selinux_netlbl_cache_invalidate(); selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload(); selinux_xfrm_notify_policyload();
...@@ -2186,7 +2243,7 @@ int security_load_policy(void *data, size_t len) ...@@ -2186,7 +2243,7 @@ int security_load_policy(void *data, size_t len)
goto out; goto out;
err: err:
kfree(map); kfree(newmap.mapping);
sidtab_destroy(&newsidtab); sidtab_destroy(&newsidtab);
policydb_destroy(newpolicydb); policydb_destroy(newpolicydb);
...@@ -2195,13 +2252,14 @@ int security_load_policy(void *data, size_t len) ...@@ -2195,13 +2252,14 @@ int security_load_policy(void *data, size_t len)
return rc; return rc;
} }
size_t security_policydb_len(void) size_t security_policydb_len(struct selinux_state *state)
{ {
struct policydb *p = &state->ss->policydb;
size_t len; size_t len;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
len = policydb.len; len = p->len;
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return len; return len;
} }
...@@ -2212,14 +2270,20 @@ size_t security_policydb_len(void) ...@@ -2212,14 +2270,20 @@ size_t security_policydb_len(void)
* @port: port number * @port: port number
* @out_sid: security identifier * @out_sid: security identifier
*/ */
int security_port_sid(u8 protocol, u16 port, u32 *out_sid) int security_port_sid(struct selinux_state *state,
u8 protocol, u16 port, u32 *out_sid)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c; struct ocontext *c;
int rc = 0; int rc = 0;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
c = policydb.ocontexts[OCON_PORT]; policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
c = policydb->ocontexts[OCON_PORT];
while (c) { while (c) {
if (c->u.port.protocol == protocol && if (c->u.port.protocol == protocol &&
c->u.port.low_port <= port && c->u.port.low_port <= port &&
...@@ -2230,7 +2294,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid) ...@@ -2230,7 +2294,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
if (c) { if (c) {
if (!c->sid[0]) { if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, rc = sidtab_context_to_sid(sidtab,
&c->context[0], &c->context[0],
&c->sid[0]); &c->sid[0]);
if (rc) if (rc)
...@@ -2242,7 +2306,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid) ...@@ -2242,7 +2306,7 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
} }
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -2252,14 +2316,20 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid) ...@@ -2252,14 +2316,20 @@ int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
* @pkey_num: pkey number * @pkey_num: pkey number
* @out_sid: security identifier * @out_sid: security identifier
*/ */
int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) int security_ib_pkey_sid(struct selinux_state *state,
u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c; struct ocontext *c;
int rc = 0; int rc = 0;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
c = policydb.ocontexts[OCON_IBPKEY]; c = policydb->ocontexts[OCON_IBPKEY];
while (c) { while (c) {
if (c->u.ibpkey.low_pkey <= pkey_num && if (c->u.ibpkey.low_pkey <= pkey_num &&
c->u.ibpkey.high_pkey >= pkey_num && c->u.ibpkey.high_pkey >= pkey_num &&
...@@ -2271,7 +2341,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) ...@@ -2271,7 +2341,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
if (c) { if (c) {
if (!c->sid[0]) { if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, rc = sidtab_context_to_sid(sidtab,
&c->context[0], &c->context[0],
&c->sid[0]); &c->sid[0]);
if (rc) if (rc)
...@@ -2282,7 +2352,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) ...@@ -2282,7 +2352,7 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
*out_sid = SECINITSID_UNLABELED; *out_sid = SECINITSID_UNLABELED;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -2292,14 +2362,20 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) ...@@ -2292,14 +2362,20 @@ int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
* @port: port number * @port: port number
* @out_sid: security identifier * @out_sid: security identifier
*/ */
int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid) int security_ib_endport_sid(struct selinux_state *state,
const char *dev_name, u8 port_num, u32 *out_sid)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct ocontext *c; struct ocontext *c;
int rc = 0; int rc = 0;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
c = policydb.ocontexts[OCON_IBENDPORT]; c = policydb->ocontexts[OCON_IBENDPORT];
while (c) { while (c) {
if (c->u.ibendport.port == port_num && if (c->u.ibendport.port == port_num &&
!strncmp(c->u.ibendport.dev_name, !strncmp(c->u.ibendport.dev_name,
...@@ -2312,7 +2388,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid) ...@@ -2312,7 +2388,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
if (c) { if (c) {
if (!c->sid[0]) { if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, rc = sidtab_context_to_sid(sidtab,
&c->context[0], &c->context[0],
&c->sid[0]); &c->sid[0]);
if (rc) if (rc)
...@@ -2323,7 +2399,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid) ...@@ -2323,7 +2399,7 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
*out_sid = SECINITSID_UNLABELED; *out_sid = SECINITSID_UNLABELED;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -2332,14 +2408,20 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid) ...@@ -2332,14 +2408,20 @@ int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
* @name: interface name * @name: interface name
* @if_sid: interface SID * @if_sid: interface SID
*/ */
int security_netif_sid(char *name, u32 *if_sid) int security_netif_sid(struct selinux_state *state,
char *name, u32 *if_sid)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
int rc = 0; int rc = 0;
struct ocontext *c; struct ocontext *c;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
c = policydb.ocontexts[OCON_NETIF]; policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
c = policydb->ocontexts[OCON_NETIF];
while (c) { while (c) {
if (strcmp(name, c->u.name) == 0) if (strcmp(name, c->u.name) == 0)
break; break;
...@@ -2348,12 +2430,12 @@ int security_netif_sid(char *name, u32 *if_sid) ...@@ -2348,12 +2430,12 @@ int security_netif_sid(char *name, u32 *if_sid)
if (c) { if (c) {
if (!c->sid[0] || !c->sid[1]) { if (!c->sid[0] || !c->sid[1]) {
rc = sidtab_context_to_sid(&sidtab, rc = sidtab_context_to_sid(sidtab,
&c->context[0], &c->context[0],
&c->sid[0]); &c->sid[0]);
if (rc) if (rc)
goto out; goto out;
rc = sidtab_context_to_sid(&sidtab, rc = sidtab_context_to_sid(sidtab,
&c->context[1], &c->context[1],
&c->sid[1]); &c->sid[1]);
if (rc) if (rc)
...@@ -2364,7 +2446,7 @@ int security_netif_sid(char *name, u32 *if_sid) ...@@ -2364,7 +2446,7 @@ int security_netif_sid(char *name, u32 *if_sid)
*if_sid = SECINITSID_NETIF; *if_sid = SECINITSID_NETIF;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -2388,15 +2470,21 @@ static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) ...@@ -2388,15 +2470,21 @@ static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
* @addrlen: address length in bytes * @addrlen: address length in bytes
* @out_sid: security identifier * @out_sid: security identifier
*/ */
int security_node_sid(u16 domain, int security_node_sid(struct selinux_state *state,
u16 domain,
void *addrp, void *addrp,
u32 addrlen, u32 addrlen,
u32 *out_sid) u32 *out_sid)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
int rc; int rc;
struct ocontext *c; struct ocontext *c;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
switch (domain) { switch (domain) {
case AF_INET: { case AF_INET: {
...@@ -2408,7 +2496,7 @@ int security_node_sid(u16 domain, ...@@ -2408,7 +2496,7 @@ int security_node_sid(u16 domain,
addr = *((u32 *)addrp); addr = *((u32 *)addrp);
c = policydb.ocontexts[OCON_NODE]; c = policydb->ocontexts[OCON_NODE];
while (c) { while (c) {
if (c->u.node.addr == (addr & c->u.node.mask)) if (c->u.node.addr == (addr & c->u.node.mask))
break; break;
...@@ -2421,7 +2509,7 @@ int security_node_sid(u16 domain, ...@@ -2421,7 +2509,7 @@ int security_node_sid(u16 domain,
rc = -EINVAL; rc = -EINVAL;
if (addrlen != sizeof(u64) * 2) if (addrlen != sizeof(u64) * 2)
goto out; goto out;
c = policydb.ocontexts[OCON_NODE6]; c = policydb->ocontexts[OCON_NODE6];
while (c) { while (c) {
if (match_ipv6_addrmask(addrp, c->u.node6.addr, if (match_ipv6_addrmask(addrp, c->u.node6.addr,
c->u.node6.mask)) c->u.node6.mask))
...@@ -2438,7 +2526,7 @@ int security_node_sid(u16 domain, ...@@ -2438,7 +2526,7 @@ int security_node_sid(u16 domain,
if (c) { if (c) {
if (!c->sid[0]) { if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, rc = sidtab_context_to_sid(sidtab,
&c->context[0], &c->context[0],
&c->sid[0]); &c->sid[0]);
if (rc) if (rc)
...@@ -2451,7 +2539,7 @@ int security_node_sid(u16 domain, ...@@ -2451,7 +2539,7 @@ int security_node_sid(u16 domain,
rc = 0; rc = 0;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -2471,11 +2559,14 @@ int security_node_sid(u16 domain, ...@@ -2471,11 +2559,14 @@ int security_node_sid(u16 domain,
* number of elements in the array. * number of elements in the array.
*/ */
int security_get_user_sids(u32 fromsid, int security_get_user_sids(struct selinux_state *state,
u32 fromsid,
char *username, char *username,
u32 **sids, u32 **sids,
u32 *nel) u32 *nel)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
struct context *fromcon, usercon; struct context *fromcon, usercon;
u32 *mysids = NULL, *mysids2, sid; u32 *mysids = NULL, *mysids2, sid;
u32 mynel = 0, maxnel = SIDS_NEL; u32 mynel = 0, maxnel = SIDS_NEL;
...@@ -2487,20 +2578,23 @@ int security_get_user_sids(u32 fromsid, ...@@ -2487,20 +2578,23 @@ int security_get_user_sids(u32 fromsid,
*sids = NULL; *sids = NULL;
*nel = 0; *nel = 0;
if (!ss_initialized) if (!state->initialized)
goto out; goto out;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
context_init(&usercon); context_init(&usercon);
rc = -EINVAL; rc = -EINVAL;
fromcon = sidtab_search(&sidtab, fromsid); fromcon = sidtab_search(sidtab, fromsid);
if (!fromcon) if (!fromcon)
goto out_unlock; goto out_unlock;
rc = -EINVAL; rc = -EINVAL;
user = hashtab_search(policydb.p_users.table, username); user = hashtab_search(policydb->p_users.table, username);
if (!user) if (!user)
goto out_unlock; goto out_unlock;
...@@ -2512,15 +2606,16 @@ int security_get_user_sids(u32 fromsid, ...@@ -2512,15 +2606,16 @@ int security_get_user_sids(u32 fromsid,
goto out_unlock; goto out_unlock;
ebitmap_for_each_positive_bit(&user->roles, rnode, i) { ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
role = policydb.role_val_to_struct[i]; role = policydb->role_val_to_struct[i];
usercon.role = i + 1; usercon.role = i + 1;
ebitmap_for_each_positive_bit(&role->types, tnode, j) { ebitmap_for_each_positive_bit(&role->types, tnode, j) {
usercon.type = j + 1; usercon.type = j + 1;
if (mls_setup_user_range(fromcon, user, &usercon)) if (mls_setup_user_range(policydb, fromcon, user,
&usercon))
continue; continue;
rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
if (rc) if (rc)
goto out_unlock; goto out_unlock;
if (mynel < maxnel) { if (mynel < maxnel) {
...@@ -2540,7 +2635,7 @@ int security_get_user_sids(u32 fromsid, ...@@ -2540,7 +2635,7 @@ int security_get_user_sids(u32 fromsid,
} }
rc = 0; rc = 0;
out_unlock: out_unlock:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
if (rc || !mynel) { if (rc || !mynel) {
kfree(mysids); kfree(mysids);
goto out; goto out;
...@@ -2554,7 +2649,8 @@ int security_get_user_sids(u32 fromsid, ...@@ -2554,7 +2649,8 @@ int security_get_user_sids(u32 fromsid,
} }
for (i = 0, j = 0; i < mynel; i++) { for (i = 0, j = 0; i < mynel; i++) {
struct av_decision dummy_avd; struct av_decision dummy_avd;
rc = avc_has_perm_noaudit(fromsid, mysids[i], rc = avc_has_perm_noaudit(state,
fromsid, mysids[i],
SECCLASS_PROCESS, /* kernel value */ SECCLASS_PROCESS, /* kernel value */
PROCESS__TRANSITION, AVC_STRICT, PROCESS__TRANSITION, AVC_STRICT,
&dummy_avd); &dummy_avd);
...@@ -2583,11 +2679,14 @@ int security_get_user_sids(u32 fromsid, ...@@ -2583,11 +2679,14 @@ int security_get_user_sids(u32 fromsid,
* *
* The caller must acquire the policy_rwlock before calling this function. * The caller must acquire the policy_rwlock before calling this function.
*/ */
static inline int __security_genfs_sid(const char *fstype, static inline int __security_genfs_sid(struct selinux_state *state,
const char *fstype,
char *path, char *path,
u16 orig_sclass, u16 orig_sclass,
u32 *sid) u32 *sid)
{ {
struct policydb *policydb = &state->ss->policydb;
struct sidtab *sidtab = &state->ss->sidtab;
int len; int len;
u16 sclass; u16 sclass;
struct genfs *genfs; struct genfs *genfs;
...@@ -2597,10 +2696,10 @@ static inline int __security_genfs_sid(const char *fstype, ...@@ -2597,10 +2696,10 @@ static inline int __security_genfs_sid(const char *fstype,
while (path[0] == '/' && path[1] == '/') while (path[0] == '/' && path[1] == '/')
path++; path++;
sclass = unmap_class(orig_sclass); sclass = unmap_class(&state->ss->map, orig_sclass);
*sid = SECINITSID_UNLABELED; *sid = SECINITSID_UNLABELED;
for (genfs = policydb.genfs; genfs; genfs = genfs->next) { for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
cmp = strcmp(fstype, genfs->fstype); cmp = strcmp(fstype, genfs->fstype);
if (cmp <= 0) if (cmp <= 0)
break; break;
...@@ -2622,7 +2721,7 @@ static inline int __security_genfs_sid(const char *fstype, ...@@ -2622,7 +2721,7 @@ static inline int __security_genfs_sid(const char *fstype,
goto out; goto out;
if (!c->sid[0]) { if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]); rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]);
if (rc) if (rc)
goto out; goto out;
} }
...@@ -2643,16 +2742,17 @@ static inline int __security_genfs_sid(const char *fstype, ...@@ -2643,16 +2742,17 @@ static inline int __security_genfs_sid(const char *fstype,
* Acquire policy_rwlock before calling __security_genfs_sid() and release * Acquire policy_rwlock before calling __security_genfs_sid() and release
* it afterward. * it afterward.
*/ */
int security_genfs_sid(const char *fstype, int security_genfs_sid(struct selinux_state *state,
const char *fstype,
char *path, char *path,
u16 orig_sclass, u16 orig_sclass,
u32 *sid) u32 *sid)
{ {
int retval; int retval;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
retval = __security_genfs_sid(fstype, path, orig_sclass, sid); retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid);
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return retval; return retval;
} }
...@@ -2660,16 +2760,21 @@ int security_genfs_sid(const char *fstype, ...@@ -2660,16 +2760,21 @@ int security_genfs_sid(const char *fstype,
* security_fs_use - Determine how to handle labeling for a filesystem. * security_fs_use - Determine how to handle labeling for a filesystem.
* @sb: superblock in question * @sb: superblock in question
*/ */
int security_fs_use(struct super_block *sb) int security_fs_use(struct selinux_state *state, struct super_block *sb)
{ {
struct policydb *policydb;
struct sidtab *sidtab;
int rc = 0; int rc = 0;
struct ocontext *c; struct ocontext *c;
struct superblock_security_struct *sbsec = sb->s_security; struct superblock_security_struct *sbsec = sb->s_security;
const char *fstype = sb->s_type->name; const char *fstype = sb->s_type->name;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
c = policydb.ocontexts[OCON_FSUSE]; policydb = &state->ss->policydb;
sidtab = &state->ss->sidtab;
c = policydb->ocontexts[OCON_FSUSE];
while (c) { while (c) {
if (strcmp(fstype, c->u.name) == 0) if (strcmp(fstype, c->u.name) == 0)
break; break;
...@@ -2679,14 +2784,14 @@ int security_fs_use(struct super_block *sb) ...@@ -2679,14 +2784,14 @@ int security_fs_use(struct super_block *sb)
if (c) { if (c) {
sbsec->behavior = c->v.behavior; sbsec->behavior = c->v.behavior;
if (!c->sid[0]) { if (!c->sid[0]) {
rc = sidtab_context_to_sid(&sidtab, &c->context[0], rc = sidtab_context_to_sid(sidtab, &c->context[0],
&c->sid[0]); &c->sid[0]);
if (rc) if (rc)
goto out; goto out;
} }
sbsec->sid = c->sid[0]; sbsec->sid = c->sid[0];
} else { } else {
rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR, rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR,
&sbsec->sid); &sbsec->sid);
if (rc) { if (rc) {
sbsec->behavior = SECURITY_FS_USE_NONE; sbsec->behavior = SECURITY_FS_USE_NONE;
...@@ -2697,20 +2802,32 @@ int security_fs_use(struct super_block *sb) ...@@ -2697,20 +2802,32 @@ int security_fs_use(struct super_block *sb)
} }
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
int security_get_bools(int *len, char ***names, int **values) int security_get_bools(struct selinux_state *state,
int *len, char ***names, int **values)
{ {
struct policydb *policydb;
int i, rc; int i, rc;
read_lock(&policy_rwlock); if (!state->initialized) {
*len = 0;
*names = NULL;
*values = NULL;
return 0;
}
read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
*names = NULL; *names = NULL;
*values = NULL; *values = NULL;
rc = 0; rc = 0;
*len = policydb.p_bools.nprim; *len = policydb->p_bools.nprim;
if (!*len) if (!*len)
goto out; goto out;
...@@ -2725,16 +2842,17 @@ int security_get_bools(int *len, char ***names, int **values) ...@@ -2725,16 +2842,17 @@ int security_get_bools(int *len, char ***names, int **values)
goto err; goto err;
for (i = 0; i < *len; i++) { for (i = 0; i < *len; i++) {
(*values)[i] = policydb.bool_val_to_struct[i]->state; (*values)[i] = policydb->bool_val_to_struct[i]->state;
rc = -ENOMEM; rc = -ENOMEM;
(*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC); (*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
GFP_ATOMIC);
if (!(*names)[i]) if (!(*names)[i])
goto err; goto err;
} }
rc = 0; rc = 0;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
err: err:
if (*names) { if (*names) {
...@@ -2746,90 +2864,98 @@ int security_get_bools(int *len, char ***names, int **values) ...@@ -2746,90 +2864,98 @@ int security_get_bools(int *len, char ***names, int **values)
} }
int security_set_bools(int len, int *values) int security_set_bools(struct selinux_state *state, int len, int *values)
{ {
struct policydb *policydb;
int i, rc; int i, rc;
int lenp, seqno = 0; int lenp, seqno = 0;
struct cond_node *cur; struct cond_node *cur;
write_lock_irq(&policy_rwlock); write_lock_irq(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
rc = -EFAULT; rc = -EFAULT;
lenp = policydb.p_bools.nprim; lenp = policydb->p_bools.nprim;
if (len != lenp) if (len != lenp)
goto out; goto out;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (!!values[i] != policydb.bool_val_to_struct[i]->state) { if (!!values[i] != policydb->bool_val_to_struct[i]->state) {
audit_log(current->audit_context, GFP_ATOMIC, audit_log(current->audit_context, GFP_ATOMIC,
AUDIT_MAC_CONFIG_CHANGE, AUDIT_MAC_CONFIG_CHANGE,
"bool=%s val=%d old_val=%d auid=%u ses=%u", "bool=%s val=%d old_val=%d auid=%u ses=%u",
sym_name(&policydb, SYM_BOOLS, i), sym_name(policydb, SYM_BOOLS, i),
!!values[i], !!values[i],
policydb.bool_val_to_struct[i]->state, policydb->bool_val_to_struct[i]->state,
from_kuid(&init_user_ns, audit_get_loginuid(current)), from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current)); audit_get_sessionid(current));
} }
if (values[i]) if (values[i])
policydb.bool_val_to_struct[i]->state = 1; policydb->bool_val_to_struct[i]->state = 1;
else else
policydb.bool_val_to_struct[i]->state = 0; policydb->bool_val_to_struct[i]->state = 0;
} }
for (cur = policydb.cond_list; cur; cur = cur->next) { for (cur = policydb->cond_list; cur; cur = cur->next) {
rc = evaluate_cond_node(&policydb, cur); rc = evaluate_cond_node(policydb, cur);
if (rc) if (rc)
goto out; goto out;
} }
seqno = ++latest_granting; seqno = ++state->ss->latest_granting;
rc = 0; rc = 0;
out: out:
write_unlock_irq(&policy_rwlock); write_unlock_irq(&state->ss->policy_rwlock);
if (!rc) { if (!rc) {
avc_ss_reset(seqno); avc_ss_reset(state->avc, seqno);
selnl_notify_policyload(seqno); selnl_notify_policyload(seqno);
selinux_status_update_policyload(seqno); selinux_status_update_policyload(state, seqno);
selinux_xfrm_notify_policyload(); selinux_xfrm_notify_policyload();
} }
return rc; return rc;
} }
int security_get_bool_value(int index) int security_get_bool_value(struct selinux_state *state,
int index)
{ {
struct policydb *policydb;
int rc; int rc;
int len; int len;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
policydb = &state->ss->policydb;
rc = -EFAULT; rc = -EFAULT;
len = policydb.p_bools.nprim; len = policydb->p_bools.nprim;
if (index >= len) if (index >= len)
goto out; goto out;
rc = policydb.bool_val_to_struct[index]->state; rc = policydb->bool_val_to_struct[index]->state;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
static int security_preserve_bools(struct policydb *p) static int security_preserve_bools(struct selinux_state *state,
struct policydb *policydb)
{ {
int rc, nbools = 0, *bvalues = NULL, i; int rc, nbools = 0, *bvalues = NULL, i;
char **bnames = NULL; char **bnames = NULL;
struct cond_bool_datum *booldatum; struct cond_bool_datum *booldatum;
struct cond_node *cur; struct cond_node *cur;
rc = security_get_bools(&nbools, &bnames, &bvalues); rc = security_get_bools(state, &nbools, &bnames, &bvalues);
if (rc) if (rc)
goto out; goto out;
for (i = 0; i < nbools; i++) { for (i = 0; i < nbools; i++) {
booldatum = hashtab_search(p->p_bools.table, bnames[i]); booldatum = hashtab_search(policydb->p_bools.table, bnames[i]);
if (booldatum) if (booldatum)
booldatum->state = bvalues[i]; booldatum->state = bvalues[i];
} }
for (cur = p->cond_list; cur; cur = cur->next) { for (cur = policydb->cond_list; cur; cur = cur->next) {
rc = evaluate_cond_node(p, cur); rc = evaluate_cond_node(policydb, cur);
if (rc) if (rc)
goto out; goto out;
} }
...@@ -2848,8 +2974,11 @@ static int security_preserve_bools(struct policydb *p) ...@@ -2848,8 +2974,11 @@ static int security_preserve_bools(struct policydb *p)
* security_sid_mls_copy() - computes a new sid based on the given * security_sid_mls_copy() - computes a new sid based on the given
* sid and the mls portion of mls_sid. * sid and the mls portion of mls_sid.
*/ */
int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) int security_sid_mls_copy(struct selinux_state *state,
u32 sid, u32 mls_sid, u32 *new_sid)
{ {
struct policydb *policydb = &state->ss->policydb;
struct sidtab *sidtab = &state->ss->sidtab;
struct context *context1; struct context *context1;
struct context *context2; struct context *context2;
struct context newcon; struct context newcon;
...@@ -2858,17 +2987,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) ...@@ -2858,17 +2987,17 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
int rc; int rc;
rc = 0; rc = 0;
if (!ss_initialized || !policydb.mls_enabled) { if (!state->initialized || !policydb->mls_enabled) {
*new_sid = sid; *new_sid = sid;
goto out; goto out;
} }
context_init(&newcon); context_init(&newcon);
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
rc = -EINVAL; rc = -EINVAL;
context1 = sidtab_search(&sidtab, sid); context1 = sidtab_search(sidtab, sid);
if (!context1) { if (!context1) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, sid); __func__, sid);
...@@ -2876,7 +3005,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) ...@@ -2876,7 +3005,7 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
} }
rc = -EINVAL; rc = -EINVAL;
context2 = sidtab_search(&sidtab, mls_sid); context2 = sidtab_search(sidtab, mls_sid);
if (!context2) { if (!context2) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, mls_sid); __func__, mls_sid);
...@@ -2891,10 +3020,11 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) ...@@ -2891,10 +3020,11 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
goto out_unlock; goto out_unlock;
/* Check the validity of the new context. */ /* Check the validity of the new context. */
if (!policydb_context_isvalid(&policydb, &newcon)) { if (!policydb_context_isvalid(policydb, &newcon)) {
rc = convert_context_handle_invalid_context(&newcon); rc = convert_context_handle_invalid_context(state, &newcon);
if (rc) { if (rc) {
if (!context_struct_to_string(&newcon, &s, &len)) { if (!context_struct_to_string(policydb, &newcon, &s,
&len)) {
audit_log(current->audit_context, audit_log(current->audit_context,
GFP_ATOMIC, AUDIT_SELINUX_ERR, GFP_ATOMIC, AUDIT_SELINUX_ERR,
"op=security_sid_mls_copy " "op=security_sid_mls_copy "
...@@ -2905,9 +3035,9 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) ...@@ -2905,9 +3035,9 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
} }
} }
rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
out_unlock: out_unlock:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
context_destroy(&newcon); context_destroy(&newcon);
out: out:
return rc; return rc;
...@@ -2933,10 +3063,13 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) ...@@ -2933,10 +3063,13 @@ int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
* multiple, inconsistent labels | -<errno> | SECSID_NULL * multiple, inconsistent labels | -<errno> | SECSID_NULL
* *
*/ */
int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, int security_net_peersid_resolve(struct selinux_state *state,
u32 nlbl_sid, u32 nlbl_type,
u32 xfrm_sid, u32 xfrm_sid,
u32 *peer_sid) u32 *peer_sid)
{ {
struct policydb *policydb = &state->ss->policydb;
struct sidtab *sidtab = &state->ss->sidtab;
int rc; int rc;
struct context *nlbl_ctx; struct context *nlbl_ctx;
struct context *xfrm_ctx; struct context *xfrm_ctx;
...@@ -2958,23 +3091,25 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, ...@@ -2958,23 +3091,25 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
return 0; return 0;
} }
/* we don't need to check ss_initialized here since the only way both /*
* We don't need to check initialized here since the only way both
* nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
* security server was initialized and ss_initialized was true */ * security server was initialized and state->initialized was true.
if (!policydb.mls_enabled) */
if (!policydb->mls_enabled)
return 0; return 0;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
rc = -EINVAL; rc = -EINVAL;
nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
if (!nlbl_ctx) { if (!nlbl_ctx) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, nlbl_sid); __func__, nlbl_sid);
goto out; goto out;
} }
rc = -EINVAL; rc = -EINVAL;
xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
if (!xfrm_ctx) { if (!xfrm_ctx) {
printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n",
__func__, xfrm_sid); __func__, xfrm_sid);
...@@ -2991,7 +3126,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, ...@@ -2991,7 +3126,7 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
* expressive */ * expressive */
*peer_sid = xfrm_sid; *peer_sid = xfrm_sid;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -3008,19 +3143,27 @@ static int get_classes_callback(void *k, void *d, void *args) ...@@ -3008,19 +3143,27 @@ static int get_classes_callback(void *k, void *d, void *args)
return 0; return 0;
} }
int security_get_classes(char ***classes, int *nclasses) int security_get_classes(struct selinux_state *state,
char ***classes, int *nclasses)
{ {
struct policydb *policydb = &state->ss->policydb;
int rc; int rc;
read_lock(&policy_rwlock); if (!state->initialized) {
*nclasses = 0;
*classes = NULL;
return 0;
}
read_lock(&state->ss->policy_rwlock);
rc = -ENOMEM; rc = -ENOMEM;
*nclasses = policydb.p_classes.nprim; *nclasses = policydb->p_classes.nprim;
*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
if (!*classes) if (!*classes)
goto out; goto out;
rc = hashtab_map(policydb.p_classes.table, get_classes_callback, rc = hashtab_map(policydb->p_classes.table, get_classes_callback,
*classes); *classes);
if (rc) { if (rc) {
int i; int i;
...@@ -3030,7 +3173,7 @@ int security_get_classes(char ***classes, int *nclasses) ...@@ -3030,7 +3173,7 @@ int security_get_classes(char ***classes, int *nclasses)
} }
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -3047,15 +3190,17 @@ static int get_permissions_callback(void *k, void *d, void *args) ...@@ -3047,15 +3190,17 @@ static int get_permissions_callback(void *k, void *d, void *args)
return 0; return 0;
} }
int security_get_permissions(char *class, char ***perms, int *nperms) int security_get_permissions(struct selinux_state *state,
char *class, char ***perms, int *nperms)
{ {
struct policydb *policydb = &state->ss->policydb;
int rc, i; int rc, i;
struct class_datum *match; struct class_datum *match;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
rc = -EINVAL; rc = -EINVAL;
match = hashtab_search(policydb.p_classes.table, class); match = hashtab_search(policydb->p_classes.table, class);
if (!match) { if (!match) {
printk(KERN_ERR "SELinux: %s: unrecognized class %s\n", printk(KERN_ERR "SELinux: %s: unrecognized class %s\n",
__func__, class); __func__, class);
...@@ -3081,25 +3226,25 @@ int security_get_permissions(char *class, char ***perms, int *nperms) ...@@ -3081,25 +3226,25 @@ int security_get_permissions(char *class, char ***perms, int *nperms)
goto err; goto err;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
err: err:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
for (i = 0; i < *nperms; i++) for (i = 0; i < *nperms; i++)
kfree((*perms)[i]); kfree((*perms)[i]);
kfree(*perms); kfree(*perms);
return rc; return rc;
} }
int security_get_reject_unknown(void) int security_get_reject_unknown(struct selinux_state *state)
{ {
return policydb.reject_unknown; return state->ss->policydb.reject_unknown;
} }
int security_get_allow_unknown(void) int security_get_allow_unknown(struct selinux_state *state)
{ {
return policydb.allow_unknown; return state->ss->policydb.allow_unknown;
} }
/** /**
...@@ -3112,13 +3257,15 @@ int security_get_allow_unknown(void) ...@@ -3112,13 +3257,15 @@ int security_get_allow_unknown(void)
* supported, false (0) if it isn't supported. * supported, false (0) if it isn't supported.
* *
*/ */
int security_policycap_supported(unsigned int req_cap) int security_policycap_supported(struct selinux_state *state,
unsigned int req_cap)
{ {
struct policydb *policydb = &state->ss->policydb;
int rc; int rc;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
rc = ebitmap_get_bit(&policydb.policycaps, req_cap); rc = ebitmap_get_bit(&policydb->policycaps, req_cap);
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -3140,6 +3287,8 @@ void selinux_audit_rule_free(void *vrule) ...@@ -3140,6 +3287,8 @@ void selinux_audit_rule_free(void *vrule)
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
{ {
struct selinux_state *state = &selinux_state;
struct policydb *policydb = &state->ss->policydb;
struct selinux_audit_rule *tmprule; struct selinux_audit_rule *tmprule;
struct role_datum *roledatum; struct role_datum *roledatum;
struct type_datum *typedatum; struct type_datum *typedatum;
...@@ -3149,7 +3298,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -3149,7 +3298,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
*rule = NULL; *rule = NULL;
if (!ss_initialized) if (!state->initialized)
return -EOPNOTSUPP; return -EOPNOTSUPP;
switch (field) { switch (field) {
...@@ -3182,15 +3331,15 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -3182,15 +3331,15 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
context_init(&tmprule->au_ctxt); context_init(&tmprule->au_ctxt);
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
tmprule->au_seqno = latest_granting; tmprule->au_seqno = state->ss->latest_granting;
switch (field) { switch (field) {
case AUDIT_SUBJ_USER: case AUDIT_SUBJ_USER:
case AUDIT_OBJ_USER: case AUDIT_OBJ_USER:
rc = -EINVAL; rc = -EINVAL;
userdatum = hashtab_search(policydb.p_users.table, rulestr); userdatum = hashtab_search(policydb->p_users.table, rulestr);
if (!userdatum) if (!userdatum)
goto out; goto out;
tmprule->au_ctxt.user = userdatum->value; tmprule->au_ctxt.user = userdatum->value;
...@@ -3198,7 +3347,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -3198,7 +3347,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_ROLE:
case AUDIT_OBJ_ROLE: case AUDIT_OBJ_ROLE:
rc = -EINVAL; rc = -EINVAL;
roledatum = hashtab_search(policydb.p_roles.table, rulestr); roledatum = hashtab_search(policydb->p_roles.table, rulestr);
if (!roledatum) if (!roledatum)
goto out; goto out;
tmprule->au_ctxt.role = roledatum->value; tmprule->au_ctxt.role = roledatum->value;
...@@ -3206,7 +3355,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -3206,7 +3355,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_TYPE:
case AUDIT_OBJ_TYPE: case AUDIT_OBJ_TYPE:
rc = -EINVAL; rc = -EINVAL;
typedatum = hashtab_search(policydb.p_types.table, rulestr); typedatum = hashtab_search(policydb->p_types.table, rulestr);
if (!typedatum) if (!typedatum)
goto out; goto out;
tmprule->au_ctxt.type = typedatum->value; tmprule->au_ctxt.type = typedatum->value;
...@@ -3215,14 +3364,15 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) ...@@ -3215,14 +3364,15 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
case AUDIT_SUBJ_CLR: case AUDIT_SUBJ_CLR:
case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_LOW:
case AUDIT_OBJ_LEV_HIGH: case AUDIT_OBJ_LEV_HIGH:
rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
GFP_ATOMIC);
if (rc) if (rc)
goto out; goto out;
break; break;
} }
rc = 0; rc = 0;
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
if (rc) { if (rc) {
selinux_audit_rule_free(tmprule); selinux_audit_rule_free(tmprule);
...@@ -3262,6 +3412,7 @@ int selinux_audit_rule_known(struct audit_krule *rule) ...@@ -3262,6 +3412,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
struct audit_context *actx) struct audit_context *actx)
{ {
struct selinux_state *state = &selinux_state;
struct context *ctxt; struct context *ctxt;
struct mls_level *level; struct mls_level *level;
struct selinux_audit_rule *rule = vrule; struct selinux_audit_rule *rule = vrule;
...@@ -3272,14 +3423,14 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, ...@@ -3272,14 +3423,14 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
return -ENOENT; return -ENOENT;
} }
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
if (rule->au_seqno < latest_granting) { if (rule->au_seqno < state->ss->latest_granting) {
match = -ESTALE; match = -ESTALE;
goto out; goto out;
} }
ctxt = sidtab_search(&sidtab, sid); ctxt = sidtab_search(&state->ss->sidtab, sid);
if (unlikely(!ctxt)) { if (unlikely(!ctxt)) {
WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
sid); sid);
...@@ -3363,7 +3514,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, ...@@ -3363,7 +3514,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
} }
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return match; return match;
} }
...@@ -3437,19 +3588,22 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, ...@@ -3437,19 +3588,22 @@ static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
* failure. * failure.
* *
*/ */
int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, int security_netlbl_secattr_to_sid(struct selinux_state *state,
struct netlbl_lsm_secattr *secattr,
u32 *sid) u32 *sid)
{ {
struct policydb *policydb = &state->ss->policydb;
struct sidtab *sidtab = &state->ss->sidtab;
int rc; int rc;
struct context *ctx; struct context *ctx;
struct context ctx_new; struct context ctx_new;
if (!ss_initialized) { if (!state->initialized) {
*sid = SECSID_NULL; *sid = SECSID_NULL;
return 0; return 0;
} }
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
if (secattr->flags & NETLBL_SECATTR_CACHE) if (secattr->flags & NETLBL_SECATTR_CACHE)
*sid = *(u32 *)secattr->cache->data; *sid = *(u32 *)secattr->cache->data;
...@@ -3457,7 +3611,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, ...@@ -3457,7 +3611,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
*sid = secattr->attr.secid; *sid = secattr->attr.secid;
else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
rc = -EIDRM; rc = -EIDRM;
ctx = sidtab_search(&sidtab, SECINITSID_NETMSG); ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
if (ctx == NULL) if (ctx == NULL)
goto out; goto out;
...@@ -3465,17 +3619,17 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, ...@@ -3465,17 +3619,17 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
ctx_new.user = ctx->user; ctx_new.user = ctx->user;
ctx_new.role = ctx->role; ctx_new.role = ctx->role;
ctx_new.type = ctx->type; ctx_new.type = ctx->type;
mls_import_netlbl_lvl(&ctx_new, secattr); mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
rc = mls_import_netlbl_cat(&ctx_new, secattr); rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
if (rc) if (rc)
goto out; goto out;
} }
rc = -EIDRM; rc = -EIDRM;
if (!mls_context_isvalid(&policydb, &ctx_new)) if (!mls_context_isvalid(policydb, &ctx_new))
goto out_free; goto out_free;
rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
if (rc) if (rc)
goto out_free; goto out_free;
...@@ -3485,12 +3639,12 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, ...@@ -3485,12 +3639,12 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
} else } else
*sid = SECSID_NULL; *sid = SECSID_NULL;
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return 0; return 0;
out_free: out_free:
ebitmap_destroy(&ctx_new.range.level[0].cat); ebitmap_destroy(&ctx_new.range.level[0].cat);
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
...@@ -3504,33 +3658,35 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, ...@@ -3504,33 +3658,35 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
* Returns zero on success, negative values on failure. * Returns zero on success, negative values on failure.
* *
*/ */
int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) int security_netlbl_sid_to_secattr(struct selinux_state *state,
u32 sid, struct netlbl_lsm_secattr *secattr)
{ {
struct policydb *policydb = &state->ss->policydb;
int rc; int rc;
struct context *ctx; struct context *ctx;
if (!ss_initialized) if (!state->initialized)
return 0; return 0;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
rc = -ENOENT; rc = -ENOENT;
ctx = sidtab_search(&sidtab, sid); ctx = sidtab_search(&state->ss->sidtab, sid);
if (ctx == NULL) if (ctx == NULL)
goto out; goto out;
rc = -ENOMEM; rc = -ENOMEM;
secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1), secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
GFP_ATOMIC); GFP_ATOMIC);
if (secattr->domain == NULL) if (secattr->domain == NULL)
goto out; goto out;
secattr->attr.secid = sid; secattr->attr.secid = sid;
secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
mls_export_netlbl_lvl(ctx, secattr); mls_export_netlbl_lvl(policydb, ctx, secattr);
rc = mls_export_netlbl_cat(ctx, secattr); rc = mls_export_netlbl_cat(policydb, ctx, secattr);
out: out:
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
return rc; return rc;
} }
#endif /* CONFIG_NETLABEL */ #endif /* CONFIG_NETLABEL */
...@@ -3541,15 +3697,17 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) ...@@ -3541,15 +3697,17 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
* @len: length of data in bytes * @len: length of data in bytes
* *
*/ */
int security_read_policy(void **data, size_t *len) int security_read_policy(struct selinux_state *state,
void **data, size_t *len)
{ {
struct policydb *policydb = &state->ss->policydb;
int rc; int rc;
struct policy_file fp; struct policy_file fp;
if (!ss_initialized) if (!state->initialized)
return -EINVAL; return -EINVAL;
*len = security_policydb_len(); *len = security_policydb_len(state);
*data = vmalloc_user(*len); *data = vmalloc_user(*len);
if (!*data) if (!*data)
...@@ -3558,9 +3716,9 @@ int security_read_policy(void **data, size_t *len) ...@@ -3558,9 +3716,9 @@ int security_read_policy(void **data, size_t *len)
fp.data = *data; fp.data = *data;
fp.len = *len; fp.len = *len;
read_lock(&policy_rwlock); read_lock(&state->ss->policy_rwlock);
rc = policydb_write(&policydb, &fp); rc = policydb_write(policydb, &fp);
read_unlock(&policy_rwlock); read_unlock(&state->ss->policy_rwlock);
if (rc) if (rc)
return rc; return rc;
......
...@@ -10,7 +10,28 @@ ...@@ -10,7 +10,28 @@
#include "policydb.h" #include "policydb.h"
#include "sidtab.h" #include "sidtab.h"
extern struct policydb policydb; /* Mapping for a single class */
struct selinux_mapping {
u16 value; /* policy value for class */
unsigned int num_perms; /* number of permissions in class */
u32 perms[sizeof(u32) * 8]; /* policy values for permissions */
};
/* Map for all of the classes, with array size */
struct selinux_map {
struct selinux_mapping *mapping; /* indexed by class */
u16 size; /* array size of mapping */
};
struct selinux_ss {
struct sidtab sidtab;
struct policydb policydb;
rwlock_t policy_rwlock;
u32 latest_granting;
struct selinux_map map;
struct page *status_page;
struct mutex status_lock;
};
void services_compute_xperms_drivers(struct extended_perms *xperms, void services_compute_xperms_drivers(struct extended_perms *xperms,
struct avtab_node *node); struct avtab_node *node);
...@@ -19,4 +40,3 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd, ...@@ -19,4 +40,3 @@ void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
struct avtab_node *node); struct avtab_node *node);
#endif /* _SS_SERVICES_H_ */ #endif /* _SS_SERVICES_H_ */
...@@ -35,8 +35,6 @@ ...@@ -35,8 +35,6 @@
* In most cases, application shall confirm the kernel status is not * In most cases, application shall confirm the kernel status is not
* changed without any system call invocations. * changed without any system call invocations.
*/ */
static struct page *selinux_status_page;
static DEFINE_MUTEX(selinux_status_lock);
/* /*
* selinux_kernel_status_page * selinux_kernel_status_page
...@@ -44,21 +42,21 @@ static DEFINE_MUTEX(selinux_status_lock); ...@@ -44,21 +42,21 @@ static DEFINE_MUTEX(selinux_status_lock);
* It returns a reference to selinux_status_page. If the status page is * It returns a reference to selinux_status_page. If the status page is
* not allocated yet, it also tries to allocate it at the first time. * not allocated yet, it also tries to allocate it at the first time.
*/ */
struct page *selinux_kernel_status_page(void) struct page *selinux_kernel_status_page(struct selinux_state *state)
{ {
struct selinux_kernel_status *status; struct selinux_kernel_status *status;
struct page *result = NULL; struct page *result = NULL;
mutex_lock(&selinux_status_lock); mutex_lock(&state->ss->status_lock);
if (!selinux_status_page) { if (!state->ss->status_page) {
selinux_status_page = alloc_page(GFP_KERNEL|__GFP_ZERO); state->ss->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
if (selinux_status_page) { if (state->ss->status_page) {
status = page_address(selinux_status_page); status = page_address(state->ss->status_page);
status->version = SELINUX_KERNEL_STATUS_VERSION; status->version = SELINUX_KERNEL_STATUS_VERSION;
status->sequence = 0; status->sequence = 0;
status->enforcing = selinux_enforcing; status->enforcing = enforcing_enabled(state);
/* /*
* NOTE: the next policyload event shall set * NOTE: the next policyload event shall set
* a positive value on the status->policyload, * a positive value on the status->policyload,
...@@ -66,11 +64,12 @@ struct page *selinux_kernel_status_page(void) ...@@ -66,11 +64,12 @@ struct page *selinux_kernel_status_page(void)
* So, application can know it was updated. * So, application can know it was updated.
*/ */
status->policyload = 0; status->policyload = 0;
status->deny_unknown = !security_get_allow_unknown(); status->deny_unknown =
!security_get_allow_unknown(state);
} }
} }
result = selinux_status_page; result = state->ss->status_page;
mutex_unlock(&selinux_status_lock); mutex_unlock(&state->ss->status_lock);
return result; return result;
} }
...@@ -80,13 +79,14 @@ struct page *selinux_kernel_status_page(void) ...@@ -80,13 +79,14 @@ struct page *selinux_kernel_status_page(void)
* *
* It updates status of the current enforcing/permissive mode. * It updates status of the current enforcing/permissive mode.
*/ */
void selinux_status_update_setenforce(int enforcing) void selinux_status_update_setenforce(struct selinux_state *state,
int enforcing)
{ {
struct selinux_kernel_status *status; struct selinux_kernel_status *status;
mutex_lock(&selinux_status_lock); mutex_lock(&state->ss->status_lock);
if (selinux_status_page) { if (state->ss->status_page) {
status = page_address(selinux_status_page); status = page_address(state->ss->status_page);
status->sequence++; status->sequence++;
smp_wmb(); smp_wmb();
...@@ -96,7 +96,7 @@ void selinux_status_update_setenforce(int enforcing) ...@@ -96,7 +96,7 @@ void selinux_status_update_setenforce(int enforcing)
smp_wmb(); smp_wmb();
status->sequence++; status->sequence++;
} }
mutex_unlock(&selinux_status_lock); mutex_unlock(&state->ss->status_lock);
} }
/* /*
...@@ -105,22 +105,23 @@ void selinux_status_update_setenforce(int enforcing) ...@@ -105,22 +105,23 @@ void selinux_status_update_setenforce(int enforcing)
* It updates status of the times of policy reloaded, and current * It updates status of the times of policy reloaded, and current
* setting of deny_unknown. * setting of deny_unknown.
*/ */
void selinux_status_update_policyload(int seqno) void selinux_status_update_policyload(struct selinux_state *state,
int seqno)
{ {
struct selinux_kernel_status *status; struct selinux_kernel_status *status;
mutex_lock(&selinux_status_lock); mutex_lock(&state->ss->status_lock);
if (selinux_status_page) { if (state->ss->status_page) {
status = page_address(selinux_status_page); status = page_address(state->ss->status_page);
status->sequence++; status->sequence++;
smp_wmb(); smp_wmb();
status->policyload = seqno; status->policyload = seqno;
status->deny_unknown = !security_get_allow_unknown(); status->deny_unknown = !security_get_allow_unknown(state);
smp_wmb(); smp_wmb();
status->sequence++; status->sequence++;
} }
mutex_unlock(&selinux_status_lock); mutex_unlock(&state->ss->status_lock);
} }
...@@ -101,11 +101,13 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp, ...@@ -101,11 +101,13 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
ctx->ctx_len = str_len; ctx->ctx_len = str_len;
memcpy(ctx->ctx_str, &uctx[1], str_len); memcpy(ctx->ctx_str, &uctx[1], str_len);
ctx->ctx_str[str_len] = '\0'; ctx->ctx_str[str_len] = '\0';
rc = security_context_to_sid(ctx->ctx_str, str_len, &ctx->ctx_sid, gfp); rc = security_context_to_sid(&selinux_state, ctx->ctx_str, str_len,
&ctx->ctx_sid, gfp);
if (rc) if (rc)
goto err; goto err;
rc = avc_has_perm(tsec->sid, ctx->ctx_sid, rc = avc_has_perm(&selinux_state,
tsec->sid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
if (rc) if (rc)
goto err; goto err;
...@@ -141,7 +143,8 @@ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) ...@@ -141,7 +143,8 @@ static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
if (!ctx) if (!ctx)
return 0; return 0;
return avc_has_perm(tsec->sid, ctx->ctx_sid, return avc_has_perm(&selinux_state,
tsec->sid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
NULL); NULL);
} }
...@@ -163,7 +166,8 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) ...@@ -163,7 +166,8 @@ int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
if (!selinux_authorizable_ctx(ctx)) if (!selinux_authorizable_ctx(ctx))
return -EINVAL; return -EINVAL;
rc = avc_has_perm(fl_secid, ctx->ctx_sid, rc = avc_has_perm(&selinux_state,
fl_secid, ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL); SECCLASS_ASSOCIATION, ASSOCIATION__POLMATCH, NULL);
return (rc == -EACCES ? -ESRCH : rc); return (rc == -EACCES ? -ESRCH : rc);
} }
...@@ -202,7 +206,8 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, ...@@ -202,7 +206,8 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
/* We don't need a separate SA Vs. policy polmatch check since the SA /* We don't need a separate SA Vs. policy polmatch check since the SA
* is now of the same label as the flow and a flow Vs. policy polmatch * is now of the same label as the flow and a flow Vs. policy polmatch
* check had already happened in selinux_xfrm_policy_lookup() above. */ * check had already happened in selinux_xfrm_policy_lookup() above. */
return (avc_has_perm(fl->flowi_secid, state_sid, return (avc_has_perm(&selinux_state,
fl->flowi_secid, state_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO,
NULL) ? 0 : 1); NULL) ? 0 : 1);
} }
...@@ -352,7 +357,8 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x, ...@@ -352,7 +357,8 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
if (secid == 0) if (secid == 0)
return -EINVAL; return -EINVAL;
rc = security_sid_to_context(secid, &ctx_str, &str_len); rc = security_sid_to_context(&selinux_state, secid, &ctx_str,
&str_len);
if (rc) if (rc)
return rc; return rc;
...@@ -420,7 +426,8 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb, ...@@ -420,7 +426,8 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended, /* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in * according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */ * non-IPsec communication unless explicitly allowed by policy. */
return avc_has_perm(sk_sid, peer_sid, return avc_has_perm(&selinux_state,
sk_sid, peer_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad); SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, ad);
} }
...@@ -463,6 +470,6 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb, ...@@ -463,6 +470,6 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,
/* This check even when there's no association involved is intended, /* This check even when there's no association involved is intended,
* according to Trent Jaeger, to make sure a process can't engage in * according to Trent Jaeger, to make sure a process can't engage in
* non-IPsec communication unless explicitly allowed by policy. */ * non-IPsec communication unless explicitly allowed by policy. */
return avc_has_perm(sk_sid, SECINITSID_UNLABELED, return avc_has_perm(&selinux_state, sk_sid, SECINITSID_UNLABELED,
SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad); SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, ad);
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册