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>
This commit is contained in:
Stephen Smalley 2019-11-27 12:04:36 -05:00 committed by Paul Moore
parent d97bd23c2d
commit 59438b4647
7 changed files with 74 additions and 27 deletions

View File

@ -74,6 +74,7 @@ struct common_audit_data {
#define LSM_AUDIT_DATA_FILE 12 #define LSM_AUDIT_DATA_FILE 12
#define LSM_AUDIT_DATA_IBPKEY 13 #define LSM_AUDIT_DATA_IBPKEY 13
#define LSM_AUDIT_DATA_IBENDPORT 14 #define LSM_AUDIT_DATA_IBENDPORT 14
#define LSM_AUDIT_DATA_LOCKDOWN 15
union { union {
struct path path; struct path path;
struct dentry *dentry; struct dentry *dentry;
@ -93,6 +94,7 @@ struct common_audit_data {
struct file *file; struct file *file;
struct lsm_ibpkey_audit *ibpkey; struct lsm_ibpkey_audit *ibpkey;
struct lsm_ibendport_audit *ibendport; struct lsm_ibendport_audit *ibendport;
int reason;
} u; } u;
/* this union contains LSM specific data */ /* this union contains LSM specific data */
union { union {

View File

@ -128,6 +128,8 @@ enum lockdown_reason {
LOCKDOWN_CONFIDENTIALITY_MAX, LOCKDOWN_CONFIDENTIALITY_MAX,
}; };
extern const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1];
/* These functions are in security/commoncap.c */ /* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns, extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
int cap, unsigned int opts); int cap, unsigned int opts);

View File

@ -16,33 +16,6 @@
static enum lockdown_reason kernel_locked_down; 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, static const enum lockdown_reason lockdown_levels[] = {LOCKDOWN_NONE,
LOCKDOWN_INTEGRITY_MAX, LOCKDOWN_INTEGRITY_MAX,
LOCKDOWN_CONFIDENTIALITY_MAX}; LOCKDOWN_CONFIDENTIALITY_MAX};

View File

@ -27,6 +27,7 @@
#include <linux/dccp.h> #include <linux/dccp.h>
#include <linux/sctp.h> #include <linux/sctp.h>
#include <linux/lsm_audit.h> #include <linux/lsm_audit.h>
#include <linux/security.h>
/** /**
* ipv4_skb_to_auditdata : fill auditdata from skb * 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->dev_name,
a->u.ibendport->port); a->u.ibendport->port);
break; 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) */ } /* switch (a->type) */
} }

View File

@ -35,6 +35,39 @@
#define LSM_COUNT (__end_lsm_info - __start_lsm_info) #define LSM_COUNT (__end_lsm_info - __start_lsm_info)
#define EARLY_LSM_COUNT (__end_early_lsm_info - __start_early_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; struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain);

View File

@ -6795,6 +6795,34 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
} }
#endif #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 = { struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
.lbs_cred = sizeof(struct task_security_struct), .lbs_cred = sizeof(struct task_security_struct),
.lbs_file = sizeof(struct file_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_read, selinux_perf_event_read),
LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write), LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write),
#endif #endif
LSM_HOOK_INIT(locked_down, selinux_lockdown),
}; };
static __init int selinux_init(void) static __init int selinux_init(void)

View File

@ -246,6 +246,8 @@ struct security_class_mapping secclass_map[] = {
{ COMMON_SOCK_PERMS, NULL } }, { COMMON_SOCK_PERMS, NULL } },
{ "perf_event", { "perf_event",
{"open", "cpu", "kernel", "tracepoint", "read", "write"} }, {"open", "cpu", "kernel", "tracepoint", "read", "write"} },
{ "lockdown",
{ "integrity", "confidentiality", NULL } },
{ NULL } { NULL }
}; };