selinux/stable-4.17 PR 20180403
-----BEGIN PGP SIGNATURE----- iQJIBAABCAAyFiEEcQCq365ubpQNLgrWVeRaWujKfIoFAlrD6XoUHHBhdWxAcGF1 bC1tb29yZS5jb20ACgkQVeRaWujKfIpy9RAAjwhkNBNJhw1UlGggVvst8lzJBdMp XxL7cg+1TcZkB12yrghILg+gY4j5PzY4GJo1gvllWIHsT8Ud6cQTI/AzeYR2OfZ3 mHv3gtyzmHsPGBdqhmgC7R10tpyXFXwDc3VLMtuuDiUl/seFEaJWOMYP7zj+tRil XoOCyoV9bb1wb7vNAzQikK8yhz3fu72Y5QOODLfaYeYojMKs8Q8pMZgi68oVQUXk SmS2mj0k2P3UqeOSk+8phJQhilm32m0tE0YnLvzAhblJLqeS2DUNnWORP1j4oQ/Q aOOu4ZQ9PA1N7VAIGceuf2HZHhnrFzWdvggp2bxegcRSIfUZ84FuZbrj60RUz2ja V6GmKYACnyd28TAWdnzjKEd4dc36LSPxnaj8hcrvyO2V34ozVEsvIEIJREoXRUJS heJ9HT+VIvmguzRCIPPeC1ZYopIt8M1kTRrszigU80TuZjIP0VJHLGQn/rgRQzuO cV5gmJ6TSGn1l54H13koBzgUCo0cAub8Nl+288qek+jLWoHnKwzLB+1HCWuyeCHt 2q6wdFfenYH0lXdIzCeC7NNHRKCrPNwkZ/32d4ZQf4cu5tAn8bOk8dSHchoAfZG8 p7N6jPPoxmi2F/GRKrTiUNZvQpyvgX3hjtJS6ljOTSYgRhjeNYeCP8U+BlOpLVQy U4KzB9wOAngTEpo= =p2Sh -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
9eda2d2dca
175
Documentation/security/LSM-sctp.rst
Normal file
175
Documentation/security/LSM-sctp.rst
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
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 |
|
||||||
|
------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
158
Documentation/security/SELinux-sctp.rst
Normal file
158
Documentation/security/SELinux-sctp.rst
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
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 @@
|
||||||
* 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 {
|
||||||
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 {
|
||||||
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;
|
||||||
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);
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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;
|
||||||
#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,
|
||||||
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,
|
||||||
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,
|
||||||
/* 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,
|
||||||
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,
|
||||||
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,
|
||||||
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 = {
|
||||||
.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 = {
|
||||||
.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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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 = {
|
||||||
.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 = {
|
||||||
.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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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(
|
||||||
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(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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,
|
||||||
/* 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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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
|
||||||
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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
{
|
{
|
||||||
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)
|
||||||
}
|
}
|
||||||
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 {
|
||||||
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)
|
||||||
* @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
|
||||||
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
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ out:
|
||||||
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)
|
||||||
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
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
|
|
||||||
spin_lock_irqsave(¬if_lock, flag);
|
spin_lock_irqsave(¬if_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(¬if_lock, flag);
|
spin_unlock_irqrestore(¬if_lock, flag);
|
||||||
|
|
||||||
|
@ -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,
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
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 @@ out:
|
||||||
* 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,
|
||||||
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,
|
||||||
/* 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,
|
||||||
|
|
||||||
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,
|
||||||
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 @@ out:
|
||||||
/**
|
/**
|
||||||
* 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)
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
* 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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
* 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,
|
||||||
* 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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ decision:
|
||||||
* 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,
|
||||||
|
|
||||||
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,
|
||||||
* 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)
|
||||||
* 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); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 @@
|
||||||
#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 {
|
||||||
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,
|
||||||
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,
|
||||||
* 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,
|
||||||
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);
|
||||||
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 @@
|
||||||
|
|
||||||
#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 {
|
||||||
|
|
||||||
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[] = {
|
||||||
{ 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 @@
|
||||||
#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 @@
|
||||||
#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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
{
|
{
|
||||||
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,
|
||||||
{
|
{
|
||||||
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 {
|
||||||
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 {
|
||||||
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 @@
|
||||||
#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 {
|
||||||
|
|
||||||
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;
|
||||||
/* 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;
|
||||||
|
|
||||||
int security_load_policy(void *data, size_t len);
|
struct selinux_state {
|
||||||
int security_read_policy(void **data, size_t *len);
|
bool disabled;
|
||||||
size_t security_policydb_len(void);
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
int security_policycap_supported(unsigned int req_cap);
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool selinux_policycap_extsockclass(void)
|
||||||
|
{
|
||||||
|
struct selinux_state *state = &selinux_state;
|
||||||
|
|
||||||
|
return state->policycap[POLICYDB_CAPABILITY_EXTSOCKCLASS];
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
/* 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);
|
||||||
#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);
|
||||||
/*
|
/*
|
||||||
* 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 {
|
||||||
*/
|
*/
|
||||||
} __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);
|
||||||
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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ skbuff_setsid_return:
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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;
|
||||||
|
|
||||||
|
@ -468,6 +545,69 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* selinux_netlbl_socket_connect_helper - Help 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int selinux_netlbl_socket_connect_helper(struct sock *sk,
|
||||||
|
struct sockaddr *addr)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
|
struct netlbl_lsm_secattr *secattr;
|
||||||
|
|
||||||
|
/* connected sockets are allowed to disconnect when the address family
|
||||||
|
* is set to AF_UNSPEC, if that is what is happening we want to reset
|
||||||
|
* the socket */
|
||||||
|
if (addr->sa_family == AF_UNSPEC) {
|
||||||
|
netlbl_sock_delattr(sk);
|
||||||
|
sksec->nlbl_state = NLBL_REQSKB;
|
||||||
|
rc = 0;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
secattr = selinux_netlbl_sock_genattr(sk);
|
||||||
|
if (secattr == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
rc = netlbl_conn_setattr(sk, addr, secattr);
|
||||||
|
if (rc == 0)
|
||||||
|
sksec->nlbl_state = NLBL_CONNLABELED;
|
||||||
|
|
||||||
|
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
|
* selinux_netlbl_socket_connect - Label a client-side socket on connect
|
||||||
* @sk: the socket to label
|
* @sk: the socket to label
|
||||||
|
@ -481,34 +621,10 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
||||||
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
|
int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct sk_security_struct *sksec = sk->sk_security;
|
|
||||||
struct netlbl_lsm_secattr *secattr;
|
|
||||||
|
|
||||||
if (sksec->nlbl_state != NLBL_REQSKB &&
|
|
||||||
sksec->nlbl_state != NLBL_CONNLABELED)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
rc = selinux_netlbl_socket_connect_locked(sk, addr);
|
||||||
/* connected sockets are allowed to disconnect when the address family
|
|
||||||
* is set to AF_UNSPEC, if that is what is happening we want to reset
|
|
||||||
* the socket */
|
|
||||||
if (addr->sa_family == AF_UNSPEC) {
|
|
||||||
netlbl_sock_delattr(sk);
|
|
||||||
sksec->nlbl_state = NLBL_REQSKB;
|
|
||||||
rc = 0;
|
|
||||||
goto socket_connect_return;
|
|
||||||
}
|
|
||||||
secattr = selinux_netlbl_sock_genattr(sk);
|
|
||||||
if (secattr == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto socket_connect_return;
|
|
||||||
}
|
|
||||||
rc = netlbl_conn_setattr(sk, addr, secattr);
|
|
||||||
if (rc == 0)
|
|
||||||
sksec->nlbl_state = NLBL_CONNLABELED;
|
|
||||||
|
|
||||||
socket_connect_return:
|
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||||
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);
|
||||||
|
|
||||||
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)
|
||||||
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);
|
||||||
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)
|
||||||
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,
|
||||||
/* 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 @@
|
||||||
* 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)
|
||||||
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)
|
||||||
* 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,
|
||||||
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,
|
||||||
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,
|
||||||
*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,
|
||||||
*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,
|
||||||
*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 @@ out:
|
||||||
* 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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
/* 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,
|
||||||
* 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,
|
||||||
* 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,
|
||||||
* 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,
|
||||||
* 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 @@
|
||||||
#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,
|
||||||
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,
|
||||||
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;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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,
|
||||||
struct avtab_node *node);
|
struct avtab_node *node);
|
||||||
|
|
||||||
#endif /* _SS_SERVICES_H_ */
|
#endif /* _SS_SERVICES_H_ */
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
* 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)
|
||||||
* 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)
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
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)
|
||||||
* 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,
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
/* 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,
|
||||||
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,
|
||||||
/* 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,
|
||||||
/* 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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue