]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
security,lockdown,selinux: implement SELinux lockdown
authorStephen Smalley <sds@tycho.nsa.gov>
Wed, 27 Nov 2019 17:04:36 +0000 (12:04 -0500)
committerPaul Moore <paul@paul-moore.com>
Mon, 9 Dec 2019 22:53:58 +0000 (17:53 -0500)
Implement a SELinux hook for lockdown.  If the lockdown module is also
enabled, then a denial by the lockdown module will take precedence over
SELinux, so SELinux can only further restrict lockdown decisions.
The SELinux hook only distinguishes at the granularity of integrity
versus confidentiality similar to the lockdown module, but includes the
full lockdown reason as part of the audit record as a hint in diagnosing
what triggered the denial.  To support this auditing, move the
lockdown_reasons[] string array from being private to the lockdown
module to the security framework so that it can be used by the lsm audit
code and so that it is always available even when the lockdown module
is disabled.

Note that the SELinux implementation allows the integrity and
confidentiality reasons to be controlled independently from one another.
Thus, in an SELinux policy, one could allow operations that specify
an integrity reason while blocking operations that specify a
confidentiality reason. The SELinux hook implementation is
stricter than the lockdown module in validating the provided reason value.

Sample AVC audit output from denials:
avc:  denied  { integrity } for pid=3402 comm="fwupd"
 lockdown_reason="/dev/mem,kmem,port" scontext=system_u:system_r:fwupd_t:s0
 tcontext=system_u:system_r:fwupd_t:s0 tclass=lockdown permissive=0

avc:  denied  { confidentiality } for pid=4628 comm="cp"
 lockdown_reason="/proc/kcore access"
 scontext=unconfined_u:unconfined_r:test_lockdown_integrity_t:s0-s0:c0.c1023
 tcontext=unconfined_u:unconfined_r:test_lockdown_integrity_t:s0-s0:c0.c1023
 tclass=lockdown permissive=0

Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Reviewed-by: James Morris <jamorris@linux.microsoft.com>
[PM: some merge fuzz do the the perf hooks]
Signed-off-by: Paul Moore <paul@paul-moore.com>
include/linux/lsm_audit.h
include/linux/security.h
security/lockdown/lockdown.c
security/lsm_audit.c
security/security.c
security/selinux/hooks.c
security/selinux/include/classmap.h

index 915330abf6e58fc2ecf494c498b7d266b0d56448..99d629fd994457589410ee08344f83b2c69cfdda 100644 (file)
@@ -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 {
index 3e8d4bacd59de1d338e4b5f33ee47d502ddd7409..64b19f050343eef7b74b23c0626fde7a141cb8f6 100644 (file)
@@ -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);
index b2f87015d6e900ca2bc2593262b2c4904daf4721..5a952617a0eba388a99345206de469b666770122 100644 (file)
 
 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};
index e40874373f2b4a72b30648bb58a09f82fbd58a52..2d2bf49016f4f98a6135693131028d32b4f523e7 100644 (file)
@@ -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) */
 }
 
index cd2d18d2d279c87ae0b44454c410a3995166d999..2b5473d924160b76a73ef5dc4111caab58370b45 100644 (file)
 #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);
 
index 116b4d644f68935a82083cdbdd232c5243d203cc..9e1c4780dc20403199c167dd4b3c40fff0f6ad6d 100644 (file)
@@ -6795,6 +6795,34 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
 }
 #endif
 
+static int selinux_lockdown(enum lockdown_reason what)
+{
+       struct common_audit_data ad;
+       u32 sid = current_sid();
+       int invalid_reason = (what <= LOCKDOWN_NONE) ||
+                            (what == LOCKDOWN_INTEGRITY_MAX) ||
+                            (what >= LOCKDOWN_CONFIDENTIALITY_MAX);
+
+       if (WARN(invalid_reason, "Invalid lockdown reason")) {
+               audit_log(audit_context(),
+                         GFP_ATOMIC, AUDIT_SELINUX_ERR,
+                         "lockdown_reason=invalid");
+               return -EINVAL;
+       }
+
+       ad.type = LSM_AUDIT_DATA_LOCKDOWN;
+       ad.u.reason = what;
+
+       if (what <= LOCKDOWN_INTEGRITY_MAX)
+               return avc_has_perm(&selinux_state,
+                                   sid, sid, SECCLASS_LOCKDOWN,
+                                   LOCKDOWN__INTEGRITY, &ad);
+       else
+               return avc_has_perm(&selinux_state,
+                                   sid, sid, SECCLASS_LOCKDOWN,
+                                   LOCKDOWN__CONFIDENTIALITY, &ad);
+}
+
 struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
        .lbs_cred = sizeof(struct task_security_struct),
        .lbs_file = sizeof(struct file_security_struct),
@@ -7107,6 +7135,8 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read),
        LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write),
 #endif
+
+       LSM_HOOK_INIT(locked_down, selinux_lockdown),
 };
 
 static __init int selinux_init(void)
index 7db24855e12d4c19c1162e6ad04b254f92bd036e..986f3ac14282f8a760b5346c7661524fa14209af 100644 (file)
@@ -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 }
   };