@@ -17,10 +17,16 @@ MAC extensions, other extensions can be built using the LSM to provide
specific changes to system operation when these tweaks are not available
in the core functionality of Linux itself.
-The Linux capabilities modules will always be included. This may be
-followed by any number of "minor" modules and at most one "major" module.
-For more details on capabilities, see ``capabilities(7)`` in the Linux
-man-pages project.
+The Linux capabilities modules will always be included. For more details
+on capabilities, see ``capabilities(7)`` in the Linux man-pages project.
+
+Security modules that do not use the security data blobs maintained
+by the LSM infrastructure are considered "minor" modules. These may be
+included at compile time and stacked explicitly. Security modules that
+use the LSM maintained security blobs are considered "major" modules.
+These may only be stacked if the CONFIG_LSM_STACKED configuration
+option is used. If this is chosen all of the security modules selected
+will be used.
A list of the active security modules can be found by reading
``/sys/kernel/security/lsm``. This is a comma separated list, and
@@ -2072,7 +2072,7 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
#define __lsm_ro_after_init __ro_after_init
#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
-extern int __init security_module_enable(const char *module);
+extern bool __init security_module_enable(const char *lsm, const bool stacked);
extern void __init capability_add_hooks(void);
#ifdef CONFIG_SECURITY_YAMA
extern void __init yama_add_hooks(void);
@@ -36,6 +36,28 @@ config SECURITY_WRITABLE_HOOKS
bool
default n
+config SECURITY_STACKING
+ bool "Security module stacking"
+ depends on SECURITY
+ help
+ Allows multiple major security modules to be stacked.
+ Modules are invoked in the order registered with a
+ "bail on fail" policy, in which the infrastructure
+ will stop processing once a denial is detected. Not
+ all modules can be stacked. SELinux and Smack are
+ known to be incompatible. User space components may
+ have trouble identifying the security module providing
+ data in some cases.
+
+ If you select this option you will have to select which
+ of the stackable modules you wish to be active. The
+ "Default security module" will be ignored. The boot line
+ "security=" option can be used to specify that one of
+ the modules identifed for stacking should be used instead
+ of the entire stack.
+
+ If you are unsure how to answer this question, answer N.
+
config SECURITY_LSM_DEBUG
bool "Enable debugging of the LSM infrastructure"
depends on SECURITY
@@ -251,6 +273,9 @@ source security/yama/Kconfig
source security/integrity/Kconfig
+menu "Security Module Selection"
+ visible if !SECURITY_STACKING
+
choice
prompt "Default security module"
default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
@@ -290,3 +315,64 @@ config DEFAULT_SECURITY
endmenu
+menu "Security Module Stack"
+ visible if SECURITY_STACKING
+
+choice
+ prompt "Stacked 'extreme' security module"
+ default SECURITY_SELINUX_STACKED if SECURITY_SELINUX
+ default SECURITY_SMACK_STACKED if SECURITY_SMACK
+ default SECURITY_APPARMOR_STACKED if SECURITY_APPARMOR
+
+ help
+ Enable an extreme security module. These modules cannot
+ be used at the same time.
+
+ config SECURITY_SELINUX_STACKED
+ bool "SELinux" if SECURITY_SELINUX=y
+ help
+ This option instructs the system to use the SELinux checks.
+ At this time the Smack security module is incompatible with this
+ module.
+ At this time the AppArmor security module is incompatible with this
+ module.
+
+ config SECURITY_SMACK_STACKED
+ bool "Simplified Mandatory Access Control" if SECURITY_SMACK=y
+ help
+ This option instructs the system to use the Smack checks.
+ At this time the SELinux security module is incompatible with this
+ module.
+ At this time the AppArmor security module is incompatible with this
+ module.
+
+ config SECURITY_APPARMOR_STACKED
+ bool "AppArmor" if SECURITY_APPARMOR=y
+ help
+ This option instructs the system to use the AppArmor checks.
+ At this time the SELinux security module is incompatible with this
+ module.
+ At this time the Smack security module is incompatible with this
+ module.
+
+ config SECURITY_NOTHING_STACKED
+ bool "Use no 'extreme' security module"
+ help
+ Use none of the SELinux, Smack or AppArmor security module.
+
+endchoice
+
+config SECURITY_TOMOYO_STACKED
+ bool "TOMOYO support is enabled by default"
+ depends on SECURITY_TOMOYO && SECURITY_STACKING
+ default n
+ help
+ This option instructs the system to use the TOMOYO checks.
+ If not selected the module will not be invoked.
+ Stacked security modules may interact in unexpected ways.
+
+ If you are unsure how to answer this question, answer N.
+
+endmenu
+
+endmenu
@@ -25,7 +25,11 @@
static inline struct aa_label *cred_label(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+#else
struct aa_label **blob = cred->security;
+#endif
AA_BUG(!blob);
return *blob;
@@ -34,7 +38,11 @@ static inline struct aa_label *cred_label(const struct cred *cred)
static inline void set_cred_label(const struct cred *cred,
struct aa_label *label)
{
+#ifdef CONFIG_SECURITY_STACKING
+ struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+#else
struct aa_label **blob = cred->security;
+#endif
AA_BUG(!blob);
*blob = label;
@@ -32,7 +32,14 @@ struct path;
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
AA_EXEC_MMAP | AA_MAY_LINK)
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+static inline struct aa_file_ctx *file_ctx(struct file *file)
+{
+#ifdef CONFIG_SECURITY_STACKING
+ return file->f_security + apparmor_blob_sizes.lbs_file;
+#else
+ return file->f_security;
+#endif
+}
/* struct aa_file_ctx - the AppArmor context the file was opened in
* @lock: lock to update the ctx
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
+#include <linux/lsm_hooks.h>
#include "match.h"
@@ -55,6 +56,9 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
size_t *ns_len);
void aa_info_message(const char *str);
+/* Security blob offsets */
+extern struct lsm_blob_sizes apparmor_blob_sizes;
+
/**
* aa_strneq - compare null terminated @str to a non null terminated substring
* @str: a null terminated string
@@ -16,7 +16,11 @@
static inline struct aa_task_ctx *task_ctx(struct task_struct *task)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return task->security + apparmor_blob_sizes.lbs_task;
+#else
return task->security;
+#endif
}
/*
@@ -1508,7 +1508,9 @@ static int __init apparmor_init(void)
int error;
if (!finish) {
- if (apparmor_enabled && security_module_enable("apparmor"))
+ if (apparmor_enabled &&
+ security_module_enable("apparmor",
+ IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED)))
security_add_blobs(&apparmor_blob_sizes);
else
apparmor_enabled = false;
@@ -1516,7 +1518,9 @@ static int __init apparmor_init(void)
return 0;
}
- if (!apparmor_enabled || !security_module_enable("apparmor")) {
+ if (!apparmor_enabled ||
+ !security_module_enable("apparmor",
+ IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED))) {
aa_info_message("AppArmor disabled by boot time parameter");
apparmor_enabled = false;
return 0;
@@ -38,6 +38,7 @@
/* Maximum number of letters for an LSM name string */
#define SECURITY_NAME_MAX 10
+#define MODULE_STACK "(stacking)"
struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
@@ -50,7 +51,11 @@ static struct lsm_blob_sizes blob_sizes;
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
+#ifdef CONFIG_SECURITY_STACKING
+ MODULE_STACK;
+#else
CONFIG_DEFAULT_SECURITY;
+#endif
static void __init do_security_initcalls(void)
{
@@ -174,6 +179,7 @@ static int lsm_append(char *new, char **result)
/**
* security_module_enable - Load given security module on boot ?
* @module: the name of the module
+ * @stacked: indicates that the module wants to be stacked
*
* Each LSM must pass this method before registering its own operations
* to avoid security registration races. This method may also be used
@@ -189,9 +195,29 @@ static int lsm_append(char *new, char **result)
*
* Otherwise, return false.
*/
-int __init security_module_enable(const char *module)
+bool __init security_module_enable(const char *lsm, const bool stacked)
{
- return !strcmp(module, chosen_lsm);
+#ifdef CONFIG_SECURITY_STACKING
+ /*
+ * Module defined on the command line security=XXXX
+ */
+ if (strcmp(chosen_lsm, MODULE_STACK)) {
+ if (!strcmp(lsm, chosen_lsm)) {
+ pr_info("Command line sets the %s security module.\n",
+ lsm);
+ return true;
+ }
+ return false;
+ }
+ /*
+ * Module configured as stacked.
+ */
+ return stacked;
+#else
+ if (strcmp(lsm, chosen_lsm) == 0)
+ return true;
+ return false;
+#endif
}
/**
@@ -6906,7 +6906,8 @@ static __init int selinux_init(void)
{
static int finish;
- if (!security_module_enable("selinux")) {
+ if (!security_module_enable("selinux",
+ IS_ENABLED(CONFIG_SECURITY_SELINUX_STACKED))) {
selinux_enabled = 0;
return 0;
}
@@ -161,47 +161,80 @@ struct bpf_security_struct {
extern struct lsm_blob_sizes selinux_blob_sizes;
static inline struct task_security_struct *selinux_cred(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return cred->security + selinux_blob_sizes.lbs_cred;
+#else
return cred->security;
+#endif
}
static inline struct file_security_struct *selinux_file(const struct file *file)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return file->f_security + selinux_blob_sizes.lbs_file;
+#else
return file->f_security;
+#endif
}
-static inline struct inode_security_struct *selinux_inode(const struct inode *inode)
+static inline struct inode_security_struct *selinux_inode(
+ const struct inode *inode)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return inode->i_security + selinux_blob_sizes.lbs_inode;
+#else
return inode->i_security;
+#endif
}
static inline struct superblock_security_struct *selinux_superblock(
const struct super_block *superblock)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return superblock->s_security + selinux_blob_sizes.lbs_superblock;
+#else
return superblock->s_security;
+#endif
}
static inline struct msg_security_struct *selinux_msg_msg(
const struct msg_msg *msg_msg)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return msg_msg->security + selinux_blob_sizes.lbs_msg_msg;
+#else
return msg_msg->security;
+#endif
}
static inline struct ipc_security_struct *selinux_ipc(
const struct kern_ipc_perm *ipc)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return ipc->security + selinux_blob_sizes.lbs_ipc;
+#else
return ipc->security;
+#endif
}
#ifdef CONFIG_KEYS
static inline struct key_security_struct *selinux_key(const struct key *key)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return key->security + selinux_blob_sizes.lbs_key;
+#else
return key->security;
+#endif
}
#endif /* CONFIG_KEYS */
static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return sock->sk_security + selinux_blob_sizes.lbs_sock;
+#else
return sock->sk_security;
+#endif
}
#endif /* _SELINUX_OBJSEC_H_ */
@@ -337,6 +337,7 @@ extern struct smack_known *smack_syslog_label;
extern struct smack_known *smack_unconfined;
#endif
extern int smack_ptrace_rule;
+extern struct lsm_blob_sizes smack_blob_sizes;
extern struct smack_known smack_known_floor;
extern struct smack_known smack_known_hat;
@@ -359,44 +360,76 @@ extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
static inline struct task_smack *smack_cred(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return cred->security + smack_blob_sizes.lbs_cred;
+#else
return cred->security;
+#endif
}
static inline struct smack_known **smack_file(const struct file *file)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return file->f_security + smack_blob_sizes.lbs_file;
+#else
return file->f_security;
+#endif
}
static inline struct inode_smack *smack_inode(const struct inode *inode)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return inode->i_security + smack_blob_sizes.lbs_inode;
+#else
return inode->i_security;
+#endif
}
static inline struct socket_smack *smack_sock(const struct sock *sock)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return sock->sk_security + smack_blob_sizes.lbs_sock;
+#else
return sock->sk_security;
+#endif
}
static inline struct superblock_smack *smack_superblock(
const struct super_block *superblock)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return superblock->s_security + smack_blob_sizes.lbs_superblock;
+#else
return superblock->s_security;
+#endif
}
static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return msg->security + smack_blob_sizes.lbs_msg_msg;
+#else
return msg->security;
+#endif
}
static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return ipc->security + smack_blob_sizes.lbs_ipc;
+#else
return ipc->security;
+#endif
}
#ifdef CONFIG_KEYS
static inline struct smack_known **smack_key(const struct key *key)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return key->security + smack_blob_sizes.lbs_key;
+#else
return key->security;
+#endif
}
#endif /* CONFIG_KEYS */
@@ -3432,18 +3432,16 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
{
struct smack_known *skp = smk_of_task_struct(p);
char *cp;
- int slen;
- if (strcmp(name, "current") != 0)
+ if (strcmp(name, "current") == 0) {
+ cp = kstrdup(skp->smk_known, GFP_KERNEL);
+ if (cp == NULL)
+ return -ENOMEM;
+ } else
return -EINVAL;
- cp = kstrdup(skp->smk_known, GFP_KERNEL);
- if (cp == NULL)
- return -ENOMEM;
-
- slen = strlen(cp);
*value = cp;
- return slen;
+ return strlen(cp);
}
/**
@@ -4683,7 +4681,8 @@ static __init int smack_init(void)
struct cred *cred = (struct cred *) current->cred;
struct task_smack *tsp;
- if (!security_module_enable("smack"))
+ if (!security_module_enable("smack",
+ IS_ENABLED(CONFIG_SECURITY_SMACK_STACKED)))
return 0;
if (!finish) {
@@ -1087,6 +1087,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+extern struct lsm_blob_sizes tomoyo_blob_sizes;
/********** Inlined functions. **********/
@@ -1206,7 +1207,11 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
*/
static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return cred->security + tomoyo_blob_sizes.lbs_cred;
+#else
return cred->security;
+#endif
}
/**
@@ -1216,8 +1221,13 @@ static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
*/
static inline struct tomoyo_domain_info *tomoyo_domain(void)
{
- struct tomoyo_domain_info **blob = tomoyo_cred(current_cred());
+ const struct cred *cred = current_cred();
+ struct tomoyo_domain_info **blob;
+
+ if (cred->security == NULL)
+ return NULL;
+ blob = tomoyo_cred(cred);
return *blob;
}
@@ -564,7 +564,8 @@ static int __init tomoyo_init(void)
struct cred *cred = (struct cred *) current_cred();
struct tomoyo_domain_info **blob;
- if (!security_module_enable("tomoyo")) {
+ if (!security_module_enable("tomoyo",
+ IS_ENABLED(CONFIG_SECURITY_TOMOYO_STACKED))) {
tomoyo_enabled = false;
return 0;
}