Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

security,lockdown,selinux: implement SELinux lockdown

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>

authored by

Stephen Smalley and committed by
Paul Moore
59438b46 d97bd23c

+74 -27
+2
include/linux/lsm_audit.h
··· 74 74 #define LSM_AUDIT_DATA_FILE 12 75 75 #define LSM_AUDIT_DATA_IBPKEY 13 76 76 #define LSM_AUDIT_DATA_IBENDPORT 14 77 + #define LSM_AUDIT_DATA_LOCKDOWN 15 77 78 union { 78 79 struct path path; 79 80 struct dentry *dentry; ··· 94 93 struct file *file; 95 94 struct lsm_ibpkey_audit *ibpkey; 96 95 struct lsm_ibendport_audit *ibendport; 96 + int reason; 97 97 } u; 98 98 /* this union contains LSM specific data */ 99 99 union {
+2
include/linux/security.h
··· 128 128 LOCKDOWN_CONFIDENTIALITY_MAX, 129 129 }; 130 130 131 + extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1]; 132 + 131 133 /* These functions are in security/commoncap.c */ 132 134 extern int cap_capable(const struct cred *cred, struct user_namespace *ns, 133 135 int cap, unsigned int opts);
-27
security/lockdown/lockdown.c
··· 16 16 17 17 static enum lockdown_reason kernel_locked_down; 18 18 19 - static const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { 20 - [LOCKDOWN_NONE] = "none", 21 - [LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading", 22 - [LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port", 23 - [LOCKDOWN_EFI_TEST] = "/dev/efi_test access", 24 - [LOCKDOWN_KEXEC] = "kexec of unsigned images", 25 - [LOCKDOWN_HIBERNATION] = "hibernation", 26 - [LOCKDOWN_PCI_ACCESS] = "direct PCI access", 27 - [LOCKDOWN_IOPORT] = "raw io port access", 28 - [LOCKDOWN_MSR] = "raw MSR access", 29 - [LOCKDOWN_ACPI_TABLES] = "modifying ACPI tables", 30 - [LOCKDOWN_PCMCIA_CIS] = "direct PCMCIA CIS storage", 31 - [LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO", 32 - [LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters", 33 - [LOCKDOWN_MMIOTRACE] = "unsafe mmio", 34 - [LOCKDOWN_DEBUGFS] = "debugfs access", 35 - [LOCKDOWN_XMON_WR] = "xmon write access", 36 - [LOCKDOWN_INTEGRITY_MAX] = "integrity", 37 - [LOCKDOWN_KCORE] = "/proc/kcore access", 38 - [LOCKDOWN_KPROBES] = "use of kprobes", 39 - [LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM", 40 - [LOCKDOWN_PERF] = "unsafe use of perf", 41 - [LOCKDOWN_TRACEFS] = "use of tracefs", 42 - [LOCKDOWN_XMON_RW] = "xmon read and write access", 43 - [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality", 44 - }; 45 - 46 19 static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE, 47 20 LOCKDOWN_INTEGRITY_MAX, 48 21 LOCKDOWN_CONFIDENTIALITY_MAX};
+5
security/lsm_audit.c
··· 27 27 #include <linux/dccp.h> 28 28 #include <linux/sctp.h> 29 29 #include <linux/lsm_audit.h> 30 + #include <linux/security.h> 30 31 31 32 /** 32 33 * ipv4_skb_to_auditdata : fill auditdata from skb ··· 425 424 audit_log_format(ab, " device=%s port_num=%u", 426 425 a->u.ibendport->dev_name, 427 426 a->u.ibendport->port); 427 + break; 428 + case LSM_AUDIT_DATA_LOCKDOWN: 429 + audit_log_format(ab, " lockdown_reason="); 430 + audit_log_string(ab, lockdown_reasons[a->u.reason]); 428 431 break; 429 432 } /* switch (a->type) */ 430 433 }
+33
security/security.c
··· 35 35 #define LSM_COUNT (__end_lsm_info - __start_lsm_info) 36 36 #define EARLY_LSM_COUNT (__end_early_lsm_info - __start_early_lsm_info) 37 37 38 + /* 39 + * These are descriptions of the reasons that can be passed to the 40 + * security_locked_down() LSM hook. Placing this array here allows 41 + * all security modules to use the same descriptions for auditing 42 + * purposes. 43 + */ 44 + const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { 45 + [LOCKDOWN_NONE] = "none", 46 + [LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading", 47 + [LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port", 48 + [LOCKDOWN_EFI_TEST] = "/dev/efi_test access", 49 + [LOCKDOWN_KEXEC] = "kexec of unsigned images", 50 + [LOCKDOWN_HIBERNATION] = "hibernation", 51 + [LOCKDOWN_PCI_ACCESS] = "direct PCI access", 52 + [LOCKDOWN_IOPORT] = "raw io port access", 53 + [LOCKDOWN_MSR] = "raw MSR access", 54 + [LOCKDOWN_ACPI_TABLES] = "modifying ACPI tables", 55 + [LOCKDOWN_PCMCIA_CIS] = "direct PCMCIA CIS storage", 56 + [LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO", 57 + [LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters", 58 + [LOCKDOWN_MMIOTRACE] = "unsafe mmio", 59 + [LOCKDOWN_DEBUGFS] = "debugfs access", 60 + [LOCKDOWN_XMON_WR] = "xmon write access", 61 + [LOCKDOWN_INTEGRITY_MAX] = "integrity", 62 + [LOCKDOWN_KCORE] = "/proc/kcore access", 63 + [LOCKDOWN_KPROBES] = "use of kprobes", 64 + [LOCKDOWN_BPF_READ] = "use of bpf to read kernel RAM", 65 + [LOCKDOWN_PERF] = "unsafe use of perf", 66 + [LOCKDOWN_TRACEFS] = "use of tracefs", 67 + [LOCKDOWN_XMON_RW] = "xmon read and write access", 68 + [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality", 69 + }; 70 + 38 71 struct security_hook_heads security_hook_heads __lsm_ro_after_init; 39 72 static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); 40 73
+30
security/selinux/hooks.c
··· 6795 6795 } 6796 6796 #endif 6797 6797 6798 + static int selinux_lockdown(enum lockdown_reason what) 6799 + { 6800 + struct common_audit_data ad; 6801 + u32 sid = current_sid(); 6802 + int invalid_reason = (what <= LOCKDOWN_NONE) || 6803 + (what == LOCKDOWN_INTEGRITY_MAX) || 6804 + (what >= LOCKDOWN_CONFIDENTIALITY_MAX); 6805 + 6806 + if (WARN(invalid_reason, "Invalid lockdown reason")) { 6807 + audit_log(audit_context(), 6808 + GFP_ATOMIC, AUDIT_SELINUX_ERR, 6809 + "lockdown_reason=invalid"); 6810 + return -EINVAL; 6811 + } 6812 + 6813 + ad.type = LSM_AUDIT_DATA_LOCKDOWN; 6814 + ad.u.reason = what; 6815 + 6816 + if (what <= LOCKDOWN_INTEGRITY_MAX) 6817 + return avc_has_perm(&selinux_state, 6818 + sid, sid, SECCLASS_LOCKDOWN, 6819 + LOCKDOWN__INTEGRITY, &ad); 6820 + else 6821 + return avc_has_perm(&selinux_state, 6822 + sid, sid, SECCLASS_LOCKDOWN, 6823 + LOCKDOWN__CONFIDENTIALITY, &ad); 6824 + } 6825 + 6798 6826 struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { 6799 6827 .lbs_cred = sizeof(struct task_security_struct), 6800 6828 .lbs_file = sizeof(struct file_security_struct), ··· 7135 7107 LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read), 7136 7108 LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write), 7137 7109 #endif 7110 + 7111 + LSM_HOOK_INIT(locked_down, selinux_lockdown), 7138 7112 }; 7139 7113 7140 7114 static __init int selinux_init(void)
+2
security/selinux/include/classmap.h
··· 246 246 { COMMON_SOCK_PERMS, NULL } }, 247 247 { "perf_event", 248 248 {"open", "cpu", "kernel", "tracepoint", "read", "write"} }, 249 + { "lockdown", 250 + { "integrity", "confidentiality", NULL } }, 249 251 { NULL } 250 252 }; 251 253