Commit b1dba247 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull SELinux update from Paul Moore:
 "This is one of the bigger SELinux pull requests in recent years with
  28 patches. Everything is passing our test suite and the highlights
  are below:

   - Mark CONFIG_SECURITY_SELINUX_DISABLE as deprecated. We're some time
     away from actually attempting to remove this in the kernel, but the
     only distro we know that still uses it (Fedora) is working on
     moving away from this so we want to at least let people know we are
     planning to remove it.

   - Reorder the SELinux hooks to help prevent bad things when SELinux
     is disabled at runtime. The proper fix is to remove the
     CONFIG_SECURITY_SELINUX_DISABLE functionality (see above) and just
     take care of it at boot time (e.g. "selinux=0").

   - Add SELinux controls for the kernel lockdown functionality,
     introducing a new SELinux class/permissions: "lockdown { integrity
     confidentiality }".

   - Add a SELinux control for move_mount(2) that reuses the "file {
     mounton }" permission.

   - Improvements to the SELinux security label data store lookup
     functions to speed up translations between our internal label
     representations and the visible string labels (both directions).

   - Revisit a previous fix related to SELinux inode auditing and
     permission caching and do it correctly this time.

   - Fix the SELinux access decision cache to cleanup properly on error.
     In some extreme cases this could limit the cache size and result in
     a decrease in performance.

   - Enable SELinux per-file labeling for binderfs.

   - The SELinux initialized and disabled flags were wrapped with
     accessors to ensure they are accessed correctly.

   - Mark several key SELinux structures with __randomize_layout.

   - Changes to the LSM build configuration to only build
     security/lsm_audit.c when needed.

   - Changes to the SELinux build configuration to only build the IB
     object cache when CONFIG_SECURITY_INFINIBAND is enabled.

   - Move a number of single-caller functions into their callers.

   - Documentation fixes (/selinux -> /sys/fs/selinux).

   - A handful of cleanup patches that aren't worth mentioning on their
     own, the individual descriptions have plenty of detail"

* tag 'selinux-pr-20200127' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux: (28 commits)
  selinux: fix regression introduced by move_mount(2) syscall
  selinux: do not allocate ancillary buffer on first load
  selinux: remove redundant allocation and helper functions
  selinux: remove redundant selinux_nlmsg_perm
  selinux: fix wrong buffer types in policydb.c
  selinux: reorder hooks to make runtime disable less broken
  selinux: treat atomic flags more carefully
  selinux: make default_noexec read-only after init
  selinux: move ibpkeys code under CONFIG_SECURITY_INFINIBAND.
  selinux: remove redundant msg_msg_alloc_security
  Documentation,selinux: fix references to old selinuxfs mount point
  selinux: deprecate disabling SELinux and runtime
  selinux: allow per-file labelling for binderfs
  selinuxfs: use scnprintf to get real length for inode
  selinux: remove set but not used variable 'sidtab'
  selinux: ensure the policy has been loaded before reading the sidtab stats
  selinux: ensure we cleanup the internal AVC counters on error in avc_update()
  selinux: randomize layout of key structures
  selinux: clean up selinux_enabled/disabled/enforcing_boot
  selinux: remove unnecessary selinux cred request
  ...
parents 07e309a9 98aa0034
What: /sys/fs/selinux/disable
Date: April 2005 (predates git)
KernelVersion: 2.6.12-rc2 (predates git)
Contact: selinux@vger.kernel.org
Description:
The selinuxfs "disable" node allows SELinux to be disabled at runtime
prior to a policy being loaded into the kernel. If disabled via this
mechanism, SELinux will remain disabled until the system is rebooted.
The preferred method of disabling SELinux is via the "selinux=0" boot
parameter, but the selinuxfs "disable" node was created to make it
easier for systems with primitive bootloaders that did not allow for
easy modification of the kernel command line. Unfortunately, allowing
for SELinux to be disabled at runtime makes it difficult to secure the
kernel's LSM hooks using the "__ro_after_init" feature.
Thankfully, the need for the SELinux runtime disable appears to be
gone, the default Kconfig configuration disables this selinuxfs node,
and only one of the major distributions, Fedora, supports disabling
SELinux at runtime. Fedora is in the process of removing the
selinuxfs "disable" node and once that is complete we will start the
slow process of removing this code from the kernel.
More information on /sys/fs/selinux/disable can be found under the
CONFIG_SECURITY_SELINUX_DISABLE Kconfig option.
......@@ -511,7 +511,7 @@
1 -- check protection requested by application.
Default value is set via a kernel config option.
Value can be changed at runtime via
/selinux/checkreqprot.
/sys/fs/selinux/checkreqprot.
cio_ignore= [S390]
See Documentation/s390/common_io.rst for details.
......@@ -1245,7 +1245,8 @@
0 -- permissive (log only, no denials).
1 -- enforcing (deny and log).
Default value is 0.
Value can be changed at runtime via /selinux/enforce.
Value can be changed at runtime via
/sys/fs/selinux/enforce.
erst_disable [ACPI]
Disable Error Record Serialization Table (ERST)
......@@ -4348,9 +4349,7 @@
See security/selinux/Kconfig help text.
0 -- disable.
1 -- enable.
Default value is set via kernel config option.
If enabled at boot time, /selinux/disable can be used
later to disable prior to initial policy load.
Default value is 1.
apparmor= [APPARMOR] Disable or enable AppArmor at boot time
Format: { "0" | "1" }
......
......@@ -14870,6 +14870,7 @@ F: include/uapi/linux/selinux_netlink.h
F: security/selinux/
F: scripts/selinux/
F: Documentation/admin-guide/LSM/SELinux.rst
F: Documentation/ABI/obsolete/sysfs-selinux-disable
SENSABLE PHANTOM
M: Jiri Slaby <jirislaby@gmail.com>
......
......@@ -74,6 +74,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_FILE 12
#define LSM_AUDIT_DATA_IBPKEY 13
#define LSM_AUDIT_DATA_IBENDPORT 14
#define LSM_AUDIT_DATA_LOCKDOWN 15
union {
struct path path;
struct dentry *dentry;
......@@ -93,6 +94,7 @@ struct common_audit_data {
struct file *file;
struct lsm_ibpkey_audit *ibpkey;
struct lsm_ibendport_audit *ibendport;
int reason;
} u;
/* this union contains LSM specific data */
union {
......
......@@ -128,6 +128,8 @@ enum lockdown_reason {
LOCKDOWN_CONFIDENTIALITY_MAX,
};
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
int cap, unsigned int opts);
......
......@@ -22,7 +22,7 @@ obj-$(CONFIG_SECURITY) += security.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
obj-$(CONFIG_AUDIT) += lsm_audit.o
obj-$(CONFIG_SECURITY) += lsm_audit.o
obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
obj-$(CONFIG_SECURITY_YAMA) += yama/
......
......@@ -16,33 +16,6 @@
static enum lockdown_reason kernel_locked_down;
static const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
[LOCKDOWN_NONE] = "none",
[LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading",
[LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port",
[LOCKDOWN_EFI_TEST] = "/dev/efi_test access",
[LOCKDOWN_KEXEC] = "kexec of unsigned images",
[LOCKDOWN_HIBERNATION] = "hibernation",
[LOCKDOWN_PCI_ACCESS] = "direct PCI access",
[LOCKDOWN_IOPORT] = "raw io port access",
[LOCKDOWN_MSR] = "raw MSR access",
[LOCKDOWN_ACPI_TABLES] = "modifying ACPI tables",
[LOCKDOWN_PCMCIA_CIS] = "direct PCMCIA CIS storage",
[LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO",
[LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters",
[LOCKDOWN_MMIOTRACE] = "unsafe mmio",
[LOCKDOWN_DEBUGFS] = "debugfs access",
[LOCKDOWN_XMON_WR] = "xmon write access",
[LOCKDOWN_INTEGRITY_MAX] = "integrity",
[LOCKDOWN_KCORE] = "/proc/kcore access",
[LOCKDOWN_KPROBES] = "use of kprobes",
[LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM",
[LOCKDOWN_PERF] = "unsafe use of perf",
[LOCKDOWN_TRACEFS] = "use of tracefs",
[LOCKDOWN_XMON_RW] = "xmon read and write access",
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
LOCKDOWN_INTEGRITY_MAX,
LOCKDOWN_CONFIDENTIALITY_MAX};
......
......@@ -27,6 +27,7 @@
#include <linux/dccp.h>
#include <linux/sctp.h>
#include <linux/lsm_audit.h>
#include <linux/security.h>
/**
* ipv4_skb_to_auditdata : fill auditdata from skb
......@@ -425,6 +426,10 @@ static void dump_common_audit_data(struct audit_buffer *ab,
a->u.ibendport->dev_name,
a->u.ibendport->port);
break;
case LSM_AUDIT_DATA_LOCKDOWN:
audit_log_format(ab, " lockdown_reason=");
audit_log_string(ab, lockdown_reasons[a->u.reason]);
break;
} /* switch (a->type) */
}
......
......@@ -35,6 +35,39 @@
#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
#define EARLY_LSM_COUNT (__end_early_lsm_info - __start_early_lsm_info)
/*
* These are descriptions of the reasons that can be passed to the
* security_locked_down() LSM hook. Placing this array here allows
* all security modules to use the same descriptions for auditing
* purposes.
*/
const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = {
[LOCKDOWN_NONE] = "none",
[LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading",
[LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port",
[LOCKDOWN_EFI_TEST] = "/dev/efi_test access",
[LOCKDOWN_KEXEC] = "kexec of unsigned images",
[LOCKDOWN_HIBERNATION] = "hibernation",
[LOCKDOWN_PCI_ACCESS] = "direct PCI access",
[LOCKDOWN_IOPORT] = "raw io port access",
[LOCKDOWN_MSR] = "raw MSR access",
[LOCKDOWN_ACPI_TABLES] = "modifying ACPI tables",
[LOCKDOWN_PCMCIA_CIS] = "direct PCMCIA CIS storage",
[LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO",
[LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters",
[LOCKDOWN_MMIOTRACE] = "unsafe mmio",
[LOCKDOWN_DEBUGFS] = "debugfs access",
[LOCKDOWN_XMON_WR] = "xmon write access",
[LOCKDOWN_INTEGRITY_MAX] = "integrity",
[LOCKDOWN_KCORE] = "/proc/kcore access",
[LOCKDOWN_KPROBES] = "use of kprobes",
[LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM",
[LOCKDOWN_PERF] = "unsafe use of perf",
[LOCKDOWN_TRACEFS] = "use of tracefs",
[LOCKDOWN_XMON_RW] = "xmon read and write access",
[LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality",
};
struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);
......
......@@ -42,6 +42,9 @@ config SECURITY_SELINUX_DISABLE
using the selinux=0 boot parameter instead of enabling this
option.
WARNING: this option is deprecated and will be removed in a future
kernel release.
If you are unsure how to answer this question, answer N.
config SECURITY_SELINUX_DEVELOP
......@@ -55,7 +58,8 @@ config SECURITY_SELINUX_DEVELOP
kernel will start in permissive mode (log everything, deny nothing)
unless you specify enforcing=1 on the kernel command line. You
can interactively toggle the kernel between enforcing mode and
permissive mode (if permitted by the policy) via /selinux/enforce.
permissive mode (if permitted by the policy) via
/sys/fs/selinux/enforce.
config SECURITY_SELINUX_AVC_STATS
bool "NSA SELinux AVC Statistics"
......@@ -63,7 +67,7 @@ config SECURITY_SELINUX_AVC_STATS
default y
help
This option collects access vector cache statistics to
/selinux/avc/cache_stats, which may be monitored via
/sys/fs/selinux/avc/cache_stats, which may be monitored via
tools such as avcstat.
config SECURITY_SELINUX_CHECKREQPROT_VALUE
......@@ -82,6 +86,29 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
default to checking the protection requested by the application.
The checkreqprot flag may be changed from the default via the
'checkreqprot=' boot parameter. It may also be changed at runtime
via /selinux/checkreqprot if authorized by policy.
via /sys/fs/selinux/checkreqprot if authorized by policy.
If you are unsure how to answer this question, answer 0.
config SECURITY_SELINUX_SIDTAB_HASH_BITS
int "NSA SELinux sidtab hashtable size"
depends on SECURITY_SELINUX
range 8 13
default 9
help
This option sets the number of buckets used in the sidtab hashtable
to 2^SECURITY_SELINUX_SIDTAB_HASH_BITS buckets. The number of hash
collisions may be viewed at /sys/fs/selinux/ss/sidtab_hash_stats. If
chain lengths are high (e.g. > 20) then selecting a higher value here
will ensure that lookups times are short and stable.
config SECURITY_SELINUX_SID2STR_CACHE_SIZE
int "NSA SELinux SID to context string translation cache size"
depends on SECURITY_SELINUX
default 256
help
This option defines the size of the internal SID -> context string
cache, which improves the performance of context to string
conversion. Setting this option to 0 disables the cache completely.
If unsure, keep the default value.
......@@ -6,7 +6,7 @@
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
netnode.o netport.o ibpkey.o \
netnode.o netport.o \
ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o
......@@ -14,6 +14,8 @@ selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
selinux-$(CONFIG_NETLABEL) += netlabel.o
selinux-$(CONFIG_SECURITY_INFINIBAND) += ibpkey.o
ccflags-y := -I$(srctree)/security/selinux -I$(srctree)/security/selinux/include
$(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
......
......@@ -424,7 +424,7 @@ static inline int avc_xperms_audit(struct selinux_state *state,
if (likely(!audited))
return 0;
return slow_avc_audit(state, ssid, tsid, tclass, requested,
audited, denied, result, ad, 0);
audited, denied, result, ad);
}
static void avc_node_free(struct rcu_head *rhead)
......@@ -617,40 +617,37 @@ static struct avc_node *avc_insert(struct selinux_avc *avc,
struct avc_node *pos, *node = NULL;
int hvalue;
unsigned long flag;
spinlock_t *lock;
struct hlist_head *head;
if (avc_latest_notif_update(avc, avd->seqno, 1))
goto out;
return NULL;
node = avc_alloc_node(avc);
if (node) {
struct hlist_head *head;
spinlock_t *lock;
int rc = 0;
hvalue = avc_hash(ssid, tsid, tclass);
avc_node_populate(node, ssid, tsid, tclass, avd);
rc = avc_xperms_populate(node, xp_node);
if (rc) {
kmem_cache_free(avc_node_cachep, node);
return NULL;
}
head = &avc->avc_cache.slots[hvalue];
lock = &avc->avc_cache.slots_lock[hvalue];
if (!node)
return NULL;
spin_lock_irqsave(lock, flag);
hlist_for_each_entry(pos, head, list) {
if (pos->ae.ssid == ssid &&
pos->ae.tsid == tsid &&
pos->ae.tclass == tclass) {
avc_node_replace(avc, node, pos);
goto found;
}
avc_node_populate(node, ssid, tsid, tclass, avd);
if (avc_xperms_populate(node, xp_node)) {
avc_node_kill(avc, node);
return NULL;
}
hvalue = avc_hash(ssid, tsid, tclass);
head = &avc->avc_cache.slots[hvalue];
lock = &avc->avc_cache.slots_lock[hvalue];
spin_lock_irqsave(lock, flag);
hlist_for_each_entry(pos, head, list) {
if (pos->ae.ssid == ssid &&
pos->ae.tsid == tsid &&
pos->ae.tclass == tclass) {
avc_node_replace(avc, node, pos);
goto found;
}
hlist_add_head_rcu(&node->list, head);
found:
spin_unlock_irqrestore(lock, flag);
}
out:
hlist_add_head_rcu(&node->list, head);
found:
spin_unlock_irqrestore(lock, flag);
return node;
}
......@@ -758,8 +755,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
noinline int slow_avc_audit(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
u32 requested, u32 audited, u32 denied, int result,
struct common_audit_data *a,
unsigned int flags)
struct common_audit_data *a)
{
struct common_audit_data stack_data;
struct selinux_audit_data sad;
......@@ -772,17 +768,6 @@ noinline int slow_avc_audit(struct selinux_state *state,
a->type = LSM_AUDIT_DATA_NONE;
}
/*
* When in a RCU walk do the audit on the RCU retry. This is because
* the collection of the dname in an inode audit message is not RCU
* safe. Note this may drop some audits when the situation changes
* during retry. However this is logically just as if the operation
* happened a little later.
*/
if ((a->type == LSM_AUDIT_DATA_INODE) &&
(flags & MAY_NOT_BLOCK))
return -ECHILD;
sad.tclass = tclass;
sad.requested = requested;
sad.ssid = ssid;
......@@ -855,15 +840,14 @@ static int avc_update_node(struct selinux_avc *avc,
/*
* If we are in a non-blocking code path, e.g. VFS RCU walk,
* then we must not add permissions to a cache entry
* because we cannot safely audit the denial. Otherwise,
* because we will not audit the denial. Otherwise,
* during the subsequent blocking retry (e.g. VFS ref walk), we
* will find the permissions already granted in the cache entry
* and won't audit anything at all, leading to silent denials in
* permissive mode that only appear when in enforcing mode.
*
* See the corresponding handling in slow_avc_audit(), and the
* logic in selinux_inode_permission for the MAY_NOT_BLOCK flag,
* which is transliterated into AVC_NONBLOCKING.
* See the corresponding handling of MAY_NOT_BLOCK in avc_audit()
* and selinux_inode_permission().
*/
if (flags & AVC_NONBLOCKING)
return 0;
......@@ -907,7 +891,7 @@ static int avc_update_node(struct selinux_avc *avc,
if (orig->ae.xp_node) {
rc = avc_xperms_populate(node, orig->ae.xp_node);
if (rc) {
kmem_cache_free(avc_node_cachep, node);
avc_node_kill(avc, node);
goto out_unlock;
}
}
......@@ -1205,6 +1189,25 @@ int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
return rc;
}
int avc_has_perm_flags(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct common_audit_data *auditdata,
int flags)
{
struct av_decision avd;
int rc, rc2;
rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested,
(flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
&avd);
rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
auditdata, flags);
if (rc2)
return rc2;
return rc;
}
u32 avc_policy_seqno(struct selinux_state *state)
{
return state->avc->avc_cache.latest_notif;
......
This diff is collapsed.
......@@ -222,7 +222,7 @@ static __init int sel_ib_pkey_init(void)
{
int iter;
if (!selinux_enabled)
if (!selinux_enabled_boot)
return 0;
for (iter = 0; iter < SEL_PKEY_HASH_SIZE; iter++) {
......
......@@ -100,8 +100,7 @@ static inline u32 avc_audit_required(u32 requested,
int slow_avc_audit(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass,
u32 requested, u32 audited, u32 denied, int result,
struct common_audit_data *a,
unsigned flags);
struct common_audit_data *a);
/**
* avc_audit - Audit the granting or denial of permissions.
......@@ -135,9 +134,12 @@ static inline int avc_audit(struct selinux_state *state,
audited = avc_audit_required(requested, avd, result, 0, &denied);
if (likely(!audited))
return 0;
/* fall back to ref-walk if we have to generate audit */
if (flags & MAY_NOT_BLOCK)
return -ECHILD;
return slow_avc_audit(state, ssid, tsid, tclass,
requested, audited, denied, result,
a, flags);
a);
}
#define AVC_STRICT 1 /* Ignore permissive mode. */
......@@ -153,6 +155,11 @@ int avc_has_perm(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata);
int avc_has_perm_flags(struct selinux_state *state,
u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata,
int flags);
int avc_has_extended_perms(struct selinux_state *state,
u32 ssid, u32 tsid, u16 tclass, u32 requested,
......
......@@ -246,6 +246,8 @@ struct security_class_mapping secclass_map[] = {
{ COMMON_SOCK_PERMS, NULL } },
{ "perf_event",
{"open", "cpu", "kernel", "tracepoint", "read", "write"} },
{ "lockdown",
{ "integrity", "confidentiality", NULL } },
{ NULL }
};
......
......@@ -14,8 +14,19 @@
#ifndef _SELINUX_IB_PKEY_H
#define _SELINUX_IB_PKEY_H
#ifdef CONFIG_SECURITY_INFINIBAND
void sel_ib_pkey_flush(void);
int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey, u32 *sid);
#else
static inline void sel_ib_pkey_flush(void)
{
return;
}
static inline int sel_ib_pkey_sid(u64 subnet_prefix, u16 pkey, u32 *sid)
{
*sid = SECINITSID_UNLABELED;
return 0;
}
#endif
#endif
......@@ -35,7 +35,7 @@ struct task_security_struct {
u32 create_sid; /* fscreate SID */
u32 keycreate_sid; /* keycreate SID */
u32 sockcreate_sid; /* fscreate SID */
};
} __randomize_layout;
enum label_initialized {
LABEL_INVALID, /* invalid or not initialized */
......
......@@ -69,7 +69,7 @@
struct netlbl_lsm_secattr;
extern int selinux_enabled;
extern int selinux_enabled_boot;
/* Policy capabilities */
enum {
......@@ -99,7 +99,9 @@ struct selinux_avc;
struct selinux_ss;
struct selinux_state {
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
bool disabled;
#endif
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
bool enforcing;
#endif
......@@ -108,22 +110,34 @@ struct selinux_state {
bool policycap[__POLICYDB_CAPABILITY_MAX];
struct selinux_avc *avc;
struct selinux_ss *ss;
};
} __randomize_layout;
void selinux_ss_init(struct selinux_ss **ss);
void selinux_avc_init(struct selinux_avc **avc);
extern struct selinux_state selinux_state;
static inline bool selinux_initialized(const struct selinux_state *state)
{
/* do a synchronized load to avoid race conditions */
return smp_load_acquire(&state->initialized);
}
static inline void selinux_mark_initialized(struct selinux_state *state)
{
/* do a synchronized write to avoid race conditions */
smp_store_release(&state->initialized, true);
}
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
static inline bool enforcing_enabled(struct selinux_state *state)
{
return state->enforcing;
return READ_ONCE(state->enforcing);
}
static inline void enforcing_set(struct selinux_state *state, bool value)
{
state->enforcing = value;
WRITE_ONCE(state->enforcing, value);
}
#else
static inline bool enforcing_enabled(struct selinux_state *state)
......@@ -136,6 +150,23 @@ static inline void enforcing_set(struct selinux_state *state, bool value)
}
#endif
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
static inline bool selinux_disabled(struct selinux_state *state)
{
return READ_ONCE(state->disabled);
}
static inline void selinux_mark_disabled(struct selinux_state *state)
{
WRITE_ONCE(state->disabled, true);
}
#else
static inline bool selinux_disabled(struct selinux_state *state)
{
return false;
}
#endif
static inline bool selinux_policycap_netpeer(void)
{
struct selinux_state *state = &selinux_state;
......@@ -395,5 +426,6 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
extern void avtab_cache_init(void);
extern void ebitmap_cache_init(void);
extern void hashtab_cache_init(void);
extern int security_sidtab_hash_stats(struct selinux_state *state, char *page);
#endif /* _SELINUX_SECURITY_H_ */
......@@ -266,7 +266,7 @@ static __init int sel_netif_init(void)
{
int i;
if (!selinux_enabled)
if (!selinux_enabled_boot)
return 0;
for (i = 0; i < SEL_NETIF_HASH_SIZE; i++)
......
......@@ -291,7 +291,7 @@ static __init int sel_netnode_init(void)
{
int iter;
if (!selinux_enabled)
if (!selinux_enabled_boot)
return 0;
for (iter = 0; iter < SEL_NETNODE_HASH_SIZE; iter++) {
......
......@@ -225,7 +225,7 @@ static __init int sel_netport_init(void)
{
int iter;
if (!selinux_enabled)
if (!selinux_enabled_boot)
return 0;
for (iter = 0; iter < SEL_NETPORT_HASH_SIZE; iter++) {
......
......@@ -168,11 +168,10 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
goto out;
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
"enforcing=%d old_enforcing=%d auid=%u ses=%u"
" enabled=%d old-enabled=%d lsm=selinux res=1",
" enabled=1 old-enabled=1 lsm=selinux res=1",
new_value, old_value,
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current),
selinux_enabled, selinux_enabled);
audit_get_sessionid(current));
enforcing_set(state, new_value);
if (new_value)
avc_ss_reset(state->avc, 0);
......@@ -282,6 +281,13 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
int new_value;
int enforcing;
/* NOTE: we are now officially considering runtime disable as
* deprecated, and using it will become increasingly painful
* (e.g. sleeping/blocking) as we progress through future
* kernel releases until eventually it is removed
*/
pr_err("SELinux: Runtime disable is deprecated, use selinux=0 on the kernel cmdline.\n");
if (count >= PAGE_SIZE)
return -ENOMEM;
......@@ -304,10 +310,10 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
goto out;
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
"enforcing=%d old_enforcing=%d auid=%u ses=%u"
" enabled=%d old-enabled=%d lsm=selinux res=1",
" enabled=0 old-enabled=1 lsm=selinux res=1",
enforcing, enforcing,
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current), 0, 1);
audit_get_sessionid(current));
}
length = count;
......@@ -1482,6 +1488,32 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
return length;
}
static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
struct selinux_state *state = fsi->state;
char *page;
ssize_t length;
page = (char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
length = security_sidtab_hash_stats(state, page);
if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, page,
length);
free_page((unsigned long)page);
return length;
}
static const struct file_operations sel_sidtab_hash_stats_ops = {
.read = sel_read_sidtab_hash_stats,
.llseek = generic_file_llseek,
};
static const struct file_operations sel_avc_cache_threshold_ops = {
.read = sel_read_avc_cache_threshold,
.write = sel_write_avc_cache_threshold,
......@@ -1599,6 +1631,37 @@ static int sel_make_avc_files(struct dentry *dir)
return 0;
}
static int sel_make_ss_files(struct dentry *dir)
{
struct super_block *sb = dir->d_sb;
struct selinux_fs_info *fsi = sb->s_fs_info;
int i;
static struct tree_descr files[] = {
{ "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO },
};
for (i = 0; i < ARRAY_SIZE(files); i++) {
struct inode *inode;
struct dentry *dentry;
dentry = d_alloc_name(dir, files[i].name);
if (!dentry)
return -ENOMEM;
inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
if (!inode) {
dput(dentry);
return -ENOMEM;
}
inode->i_fop = files[i].ops;
inode->i_ino = ++fsi->last_ino;
d_add(dentry, inode);
}
return 0;
}
static ssize_t sel_read_initcon(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
......@@ -1672,7 +1735,7 @@ static ssize_t sel_read_class(struct file *file, char __user *buf,
{
unsigned long ino = file_inode(file)->i_ino;
char res[TMPBUFLEN];
ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
ssize_t len = scnprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
return simple_read_from_buffer(buf, count, ppos, res, len);
}
......@@ -1686,7 +1749,7 @@ static ssize_t sel_read_perm(struct file *file, char __user *buf,
{
unsigned long ino = file_inode(file)->i_ino;
char res[TMPBUFLEN];
ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
ssize_t len = scnprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
return simple_read_from_buffer(buf, count, ppos, res, len);
}
......@@ -1963,6 +2026,14 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
}
ret = sel_make_avc_files(dentry);
dentry = sel_make_dir(sb->s_root, "ss", &fsi->last_ino);
if (IS_ERR(dentry)) {
ret = PTR_ERR(dentry);
goto err;
}
ret = sel_make_ss_files(dentry);
if (ret)
goto err;
......@@ -2040,7 +2111,7 @@ static int __init init_sel_fs(void)
sizeof(NULL_FILE_NAME)-1);
int err;
if (!selinux_enabled)
if (!selinux_enabled_boot)
return 0;
err = sysfs_create_mount_point(fs_kobj, "selinux");
......
......@@ -31,6 +31,7 @@ struct context {
u32 len; /* length of string in bytes */
struct mls_range range;
char *str; /* string representation if context cannot be mapped. */
u32 hash; /* a hash of the string representation */
};
static inline void mls_context_init(struct context *c)
......@@ -168,12 +169,13 @@ static inline int context_cpy(struct context *dst, struct context *src)
kfree(dst->str);
return rc;
}
dst->hash = src->hash;
return 0;
}
static inline void context_destroy(struct context *c)
{
c->user = c->role = c->type = 0;
c->user = c->role = c->type = c->hash = 0;
kfree(c->str);
c->str = NULL;
c->len = 0;
......@@ -182,6 +184,8 @@ static inline void context_destroy(struct context *c)
static inline int context_cmp(struct context *c1, struct context *c2)
{
if (c1->hash && c2->hash && (c1->hash != c2->hash))
return 0;
if (c1->len && c2->len)
return (c1->len == c2->len && !strcmp(c1->str, c2->str));
if (c1->len || c2->len)
......@@ -192,5 +196,10 @@ static inline int context_cmp(struct context *c1, struct context *c2)
mls_context_cmp(c1, c2));
}
static inline unsigned int context_compute_hash(const char *s)
{
return full_name_hash(NULL, s, strlen(s));
}
#endif /* _SS_CONTEXT_H_ */
......@@ -878,6 +878,11 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
sidtab_destroy(s);
goto out;
}
rc = context_add_hash(p, &c->context[0]);
if (rc) {
sidtab_destroy(s);
goto out;
}
rc = sidtab_set_initial(s, c->sid[0], &c->context[0]);
if (rc) {
......@@ -2654,7 +2659,7 @@ static int role_trans_write(struct policydb *p, void *fp)
{
struct role_trans *r = p->role_tr;
struct role_trans *tr;
u32 buf[3];
__le32 buf[3];
size_t nel;
int rc;
......@@ -2686,7 +2691,7 @@ static int role_trans_write(struct policydb *p, void *fp)
static int role_allow_write(struct role_allow *r, void *fp)
{
struct role_allow *ra;
u32 buf[2];
__le32 buf[2];
size_t nel;
int rc;
......
......@@ -307,7 +307,7 @@ struct policydb {
u16 process_class;
u32 process_trans_perms;
};
} __randomize_layout;
extern void policydb_destroy(struct policydb *p);
extern int policydb_load_isids(struct policydb *p, struct sidtab *s);
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
#define _SS_SERVICES_H_
#include "policydb.h"
#include "sidtab.h"
#include "context.h"
/* Mapping for a single class */
struct selinux_mapping {
......@@ -31,7 +31,7 @@ struct selinux_ss {
struct selinux_map map;
struct page *status_page;
struct mutex status_lock;
};
} __randomize_layout;
void services_compute_xperms_drivers(struct extended_perms *xperms,
struct avtab_node *node);
......@@ -39,4 +39,6 @@ void services_compute_xperms_drivers(struct extended_perms *xperms,
void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
struct avtab_node *node);
int context_add_hash(struct policydb *policydb, struct context *context);
#endif /* _SS_SERVICES_H_ */
This diff is collapsed.
......@@ -13,16 +13,19 @@
#include <linux/spinlock_types.h>
#include <linux/log2.h>
#include <linux/hashtable.h>
#include "context.h"
struct sidtab_entry_leaf {
struct sidtab_entry {
u32 sid;
struct context context;
#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
struct sidtab_str_cache __rcu *cache;
#endif
struct hlist_node list;
};
struct sidtab_node_inner;
struct sidtab_node_leaf;
union sidtab_entry_inner {
struct sidtab_node_inner *ptr_inner;
struct sidtab_node_leaf *ptr_leaf;
......@@ -38,7 +41,7 @@ union sidtab_entry_inner {
(SIDTAB_NODE_ALLOC_SHIFT - size_to_shift(sizeof(union sidtab_entry_inner)))
#define SIDTAB_INNER_ENTRIES ((size_t)1 << SIDTAB_INNER_SHIFT)
#define SIDTAB_LEAF_ENTRIES \
(SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry_leaf))
(SIDTAB_NODE_ALLOC_SIZE / sizeof(struct sidtab_entry))
#define SIDTAB_MAX_BITS 32
#define SIDTAB_MAX U32_MAX
......@@ -48,7 +51,7 @@ union sidtab_entry_inner {
SIDTAB_INNER_SHIFT)
struct sidtab_node_leaf {
struct sidtab_entry_leaf entries[SIDTAB_LEAF_ENTRIES];
struct sidtab_entry entries[SIDTAB_LEAF_ENTRIES];
};
struct sidtab_node_inner {
......@@ -57,7 +60,7 @@ struct sidtab_node_inner {
struct sidtab_isid_entry {
int set;
struct context context;
struct sidtab_entry entry;
};
struct sidtab_convert_params {
......@@ -66,7 +69,8 @@ struct sidtab_convert_params {
struct sidtab *target;
};
#define SIDTAB_RCACHE_SIZE 3
#define SIDTAB_HASH_BITS CONFIG_SECURITY_SELINUX_SIDTAB_HASH_BITS
#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
struct sidtab {
/*
......@@ -83,17 +87,38 @@ struct sidtab {
struct sidtab_convert_params *convert;
spinlock_t lock;
/* reverse lookup cache - access atomically via {READ|WRITE}_ONCE() */
u32 rcache[SIDTAB_RCACHE_SIZE];
#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
/* SID -> context string cache */
u32 cache_free_slots;
struct list_head cache_lru_list;
spinlock_t cache_lock;
#endif
/* index == SID - 1 (no entry for SECSID_NULL) */
struct sidtab_isid_entry isids[SECINITSID_NUM];
/* Hash table for fast reverse context-to-sid lookups. */
DECLARE_HASHTABLE(context_to_sid, SIDTAB_HASH_BITS);
};
int sidtab_init(struct sidtab *s);
int sidtab_set_initial(struct sidtab *s, u32 sid, struct context *context);
struct context *sidtab_search(struct sidtab *s, u32 sid);
struct context *sidtab_search_force(struct sidtab *s, u32 sid);
struct sidtab_entry *sidtab_search_entry(struct sidtab *s, u32 sid);
struct sidtab_entry *sidtab_search_entry_force(struct sidtab *s, u32 sid);
static inline struct context *sidtab_search(struct sidtab *s, u32 sid)
{
struct sidtab_entry *entry = sidtab_search_entry(s, sid);
return entry ? &entry->context : NULL;
}
static inline struct context *sidtab_search_force(struct sidtab *s, u32 sid)
{
struct sidtab_entry *entry = sidtab_search_entry_force(s, sid);
return entry ? &entry->context : NULL;
}
int sidtab_convert(struct sidtab *s, struct sidtab_convert_params *params);
......@@ -101,6 +126,27 @@ int sidtab_context_to_sid(struct sidtab *s, struct context *context, u32 *sid);
void sidtab_destroy(struct sidtab *s);
int sidtab_hash_stats(struct sidtab *sidtab, char *page);
#if CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0
void sidtab_sid2str_put(struct sidtab *s, struct sidtab_entry *entry,
const char *str, u32 str_len);
int sidtab_sid2str_get(struct sidtab *s, struct sidtab_entry *entry,
char **out, u32 *out_len);
#else
static inline void sidtab_sid2str_put(struct sidtab *s,
struct sidtab_entry *entry,
const char *str, u32 str_len)
{
}
static inline int sidtab_sid2str_get(struct sidtab *s,
struct sidtab_entry *entry,
char **out, u32 *out_len)
{
return -ENOENT;
}
#endif /* CONFIG_SECURITY_SELINUX_SID2STR_CACHE_SIZE > 0 */
#endif /* _SS_SIDTAB_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment