summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-03-07 11:44:01 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-03-07 11:44:01 -0800
commitae5906ceee038ea29ff5162d1bcd18fb50af8b94 (patch)
tree841a11c6d3c3afcf7e4d57be370ebcf57aab214a /security
parent1fc1cd8399ab5541a488a7e47b2f21537dd76c2d (diff)
parent468e91cecb3218afd684b8c422490dfebe0691bb (diff)
Merge branch 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris: - Extend LSM stacking to allow sharing of cred, file, ipc, inode, and task blobs. This paves the way for more full-featured LSMs to be merged, and is specifically aimed at LandLock and SARA LSMs. This work is from Casey and Kees. - There's a new LSM from Micah Morton: "SafeSetID gates the setid family of syscalls to restrict UID/GID transitions from a given UID/GID to only those approved by a system-wide whitelist." This feature is currently shipping in ChromeOS. * 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (62 commits) keys: fix missing __user in KEYCTL_PKEY_QUERY LSM: Update list of SECURITYFS users in Kconfig LSM: Ignore "security=" when "lsm=" is specified LSM: Update function documentation for cap_capable security: mark expected switch fall-throughs and add a missing break tomoyo: Bump version. LSM: fix return value check in safesetid_init_securityfs() LSM: SafeSetID: add selftest LSM: SafeSetID: remove unused include LSM: SafeSetID: 'depend' on CONFIG_SECURITY LSM: Add 'name' field for SafeSetID in DEFINE_LSM LSM: add SafeSetID module that gates setid calls LSM: add SafeSetID module that gates setid calls tomoyo: Allow multiple use_group lines. tomoyo: Coding style fix. tomoyo: Swicth from cred->security to task_struct->security. security: keys: annotate implicit fall throughs security: keys: annotate implicit fall throughs security: keys: annotate implicit fall through capabilities:: annotate implicit fall through ...
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig45
-rw-r--r--security/Makefile2
-rw-r--r--security/apparmor/Kconfig16
-rw-r--r--security/apparmor/capability.c14
-rw-r--r--security/apparmor/domain.c4
-rw-r--r--security/apparmor/include/capability.h2
-rw-r--r--security/apparmor/include/cred.h16
-rw-r--r--security/apparmor/include/file.h5
-rw-r--r--security/apparmor/include/lib.h4
-rw-r--r--security/apparmor/include/task.h18
-rw-r--r--security/apparmor/ipc.c3
-rw-r--r--security/apparmor/lsm.c67
-rw-r--r--security/apparmor/resource.c2
-rw-r--r--security/apparmor/task.c6
-rw-r--r--security/commoncap.c28
-rw-r--r--security/integrity/ima/ima_appraise.c1
-rw-r--r--security/integrity/ima/ima_policy.c4
-rw-r--r--security/integrity/ima/ima_template_lib.c1
-rw-r--r--security/keys/keyctl.c2
-rw-r--r--security/keys/keyring.c1
-rw-r--r--security/keys/process_keys.c3
-rw-r--r--security/keys/request_key.c4
-rw-r--r--security/loadpin/loadpin.c8
-rw-r--r--security/safesetid/Kconfig14
-rw-r--r--security/safesetid/Makefile7
-rw-r--r--security/safesetid/lsm.c277
-rw-r--r--security/safesetid/lsm.h33
-rw-r--r--security/safesetid/securityfs.c193
-rw-r--r--security/security.c648
-rw-r--r--security/selinux/Kconfig15
-rw-r--r--security/selinux/Makefile2
-rw-r--r--security/selinux/exports.c23
-rw-r--r--security/selinux/hooks.c362
-rw-r--r--security/selinux/include/audit.h3
-rw-r--r--security/selinux/include/objsec.h38
-rw-r--r--security/selinux/selinuxfs.c4
-rw-r--r--security/selinux/ss/services.c1
-rw-r--r--security/selinux/xfrm.c4
-rw-r--r--security/smack/smack.h44
-rw-r--r--security/smack/smack_access.c6
-rw-r--r--security/smack/smack_lsm.c317
-rw-r--r--security/smack/smackfs.c18
-rw-r--r--security/tomoyo/audit.c31
-rw-r--r--security/tomoyo/common.c199
-rw-r--r--security/tomoyo/common.h51
-rw-r--r--security/tomoyo/condition.c59
-rw-r--r--security/tomoyo/domain.c76
-rw-r--r--security/tomoyo/file.c20
-rw-r--r--security/tomoyo/gc.c19
-rw-r--r--security/tomoyo/group.c5
-rw-r--r--security/tomoyo/load_policy.c8
-rw-r--r--security/tomoyo/memory.c9
-rw-r--r--security/tomoyo/mount.c2
-rw-r--r--security/tomoyo/realpath.c18
-rw-r--r--security/tomoyo/securityfs_if.c30
-rw-r--r--security/tomoyo/tomoyo.c160
-rw-r--r--security/tomoyo/util.c23
-rw-r--r--security/yama/yama_lsm.c8
58 files changed, 2018 insertions, 965 deletions
diff --git a/security/Kconfig b/security/Kconfig
index e4fe2f3c2c65..1d6463fb1450 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -40,8 +40,7 @@ config SECURITYFS
bool "Enable the securityfs filesystem"
help
This will build the securityfs filesystem. It is currently used by
- the TPM bios character driver and IMA, an integrity provider. It is
- not used by SELinux or SMACK.
+ various security modules (AppArmor, IMA, SafeSetID, TOMOYO, TPM).
If you are unsure how to answer this question, answer N.
@@ -236,45 +235,19 @@ source "security/tomoyo/Kconfig"
source "security/apparmor/Kconfig"
source "security/loadpin/Kconfig"
source "security/yama/Kconfig"
+source "security/safesetid/Kconfig"
source "security/integrity/Kconfig"
-choice
- prompt "Default security module"
- default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
- default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
- default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
- default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
- default DEFAULT_SECURITY_DAC
-
+config LSM
+ string "Ordered list of enabled LSMs"
+ default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
help
- Select the security module that will be used by default if the
- kernel parameter security= is not specified.
-
- config DEFAULT_SECURITY_SELINUX
- bool "SELinux" if SECURITY_SELINUX=y
-
- config DEFAULT_SECURITY_SMACK
- bool "Simplified Mandatory Access Control" if SECURITY_SMACK=y
-
- config DEFAULT_SECURITY_TOMOYO
- bool "TOMOYO" if SECURITY_TOMOYO=y
-
- config DEFAULT_SECURITY_APPARMOR
- bool "AppArmor" if SECURITY_APPARMOR=y
-
- config DEFAULT_SECURITY_DAC
- bool "Unix Discretionary Access Controls"
-
-endchoice
+ A comma-separated list of LSMs, in initialization order.
+ Any LSMs left off this list will be ignored. This can be
+ controlled at boot with the "lsm=" parameter.
-config DEFAULT_SECURITY
- string
- default "selinux" if DEFAULT_SECURITY_SELINUX
- default "smack" if DEFAULT_SECURITY_SMACK
- default "tomoyo" if DEFAULT_SECURITY_TOMOYO
- default "apparmor" if DEFAULT_SECURITY_APPARMOR
- default "" if DEFAULT_SECURITY_DAC
+ If unsure, leave this as the default.
endmenu
diff --git a/security/Makefile b/security/Makefile
index 4d2d3782ddef..c598b904938f 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo
subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor
subdir-$(CONFIG_SECURITY_YAMA) += yama
subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin
+subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid
# always enable default capabilities
obj-y += commoncap.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/
obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/
obj-$(CONFIG_SECURITY_YAMA) += yama/
obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/
+obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/
obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
# Object integrity file lists
diff --git a/security/apparmor/Kconfig b/security/apparmor/Kconfig
index b6b68a7750ce..3de21f46c82a 100644
--- a/security/apparmor/Kconfig
+++ b/security/apparmor/Kconfig
@@ -14,22 +14,6 @@ config SECURITY_APPARMOR
If you are unsure how to answer this question, answer N.
-config SECURITY_APPARMOR_BOOTPARAM_VALUE
- int "AppArmor boot parameter default value"
- depends on SECURITY_APPARMOR
- range 0 1
- default 1
- help
- This option sets the default value for the kernel parameter
- 'apparmor', which allows AppArmor to be enabled or disabled
- at boot. If this option is set to 0 (zero), the AppArmor
- kernel parameter will default to 0, disabling AppArmor at
- boot. If this option is set to 1 (one), the AppArmor
- kernel parameter will default to 1, enabling AppArmor at
- boot.
-
- If you are unsure how to answer this question, answer 1.
-
config SECURITY_APPARMOR_HASH
bool "Enable introspection of sha1 hashes for loaded profiles"
depends on SECURITY_APPARMOR
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c
index 253ef6e9d445..752f73980e30 100644
--- a/security/apparmor/capability.c
+++ b/security/apparmor/capability.c
@@ -110,13 +110,13 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
* profile_capable - test if profile allows use of capability @cap
* @profile: profile being enforced (NOT NULL, NOT unconfined)
* @cap: capability to test if allowed
- * @audit: whether an audit record should be generated
+ * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
* @sa: audit data (MAY BE NULL indicating no auditing)
*
* Returns: 0 if allowed else -EPERM
*/
-static int profile_capable(struct aa_profile *profile, int cap, int audit,
- struct common_audit_data *sa)
+static int profile_capable(struct aa_profile *profile, int cap,
+ unsigned int opts, struct common_audit_data *sa)
{
int error;
@@ -126,7 +126,7 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit,
else
error = -EPERM;
- if (audit == SECURITY_CAP_NOAUDIT) {
+ if (opts & CAP_OPT_NOAUDIT) {
if (!COMPLAIN_MODE(profile))
return error;
/* audit the cap request in complain mode but note that it
@@ -142,13 +142,13 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit,
* aa_capable - test permission to use capability
* @label: label being tested for capability (NOT NULL)
* @cap: capability to be tested
- * @audit: whether an audit record should be generated
+ * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
*
* Look up capability in profile capability set.
*
* Returns: 0 on success, or else an error code.
*/
-int aa_capable(struct aa_label *label, int cap, int audit)
+int aa_capable(struct aa_label *label, int cap, unsigned int opts)
{
struct aa_profile *profile;
int error = 0;
@@ -156,7 +156,7 @@ int aa_capable(struct aa_label *label, int cap, int audit)
sa.u.cap = cap;
error = fn_for_each_confined(label, profile,
- profile_capable(profile, cap, audit, &sa));
+ profile_capable(profile, cap, opts, &sa));
return error;
}
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 11975ec8d566..ca2dccf5b445 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -572,7 +572,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
stack = NULL;
break;
}
- /* fall through to X_NAME */
+ /* fall through - to X_NAME */
case AA_X_NAME:
if (xindex & AA_X_CHILD)
/* released by caller */
@@ -975,7 +975,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
}
aa_put_label(cred_label(bprm->cred));
/* transfer reference, released when cred is freed */
- cred_label(bprm->cred) = new;
+ set_cred_label(bprm->cred, new);
done:
aa_put_label(label);
diff --git a/security/apparmor/include/capability.h b/security/apparmor/include/capability.h
index e0304e2aeb7f..1b3663b6ab12 100644
--- a/security/apparmor/include/capability.h
+++ b/security/apparmor/include/capability.h
@@ -40,7 +40,7 @@ struct aa_caps {
extern struct aa_sfs_entry aa_sfs_entry_caps[];
-int aa_capable(struct aa_label *label, int cap, int audit);
+int aa_capable(struct aa_label *label, int cap, unsigned int opts);
static inline void aa_free_cap_rules(struct aa_caps *caps)
{
diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h
index 265ae6641a06..b9504a05fddc 100644
--- a/security/apparmor/include/cred.h
+++ b/security/apparmor/include/cred.h
@@ -23,8 +23,22 @@
#include "policy_ns.h"
#include "task.h"
-#define cred_label(X) ((X)->security)
+static inline struct aa_label *cred_label(const struct cred *cred)
+{
+ struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+
+ AA_BUG(!blob);
+ return *blob;
+}
+static inline void set_cred_label(const struct cred *cred,
+ struct aa_label *label)
+{
+ struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+
+ AA_BUG(!blob);
+ *blob = label;
+}
/**
* aa_cred_raw_label - obtain cred's label
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index 4c2c8ac8842f..8be09208cf7c 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -32,7 +32,10 @@ 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)
+{
+ return file->f_security + apparmor_blob_sizes.lbs_file;
+}
/* struct aa_file_ctx - the AppArmor context the file was opened in
* @lock: lock to update the ctx
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h
index 6505e1ad9e23..bbe9b384d71d 100644
--- a/security/apparmor/include/lib.h
+++ b/security/apparmor/include/lib.h
@@ -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
diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h
index 55edaa1d83f8..311e652324e3 100644
--- a/security/apparmor/include/task.h
+++ b/security/apparmor/include/task.h
@@ -14,7 +14,10 @@
#ifndef __AA_TASK_H
#define __AA_TASK_H
-#define task_ctx(X) ((X)->security)
+static inline struct aa_task_ctx *task_ctx(struct task_struct *task)
+{
+ return task->security + apparmor_blob_sizes.lbs_task;
+}
/*
* struct aa_task_ctx - information for current task label change
@@ -37,17 +40,6 @@ int aa_restore_previous_label(u64 cookie);
struct aa_label *aa_get_task_label(struct task_struct *task);
/**
- * aa_alloc_task_ctx - allocate a new task_ctx
- * @flags: gfp flags for allocation
- *
- * Returns: allocated buffer or NULL on failure
- */
-static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags)
-{
- return kzalloc(sizeof(struct aa_task_ctx), flags);
-}
-
-/**
* aa_free_task_ctx - free a task_ctx
* @ctx: task_ctx to free (MAYBE NULL)
*/
@@ -57,8 +49,6 @@ static inline void aa_free_task_ctx(struct aa_task_ctx *ctx)
aa_put_label(ctx->nnp);
aa_put_label(ctx->previous);
aa_put_label(ctx->onexec);
-
- kzfree(ctx);
}
}
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index 527ea1557120..aacd1e95cb59 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -107,7 +107,8 @@ static int profile_tracer_perm(struct aa_profile *tracer,
aad(sa)->label = &tracer->label;
aad(sa)->peer = tracee;
aad(sa)->request = 0;
- aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1);
+ aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
+ CAP_OPT_NONE);
return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
}
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 8db1731d046a..49d664ddff44 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -60,7 +60,7 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
static void apparmor_cred_free(struct cred *cred)
{
aa_put_label(cred_label(cred));
- cred_label(cred) = NULL;
+ set_cred_label(cred, NULL);
}
/*
@@ -68,7 +68,7 @@ static void apparmor_cred_free(struct cred *cred)
*/
static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
- cred_label(cred) = NULL;
+ set_cred_label(cred, NULL);
return 0;
}
@@ -78,7 +78,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
- cred_label(new) = aa_get_newest_label(cred_label(old));
+ set_cred_label(new, aa_get_newest_label(cred_label(old)));
return 0;
}
@@ -87,26 +87,21 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
*/
static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
{
- cred_label(new) = aa_get_newest_label(cred_label(old));
+ set_cred_label(new, aa_get_newest_label(cred_label(old)));
}
static void apparmor_task_free(struct task_struct *task)
{
aa_free_task_ctx(task_ctx(task));
- task_ctx(task) = NULL;
}
static int apparmor_task_alloc(struct task_struct *task,
unsigned long clone_flags)
{
- struct aa_task_ctx *new = aa_alloc_task_ctx(GFP_KERNEL);
-
- if (!new)
- return -ENOMEM;
+ struct aa_task_ctx *new = task_ctx(task);
aa_dup_task_ctx(new, task_ctx(current));
- task_ctx(task) = new;
return 0;
}
@@ -177,14 +172,14 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
}
static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
- int cap, int audit)
+ int cap, unsigned int opts)
{
struct aa_label *label;
int error = 0;
label = aa_get_newest_cred_label(cred);
if (!unconfined(label))
- error = aa_capable(label, cap, audit);
+ error = aa_capable(label, cap, opts);
aa_put_label(label);
return error;
@@ -434,21 +429,21 @@ static int apparmor_file_open(struct file *file)
static int apparmor_file_alloc_security(struct file *file)
{
- int error = 0;
-
- /* freed by apparmor_file_free_security */
+ struct aa_file_ctx *ctx = file_ctx(file);
struct aa_label *label = begin_current_label_crit_section();
- file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
- if (!file_ctx(file))
- error = -ENOMEM;
- end_current_label_crit_section(label);
- return error;
+ spin_lock_init(&ctx->lock);
+ rcu_assign_pointer(ctx->label, aa_get_label(label));
+ end_current_label_crit_section(label);
+ return 0;
}
static void apparmor_file_free_security(struct file *file)
{
- aa_free_file_ctx(file_ctx(file));
+ struct aa_file_ctx *ctx = file_ctx(file);
+
+ if (ctx)
+ aa_put_label(rcu_access_pointer(ctx->label));
}
static int common_file_perm(const char *op, struct file *file, u32 mask)
@@ -1151,6 +1146,15 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
}
#endif
+/*
+ * The cred blob is a pointer to, not an instance of, an aa_task_ctx.
+ */
+struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
+ .lbs_cred = sizeof(struct aa_task_ctx *),
+ .lbs_file = sizeof(struct aa_file_ctx),
+ .lbs_task = sizeof(struct aa_task_ctx),
+};
+
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -1333,8 +1337,8 @@ bool aa_g_paranoid_load = true;
module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
/* Boot time disable flag */
-static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
-module_param_named(enabled, apparmor_enabled, bool, S_IRUGO);
+static int apparmor_enabled __lsm_ro_after_init = 1;
+module_param_named(enabled, apparmor_enabled, int, 0444);
static int __init apparmor_enabled_setup(char *str)
{
@@ -1479,14 +1483,8 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
static int __init set_init_ctx(void)
{
struct cred *cred = (struct cred *)current->real_cred;
- struct aa_task_ctx *ctx;
-
- ctx = aa_alloc_task_ctx(GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
- cred_label(cred) = aa_get_label(ns_unconfined(root_ns));
- task_ctx(current) = ctx;
+ set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
return 0;
}
@@ -1665,12 +1663,6 @@ static int __init apparmor_init(void)
{
int error;
- if (!apparmor_enabled || !security_module_enable("apparmor")) {
- aa_info_message("AppArmor disabled by boot time parameter");
- apparmor_enabled = false;
- return 0;
- }
-
aa_secids_init();
error = aa_setup_dfa_engine();
@@ -1731,5 +1723,8 @@ alloc_out:
DEFINE_LSM(apparmor) = {
.name = "apparmor",
+ .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+ .enabled = &apparmor_enabled,
+ .blobs = &apparmor_blob_sizes,
.init = apparmor_init,
};
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index 95fd26d09757..552ed09cb47e 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
*/
if (label != peer &&
- aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0)
+ aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
error = fn_for_each(label, profile,
audit_resource(profile, resource,
new_rlim->rlim_max, peer,
diff --git a/security/apparmor/task.c b/security/apparmor/task.c
index c6b78a14da91..4551110f0496 100644
--- a/security/apparmor/task.c
+++ b/security/apparmor/task.c
@@ -81,7 +81,7 @@ int aa_replace_current_label(struct aa_label *label)
*/
aa_get_label(label);
aa_put_label(cred_label(new));
- cred_label(new) = label;
+ set_cred_label(new, label);
commit_creds(new);
return 0;
@@ -138,7 +138,7 @@ int aa_set_current_hat(struct aa_label *label, u64 token)
return -EACCES;
}
- cred_label(new) = aa_get_newest_label(label);
+ set_cred_label(new, aa_get_newest_label(label));
/* clear exec on switching context */
aa_put_label(ctx->onexec);
ctx->onexec = NULL;
@@ -172,7 +172,7 @@ int aa_restore_previous_label(u64 token)
return -ENOMEM;
aa_put_label(cred_label(new));
- cred_label(new) = aa_get_newest_label(ctx->previous);
+ set_cred_label(new, aa_get_newest_label(ctx->previous));
AA_BUG(!cred_label(new));
/* clear exec && prev information when restoring to previous context */
aa_clear_task_ctx_trans(ctx);
diff --git a/security/commoncap.c b/security/commoncap.c
index 232db019f051..f1d117c3d8ae 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -57,7 +57,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
* @cred: The credentials to use
* @ns: The user namespace in which we need the capability
* @cap: The capability to check for
- * @audit: Whether to write an audit message or not
+ * @opts: Bitmask of options defined in include/linux/security.h
*
* Determine whether the nominated task has the specified capability amongst
* its effective set, returning 0 if it does, -ve if it does not.
@@ -68,7 +68,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
* kernel's capable() and has_capability() returns 1 for this case.
*/
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
- int cap, int audit)
+ int cap, unsigned int opts)
{
struct user_namespace *ns = targ_ns;
@@ -222,12 +222,11 @@ int cap_capget(struct task_struct *target, kernel_cap_t *effective,
*/
static inline int cap_inh_is_capped(void)
{
-
/* they are so limited unless the current task has the CAP_SETPCAP
* capability
*/
if (cap_capable(current_cred(), current_cred()->user_ns,
- CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
+ CAP_SETPCAP, CAP_OPT_NONE) == 0)
return 0;
return 1;
}
@@ -1208,8 +1207,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|| ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|| (cap_capable(current_cred(),
- current_cred()->user_ns, CAP_SETPCAP,
- SECURITY_CAP_AUDIT) != 0) /*[4]*/
+ current_cred()->user_ns,
+ CAP_SETPCAP,
+ CAP_OPT_NONE) != 0) /*[4]*/
/*
* [1] no changing of bits that are locked
* [2] no unlocking of locks
@@ -1304,9 +1304,10 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
{
int cap_sys_admin = 0;
- if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
- SECURITY_CAP_NOAUDIT) == 0)
+ if (cap_capable(current_cred(), &init_user_ns,
+ CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0)
cap_sys_admin = 1;
+
return cap_sys_admin;
}
@@ -1325,7 +1326,7 @@ int cap_mmap_addr(unsigned long addr)
if (addr < dac_mmap_min_addr) {
ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
- SECURITY_CAP_AUDIT);
+ CAP_OPT_NONE);
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
if (ret == 0)
current->flags |= PF_SUPERPRIV;
@@ -1362,10 +1363,17 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory),
};
-void __init capability_add_hooks(void)
+static int __init capability_init(void)
{
security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
"capability");
+ return 0;
}
+DEFINE_LSM(capability) = {
+ .name = "capability",
+ .order = LSM_ORDER_FIRST,
+ .init = capability_init,
+};
+
#endif /* CONFIG_SECURITY */
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index a2baa85ea2f5..5fb7127bbe68 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -114,6 +114,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
break;
case CREDS_CHECK:
iint->ima_creds_status = status;
+ break;
case FILE_CHECK:
case POST_SETATTR:
iint->ima_file_status = status;
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index 8bc8a1c8cb3f..122797023bdb 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -938,10 +938,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
case Opt_uid_gt:
case Opt_euid_gt:
entry->uid_op = &uid_gt;
+ /* fall through */
case Opt_uid_lt:
case Opt_euid_lt:
if ((token == Opt_uid_lt) || (token == Opt_euid_lt))
entry->uid_op = &uid_lt;
+ /* fall through */
case Opt_uid_eq:
case Opt_euid_eq:
uid_token = (token == Opt_uid_eq) ||
@@ -970,9 +972,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
break;
case Opt_fowner_gt:
entry->fowner_op = &uid_gt;
+ /* fall through */
case Opt_fowner_lt:
if (token == Opt_fowner_lt)
entry->fowner_op = &uid_lt;
+ /* fall through */
case Opt_fowner_eq:
ima_log_string_op(ab, "fowner", args[0].from,
entry->fowner_op);
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 43752002c222..513b457ae900 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -83,6 +83,7 @@ static void ima_show_template_data_ascii(struct seq_file *m,
/* skip ':' and '\0' */
buf_ptr += 2;
buflen -= buf_ptr - field_data->data;
+ /* fall through */
case DATA_FMT_DIGEST:
case DATA_FMT_HEX:
if (!buflen)
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 7bbe03593e58..3e4053a217c3 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1752,7 +1752,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
return -EINVAL;
return keyctl_pkey_query((key_serial_t)arg2,
(const char __user *)arg4,
- (struct keyctl_pkey_query *)arg5);
+ (struct keyctl_pkey_query __user *)arg5);
case KEYCTL_PKEY_ENCRYPT:
case KEYCTL_PKEY_DECRYPT:
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index f81372f53dd7..e14f09e3a4b0 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -246,6 +246,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
(ASSOC_ARRAY_KEY_CHUNK_SIZE - 8));
n--;
offset = 1;
+ /* fall through */
default:
offset += sizeof(chunk) - 1;
offset += (level - 3) * sizeof(chunk);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 0e0b9ccad2f8..9320424c4a46 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -380,6 +380,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
case -EAGAIN: /* no key */
if (ret)
break;
+ /* fall through */
case -ENOKEY: /* negative key */
ret = key_ref;
break;
@@ -404,6 +405,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
case -EAGAIN: /* no key */
if (ret)
break;
+ /* fall through */
case -ENOKEY: /* negative key */
ret = key_ref;
break;
@@ -424,6 +426,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
case -EAGAIN: /* no key */
if (ret)
break;
+ /* fall through */
case -ENOKEY: /* negative key */
ret = key_ref;
break;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 7a0c6b666ff0..2f17d84d46f1 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -273,16 +273,19 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
}
}
+ /* fall through */
case KEY_REQKEY_DEFL_THREAD_KEYRING:
dest_keyring = key_get(cred->thread_keyring);
if (dest_keyring)
break;
+ /* fall through */
case KEY_REQKEY_DEFL_PROCESS_KEYRING:
dest_keyring = key_get(cred->process_keyring);
if (dest_keyring)
break;
+ /* fall through */
case KEY_REQKEY_DEFL_SESSION_KEYRING:
rcu_read_lock();
dest_keyring = key_get(
@@ -292,6 +295,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
if (dest_keyring)
break;
+ /* fall through */
case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
dest_keyring =
key_get(cred->user->session_keyring);
diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c
index 48f39631b370..055fb0a64169 100644
--- a/security/loadpin/loadpin.c
+++ b/security/loadpin/loadpin.c
@@ -187,13 +187,19 @@ static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
};
-void __init loadpin_add_hooks(void)
+static int __init loadpin_init(void)
{
pr_info("ready to pin (currently %senforcing)\n",
enforce ? "" : "not ");
security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
+ return 0;
}
+DEFINE_LSM(loadpin) = {
+ .name = "loadpin",
+ .init = loadpin_init,
+};
+
/* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
module_param(enforce, int, 0);
MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
diff --git a/security/safesetid/Kconfig b/security/safesetid/Kconfig
new file mode 100644
index 000000000000..4f415c4e3f93
--- /dev/null
+++ b/security/safesetid/Kconfig
@@ -0,0 +1,14 @@
+config SECURITY_SAFESETID
+ bool "Gate setid transitions to limit CAP_SET{U/G}ID capabilities"
+ depends on SECURITY
+ select SECURITYFS
+ default n
+ help
+ SafeSetID is an LSM module that gates the setid family of syscalls to
+ restrict UID/GID transitions from a given UID/GID to only those
+ approved by a system-wide whitelist. These restrictions also prohibit
+ the given UIDs/GIDs from obtaining auxiliary privileges associated
+ with CAP_SET{U/G}ID, such as allowing a user to set up user namespace
+ UID mappings.
+
+ If you are unsure how to answer this question, answer N.
diff --git a/security/safesetid/Makefile b/security/safesetid/Makefile
new file mode 100644
index 000000000000..6b0660321164
--- /dev/null
+++ b/security/safesetid/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the safesetid LSM.
+#
+
+obj-$(CONFIG_SECURITY_SAFESETID) := safesetid.o
+safesetid-y := lsm.o securityfs.o
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
new file mode 100644
index 000000000000..cecd38e2ac80
--- /dev/null
+++ b/security/safesetid/lsm.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SafeSetID Linux Security Module
+ *
+ * Author: Micah Morton <mortonm@chromium.org>
+ *
+ * Copyright (C) 2018 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "SafeSetID: " fmt
+
+#include <linux/hashtable.h>
+#include <linux/lsm_hooks.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/sched/task_stack.h>
+#include <linux/security.h>
+
+/* Flag indicating whether initialization completed */
+int safesetid_initialized;
+
+#define NUM_BITS 8 /* 128 buckets in hash table */
+
+static DEFINE_HASHTABLE(safesetid_whitelist_hashtable, NUM_BITS);
+
+/*
+ * Hash table entry to store safesetid policy signifying that 'parent' user
+ * can setid to 'child' user.
+ */
+struct entry {
+ struct hlist_node next;
+ struct hlist_node dlist; /* for deletion cleanup */
+ uint64_t parent_kuid;
+ uint64_t child_kuid;
+};
+
+static DEFINE_SPINLOCK(safesetid_whitelist_hashtable_spinlock);
+
+static bool check_setuid_policy_hashtable_key(kuid_t parent)
+{
+ struct entry *entry;
+
+ rcu_read_lock();
+ hash_for_each_possible_rcu(safesetid_whitelist_hashtable,
+ entry, next, __kuid_val(parent)) {
+ if (entry->parent_kuid == __kuid_val(parent)) {
+ rcu_read_unlock();
+ return true;
+ }
+ }
+ rcu_read_unlock();
+
+ return false;
+}
+
+static bool check_setuid_policy_hashtable_key_value(kuid_t parent,
+ kuid_t child)
+{
+ struct entry *entry;
+
+ rcu_read_lock();
+ hash_for_each_possible_rcu(safesetid_whitelist_hashtable,
+ entry, next, __kuid_val(parent)) {
+ if (entry->parent_kuid == __kuid_val(parent) &&
+ entry->child_kuid == __kuid_val(child)) {
+ rcu_read_unlock();
+ return true;
+ }
+ }
+ rcu_read_unlock();
+
+ return false;
+}
+
+static int safesetid_security_capable(const struct cred *cred,
+ struct user_namespace *ns,
+ int cap,
+ unsigned int opts)
+{
+ if (cap == CAP_SETUID &&
+ check_setuid_policy_hashtable_key(cred->uid)) {
+ if (!(opts & CAP_OPT_INSETID)) {
+ /*
+ * Deny if we're not in a set*uid() syscall to avoid
+ * giving powers gated by CAP_SETUID that are related
+ * to functionality other than calling set*uid() (e.g.
+ * allowing user to set up userns uid mappings).
+ */
+ pr_warn("Operation requires CAP_SETUID, which is not available to UID %u for operations besides approved set*uid transitions",
+ __kuid_val(cred->uid));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int check_uid_transition(kuid_t parent, kuid_t child)
+{
+ if (check_setuid_policy_hashtable_key_value(parent, child))
+ return 0;
+ pr_warn("UID transition (%d -> %d) blocked",
+ __kuid_val(parent),
+ __kuid_val(child));
+ /*
+ * Kill this process to avoid potential security vulnerabilities
+ * that could arise from a missing whitelist entry preventing a
+ * privileged process from dropping to a lesser-privileged one.
+ */
+ force_sig(SIGKILL, current);
+ return -EACCES;
+}
+
+/*
+ * Check whether there is either an exception for user under old cred struct to
+ * set*uid to user under new cred struct, or the UID transition is allowed (by
+ * Linux set*uid rules) even without CAP_SETUID.
+ */
+static int safesetid_task_fix_setuid(struct cred *new,
+ const struct cred *old,
+ int flags)
+{
+
+ /* Do nothing if there are no setuid restrictions for this UID. */
+ if (!check_setuid_policy_hashtable_key(old->uid))
+ return 0;
+
+ switch (flags) {
+ case LSM_SETID_RE:
+ /*
+ * Users for which setuid restrictions exist can only set the
+ * real UID to the real UID or the effective UID, unless an
+ * explicit whitelist policy allows the transition.
+ */
+ if (!uid_eq(old->uid, new->uid) &&
+ !uid_eq(old->euid, new->uid)) {
+ return check_uid_transition(old->uid, new->uid);
+ }
+ /*
+ * Users for which setuid restrictions exist can only set the
+ * effective UID to the real UID, the effective UID, or the
+ * saved set-UID, unless an explicit whitelist policy allows
+ * the transition.
+ */
+ if (!uid_eq(old->uid, new->euid) &&
+ !uid_eq(old->euid, new->euid) &&
+ !uid_eq(old->suid, new->euid)) {
+ return check_uid_transition(old->euid, new->euid);
+ }
+ break;
+ case LSM_SETID_ID:
+ /*
+ * Users for which setuid restrictions exist cannot change the
+ * real UID or saved set-UID unless an explicit whitelist
+ * policy allows the transition.
+ */
+ if (!uid_eq(old->uid, new->uid))
+ return check_uid_transition(old->uid, new->uid);
+ if (!uid_eq(old->suid, new->suid))
+ return check_uid_transition(old->suid, new->suid);
+ break;
+ case LSM_SETID_RES:
+ /*
+ * Users for which setuid restrictions exist cannot change the
+ * real UID, effective UID, or saved set-UID to anything but
+ * one of: the current real UID, the current effective UID or
+ * the current saved set-user-ID unless an explicit whitelist
+ * policy allows the transition.
+ */
+ if (!uid_eq(new->uid, old->uid) &&
+ !uid_eq(new->uid, old->euid) &&
+ !uid_eq(new->uid, old->suid)) {
+ return check_uid_transition(old->uid, new->uid);
+ }
+ if (!uid_eq(new->euid, old->uid) &&
+ !uid_eq(new->euid, old->euid) &&
+ !uid_eq(new->euid, old->suid)) {
+ return check_uid_transition(old->euid, new->euid);
+ }
+ if (!uid_eq(new->suid, old->uid) &&
+ !uid_eq(new->suid, old->euid) &&
+ !uid_eq(new->suid, old->suid)) {
+ return check_uid_transition(old->suid, new->suid);
+ }
+ break;
+ case LSM_SETID_FS:
+ /*
+ * Users for which setuid restrictions exist cannot change the
+ * filesystem UID to anything but one of: the current real UID,
+ * the current effective UID or the current saved set-UID
+ * unless an explicit whitelist policy allows the transition.
+ */
+ if (!uid_eq(new->fsuid, old->uid) &&
+ !uid_eq(new->fsuid, old->euid) &&
+ !uid_eq(new->fsuid, old->suid) &&
+ !uid_eq(new->fsuid, old->fsuid)) {
+ return check_uid_transition(old->fsuid, new->fsuid);
+ }
+ break;
+ default:
+ pr_warn("Unknown setid state %d\n", flags);
+ force_sig(SIGKILL, current);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child)
+{
+ struct entry *new;
+
+ /* Return if entry already exists */
+ if (check_setuid_policy_hashtable_key_value(parent, child))
+ return 0;
+
+ new = kzalloc(sizeof(struct entry), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+ new->parent_kuid = __kuid_val(parent);
+ new->child_kuid = __kuid_val(child);
+ spin_lock(&safesetid_whitelist_hashtable_spinlock);
+ hash_add_rcu(safesetid_whitelist_hashtable,
+ &new->next,
+ __kuid_val(parent));
+ spin_unlock(&safesetid_whitelist_hashtable_spinlock);
+ return 0;
+}
+
+void flush_safesetid_whitelist_entries(void)
+{
+ struct entry *entry;
+ struct hlist_node *hlist_node;
+ unsigned int bkt_loop_cursor;
+ HLIST_HEAD(free_list);
+
+ /*
+ * Could probably use hash_for_each_rcu here instead, but this should
+ * be fine as well.
+ */
+ spin_lock(&safesetid_whitelist_hashtable_spinlock);
+ hash_for_each_safe(safesetid_whitelist_hashtable, bkt_loop_cursor,
+ hlist_node, entry, next) {
+ hash_del_rcu(&entry->next);
+ hlist_add_head(&entry->dlist, &free_list);
+ }
+ spin_unlock(&safesetid_whitelist_hashtable_spinlock);
+ synchronize_rcu();
+ hlist_for_each_entry_safe(entry, hlist_node, &free_list, dlist) {
+ hlist_del(&entry->dlist);
+ kfree(entry);
+ }
+}
+
+static struct security_hook_list safesetid_security_hooks[] = {
+ LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid),
+ LSM_HOOK_INIT(capable, safesetid_security_capable)
+};
+
+static int __init safesetid_security_init(void)
+{
+ security_add_hooks(safesetid_security_hooks,
+ ARRAY_SIZE(safesetid_security_hooks), "safesetid");
+
+ /* Report that SafeSetID successfully initialized */
+ safesetid_initialized = 1;
+
+ return 0;
+}
+
+DEFINE_LSM(safesetid_security_init) = {
+ .init = safesetid_security_init,
+ .name = "safesetid",
+};
diff --git a/security/safesetid/lsm.h b/security/safesetid/lsm.h
new file mode 100644
index 000000000000..c1ea3c265fcf
--- /dev/null
+++ b/security/safesetid/lsm.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SafeSetID Linux Security Module
+ *
+ * Author: Micah Morton <mortonm@chromium.org>
+ *
+ * Copyright (C) 2018 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef _SAFESETID_H
+#define _SAFESETID_H
+
+#include <linux/types.h>
+
+/* Flag indicating whether initialization completed */
+extern int safesetid_initialized;
+
+/* Function type. */
+enum safesetid_whitelist_file_write_type {
+ SAFESETID_WHITELIST_ADD, /* Add whitelist policy. */
+ SAFESETID_WHITELIST_FLUSH, /* Flush whitelist policies. */
+};
+
+/* Add entry to safesetid whitelist to allow 'parent' to setid to 'child'. */
+int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child);
+
+void flush_safesetid_whitelist_entries(void);
+
+#endif /* _SAFESETID_H */
diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c
new file mode 100644
index 000000000000..2c6c829be044
--- /dev/null
+++ b/security/safesetid/securityfs.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SafeSetID Linux Security Module
+ *
+ * Author: Micah Morton <mortonm@chromium.org>
+ *
+ * Copyright (C) 2018 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/security.h>
+#include <linux/cred.h>
+
+#include "lsm.h"
+
+static struct dentry *safesetid_policy_dir;
+
+struct safesetid_file_entry {
+ const char *name;
+ enum safesetid_whitelist_file_write_type type;
+ struct dentry *dentry;
+};
+
+static struct safesetid_file_entry safesetid_files[] = {
+ {.name = "add_whitelist_policy",
+ .type = SAFESETID_WHITELIST_ADD},
+ {.name = "flush_whitelist_policies",
+ .type = SAFESETID_WHITELIST_FLUSH},
+};
+
+/*
+ * In the case the input buffer contains one or more invalid UIDs, the kuid_t
+ * variables pointed to by 'parent' and 'child' will get updated but this
+ * function will return an error.
+ */
+static int parse_safesetid_whitelist_policy(const char __user *buf,
+ size_t len,
+ kuid_t *parent,
+ kuid_t *child)
+{
+ char *kern_buf;
+ char *parent_buf;
+ char *child_buf;
+ const char separator[] = ":";
+ int ret;
+ size_t first_substring_length;
+ long parsed_parent;
+ long parsed_child;
+
+ /* Duplicate string from user memory and NULL-terminate */
+ kern_buf = memdup_user_nul(buf, len);
+ if (IS_ERR(kern_buf))
+ return PTR_ERR(kern_buf);
+
+ /*
+ * Format of |buf| string should be <UID>:<UID>.
+ * Find location of ":" in kern_buf (copied from |buf|).
+ */
+ first_substring_length = strcspn(kern_buf, separator);
+ if (first_substring_length == 0 || first_substring_length == len) {
+ ret = -EINVAL;
+ goto free_kern;
+ }
+
+ parent_buf = kmemdup_nul(kern_buf, first_substring_length, GFP_KERNEL);
+ if (!parent_buf) {
+ ret = -ENOMEM;
+ goto free_kern;
+ }
+
+ ret = kstrtol(parent_buf, 0, &parsed_parent);
+ if (ret)
+ goto free_both;
+
+ child_buf = kern_buf + first_substring_length + 1;
+ ret = kstrtol(child_buf, 0, &parsed_child);
+ if (ret)
+ goto free_both;
+
+ *parent = make_kuid(current_user_ns(), parsed_parent);
+ if (!uid_valid(*parent)) {
+ ret = -EINVAL;
+ goto free_both;
+ }
+
+ *child = make_kuid(current_user_ns(), parsed_child);
+ if (!uid_valid(*child)) {
+ ret = -EINVAL;
+ goto free_both;
+ }
+
+free_both:
+ kfree(parent_buf);
+free_kern:
+ kfree(kern_buf);
+ return ret;
+}
+
+static ssize_t safesetid_file_write(struct file *file,
+ const char __user *buf,
+ size_t len,
+ loff_t *ppos)
+{
+ struct safesetid_file_entry *file_entry =
+ file->f_inode->i_private;
+ kuid_t parent;
+ kuid_t child;
+ int ret;
+
+ if (!ns_capable(current_user_ns(), CAP_MAC_ADMIN))
+ return -EPERM;
+
+ if (*ppos != 0)
+ return -EINVAL;
+
+ switch (file_entry->type) {
+ case SAFESETID_WHITELIST_FLUSH:
+ flush_safesetid_whitelist_entries();
+ break;
+ case SAFESETID_WHITELIST_ADD:
+ ret = parse_safesetid_whitelist_policy(buf, len, &parent,
+ &child);
+ if (ret)
+ return ret;
+
+ ret = add_safesetid_whitelist_entry(parent, child);
+ if (ret)
+ return ret;
+ break;
+ default:
+ pr_warn("Unknown securityfs file %d\n", file_entry->type);
+ break;
+ }
+
+ /* Return len on success so caller won't keep trying to write */
+ return len;
+}
+
+static const struct file_operations safesetid_file_fops = {
+ .write = safesetid_file_write,
+};
+
+static void safesetid_shutdown_securityfs(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) {
+ struct safesetid_file_entry *entry =
+ &safesetid_files[i];
+ securityfs_remove(entry->dentry);
+ entry->dentry = NULL;
+ }
+
+ securityfs_remove(safesetid_policy_dir);
+ safesetid_policy_dir = NULL;
+}
+
+static int __init safesetid_init_securityfs(void)
+{
+ int i;
+ int ret;
+
+ if (!safesetid_initialized)
+ return 0;
+
+ safesetid_policy_dir = securityfs_create_dir("safesetid", NULL);
+ if (IS_ERR(safesetid_policy_dir)) {
+ ret = PTR_ERR(safesetid_policy_dir);
+ goto error;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) {
+ struct safesetid_file_entry *entry =
+ &safesetid_files[i];
+ entry->dentry = securityfs_create_file(
+ entry->name, 0200, safesetid_policy_dir,
+ entry, &safesetid_file_fops);
+ if (IS_ERR(entry->dentry)) {
+ ret = PTR_ERR(entry->dentry);
+ goto error;
+ }
+ }
+
+ return 0;
+
+error:
+ safesetid_shutdown_securityfs();
+ return ret;
+}
+fs_initcall(safesetid_init_securityfs);
diff --git a/security/security.c b/security/security.c
index 55bc49027ba9..ed9b8cbf21cf 100644
--- a/security/security.c
+++ b/security/security.c
@@ -30,20 +30,32 @@
#include <linux/personality.h>
#include <linux/backing-dev.h>
#include <linux/string.h>
+#include <linux/msg.h>
#include <net/flow.h>
#define MAX_LSM_EVM_XATTR 2
-/* Maximum number of letters for an LSM name string */
-#define SECURITY_NAME_MAX 10
+/* How many LSMs were built into the kernel? */
+#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
+static struct kmem_cache *lsm_file_cache;
+static struct kmem_cache *lsm_inode_cache;
+
char *lsm_names;
+static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
+
/* Boot-time LSM user choice */
-static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
- CONFIG_DEFAULT_SECURITY;
+static __initdata const char *chosen_lsm_order;
+static __initdata const char *chosen_major_lsm;
+
+static __initconst const char * const builtin_lsm_order = CONFIG_LSM;
+
+/* Ordered list of LSMs to initialize. */
+static __initdata struct lsm_info **ordered_lsms;
+static __initdata struct lsm_info *exclusive;
static __initdata bool debug;
#define init_debug(...) \
@@ -52,18 +64,269 @@ static __initdata bool debug;
pr_info(__VA_ARGS__); \
} while (0)
-static void __init major_lsm_init(void)
+static bool __init is_enabled(struct lsm_info *lsm)
{
- struct lsm_info *lsm;
- int ret;
+ if (!lsm->enabled)
+ return false;
+
+ return *lsm->enabled;
+}
+
+/* Mark an LSM's enabled flag. */
+static int lsm_enabled_true __initdata = 1;
+static int lsm_enabled_false __initdata = 0;
+static void __init set_enabled(struct lsm_info *lsm, bool enabled)
+{
+ /*
+ * When an LSM hasn't configured an enable variable, we can use
+ * a hard-coded location for storing the default enabled state.
+ */
+ if (!lsm->enabled) {
+ if (enabled)
+ lsm->enabled = &lsm_enabled_true;
+ else
+ lsm->enabled = &lsm_enabled_false;
+ } else if (lsm->enabled == &lsm_enabled_true) {
+ if (!enabled)
+ lsm->enabled = &lsm_enabled_false;
+ } else if (lsm->enabled == &lsm_enabled_false) {
+ if (enabled)
+ lsm->enabled = &lsm_enabled_true;
+ } else {
+ *lsm->enabled = enabled;
+ }
+}
+
+/* Is an LSM already listed in the ordered LSMs list? */
+static bool __init exists_ordered_lsm(struct lsm_info *lsm)
+{
+ struct lsm_info **check;
+
+ for (check = ordered_lsms; *check; check++)
+ if (*check == lsm)
+ return true;
+
+ return false;
+}
+
+/* Append an LSM to the list of ordered LSMs to initialize. */
+static int last_lsm __initdata;
+static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
+{
+ /* Ignore duplicate selections. */
+ if (exists_ordered_lsm(lsm))
+ return;
+
+ if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM slots!?\n", from))
+ return;
+
+ /* Enable this LSM, if it is not already set. */
+ if (!lsm->enabled)
+ lsm->enabled = &lsm_enabled_true;
+ ordered_lsms[last_lsm++] = lsm;
+
+ init_debug("%s ordering: %s (%sabled)\n", from, lsm->name,
+ is_enabled(lsm) ? "en" : "dis");
+}
+
+/* Is an LSM allowed to be initialized? */
+static bool __init lsm_allowed(struct lsm_info *lsm)
+{
+ /* Skip if the LSM is disabled. */
+ if (!is_enabled(lsm))
+ return false;
+
+ /* Not allowed if another exclusive LSM already initialized. */
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+ init_debug("exclusive disabled: %s\n", lsm->name);
+ return false;
+ }
+
+ return true;
+}
+
+static void __init lsm_set_blob_size(int *need, int *lbs)
+{
+ int offset;
+
+ if (*need > 0) {
+ offset = *lbs;
+ *lbs += *need;
+ *need = offset;
+ }
+}
+
+static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+{
+ if (!needed)
+ return;
+
+ lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
+ /*
+ * The inode blob gets an rcu_head in addition to
+ * what the modules might need.
+ */
+ if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
+ blob_sizes.lbs_inode = sizeof(struct rcu_head);
+ lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+}
+
+/* Prepare LSM for initialization. */
+static void __init prepare_lsm(struct lsm_info *lsm)
+{
+ int enabled = lsm_allowed(lsm);
+
+ /* Record enablement (to handle any following exclusive LSMs). */
+ set_enabled(lsm, enabled);
+
+ /* If enabled, do pre-initialization work. */
+ if (enabled) {
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+ exclusive = lsm;
+ init_debug("exclusive chosen: %s\n", lsm->name);
+ }
+
+ lsm_set_blob_sizes(lsm->blobs);
+ }
+}
+
+/* Initialize a given LSM, if it is enabled. */
+static void __init initialize_lsm(struct lsm_info *lsm)
+{
+ if (is_enabled(lsm)) {
+ int ret;
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
init_debug("initializing %s\n", lsm->name);
ret = lsm->init();
WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
}
}
+/* Populate ordered LSMs list from comma-separated LSM name list. */
+static void __init ordered_lsm_parse(const char *order, const char *origin)
+{
+ struct lsm_info *lsm;
+ char *sep, *name, *next;
+
+ /* LSM_ORDER_FIRST is always first. */
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (lsm->order == LSM_ORDER_FIRST)
+ append_ordered_lsm(lsm, "first");
+ }
+
+ /* Process "security=", if given. */
+ if (chosen_major_lsm) {
+ struct lsm_info *major;
+
+ /*
+ * To match the original "security=" behavior, this
+ * explicitly does NOT fallback to another Legacy Major
+ * if the selected one was separately disabled: disable
+ * all non-matching Legacy Major LSMs.
+ */
+ for (major = __start_lsm_info; major < __end_lsm_info;
+ major++) {
+ if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
+ strcmp(major->name, chosen_major_lsm) != 0) {
+ set_enabled(major, false);
+ init_debug("security=%s disabled: %s\n",
+ chosen_major_lsm, major->name);
+ }
+ }
+ }
+
+ sep = kstrdup(order, GFP_KERNEL);
+ next = sep;
+ /* Walk the list, looking for matching LSMs. */
+ while ((name = strsep(&next, ",")) != NULL) {
+ bool found = false;
+
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (lsm->order == LSM_ORDER_MUTABLE &&
+ strcmp(lsm->name, name) == 0) {
+ append_ordered_lsm(lsm, origin);
+ found = true;
+ }
+ }
+
+ if (!found)
+ init_debug("%s ignored: %s\n", origin, name);
+ }
+
+ /* Process "security=", if given. */
+ if (chosen_major_lsm) {
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (exists_ordered_lsm(lsm))
+ continue;
+ if (strcmp(lsm->name, chosen_major_lsm) == 0)
+ append_ordered_lsm(lsm, "security=");
+ }
+ }
+
+ /* Disable all LSMs not in the ordered list. */
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (exists_ordered_lsm(lsm))
+ continue;
+ set_enabled(lsm, false);
+ init_debug("%s disabled: %s\n", origin, lsm->name);
+ }
+
+ kfree(sep);
+}
+
+static void __init lsm_early_cred(struct cred *cred);
+static void __init lsm_early_task(struct task_struct *task);
+
+static void __init ordered_lsm_init(void)
+{
+ struct lsm_info **lsm;
+
+ ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms),
+ GFP_KERNEL);
+
+ if (chosen_lsm_order) {
+ if (chosen_major_lsm) {
+ pr_info("security= is ignored because it is superseded by lsm=\n");
+ chosen_major_lsm = NULL;
+ }
+ ordered_lsm_parse(chosen_lsm_order, "cmdline");
+ } else
+ ordered_lsm_parse(builtin_lsm_order, "builtin");
+
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ prepare_lsm(*lsm);
+
+ init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
+ init_debug("file blob size = %d\n", blob_sizes.lbs_file);
+ init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
+ init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
+ init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
+ init_debug("task blob size = %d\n", blob_sizes.lbs_task);
+
+ /*
+ * Create any kmem_caches needed for blobs
+ */
+ if (blob_sizes.lbs_file)
+ lsm_file_cache = kmem_cache_create("lsm_file_cache",
+ blob_sizes.lbs_file, 0,
+ SLAB_PANIC, NULL);
+ if (blob_sizes.lbs_inode)
+ lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+ blob_sizes.lbs_inode, 0,
+ SLAB_PANIC, NULL);
+
+ lsm_early_cred((struct cred *) current->cred);
+ lsm_early_task(current);
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ initialize_lsm(*lsm);
+
+ kfree(ordered_lsms);
+}
+
/**
* security_init - initializes the security framework
*
@@ -80,28 +343,27 @@ int __init security_init(void)
i++)
INIT_HLIST_HEAD(&list[i]);
- /*
- * Load minor LSMs, with the capability module always first.
- */
- capability_add_hooks();
- yama_add_hooks();
- loadpin_add_hooks();
-
- /*
- * Load all the remaining security modules.
- */
- major_lsm_init();
+ /* Load LSMs in specified order. */
+ ordered_lsm_init();
return 0;
}
/* Save user chosen LSM */
-static int __init choose_lsm(char *str)
+static int __init choose_major_lsm(char *str)
+{
+ chosen_major_lsm = str;
+ return 1;
+}
+__setup("security=", choose_major_lsm);
+
+/* Explicitly choose LSM initialization order. */
+static int __init choose_lsm_order(char *str)
{
- strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+ chosen_lsm_order = str;
return 1;
}
-__setup("security=", choose_lsm);
+__setup("lsm=", choose_lsm_order);
/* Enable LSM order debugging. */
static int __init enable_debug(char *str)
@@ -148,29 +410,6 @@ static int lsm_append(char *new, char **result)
}
/**
- * security_module_enable - Load given security module on boot ?
- * @module: the name of the module
- *
- * Each LSM must pass this method before registering its own operations
- * to avoid security registration races. This method may also be used
- * to check if your LSM is currently loaded during kernel initialization.
- *
- * Returns:
- *
- * true if:
- *
- * - The passed LSM is the one chosen by user at boot time,
- * - or the passed LSM is configured as the default and the user did not
- * choose an alternate LSM at boot time.
- *
- * Otherwise, return false.
- */
-int __init security_module_enable(const char *module)
-{
- return !strcmp(module, chosen_lsm);
-}
-
-/**
* security_add_hooks - Add a modules hooks to the hook lists.
* @hooks: the hooks to add
* @count: the number of hooks to add
@@ -209,6 +448,161 @@ int unregister_lsm_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL(unregister_lsm_notifier);
+/**
+ * lsm_cred_alloc - allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ * @gfp: allocation type
+ *
+ * Allocate the cred blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+{
+ if (blob_sizes.lbs_cred == 0) {
+ cred->security = NULL;
+ return 0;
+ }
+
+ cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
+ if (cred->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_early_cred - during initialization allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ *
+ * Allocate the cred blob for all the modules
+ */
+static void __init lsm_early_cred(struct cred *cred)
+{
+ int rc = lsm_cred_alloc(cred, GFP_KERNEL);
+
+ if (rc)
+ panic("%s: Early cred alloc failed.\n", __func__);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_file_alloc(struct file *file)
+{
+ if (!lsm_file_cache) {
+ file->f_security = NULL;
+ return 0;
+ }
+
+ file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+ if (file->f_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_inode_alloc - allocate a composite inode blob
+ * @inode: the inode that needs a blob
+ *
+ * Allocate the inode blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_inode_alloc(struct inode *inode)
+{
+ if (!lsm_inode_cache) {
+ inode->i_security = NULL;
+ return 0;
+ }
+
+ inode->i_security = kmem_cache_zalloc(lsm_inode_cache, GFP_NOFS);
+ if (inode->i_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_task_alloc - allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_task_alloc(struct task_struct *task)
+{
+ if (blob_sizes.lbs_task == 0) {
+ task->security = NULL;
+ return 0;
+ }
+
+ task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
+ if (task->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_ipc_alloc - allocate a composite ipc blob
+ * @kip: the ipc that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_ipc_alloc(struct kern_ipc_perm *kip)
+{
+ if (blob_sizes.lbs_ipc == 0) {
+ kip->security = NULL;
+ return 0;
+ }
+
+ kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL);
+ if (kip->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_msg_msg_alloc - allocate a composite msg_msg blob
+ * @mp: the msg_msg that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_msg_msg_alloc(struct msg_msg *mp)
+{
+ if (blob_sizes.lbs_msg_msg == 0) {
+ mp->security = NULL;
+ return 0;
+ }
+
+ mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL);
+ if (mp->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_early_task - during initialization allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ */
+static void __init lsm_early_task(struct task_struct *task)
+{
+ int rc = lsm_task_alloc(task);
+
+ if (rc)
+ panic("%s: Early task alloc failed.\n", __func__);
+}
+
/*
* Hook list operation macros.
*
@@ -294,16 +688,12 @@ int security_capset(struct cred *new, const struct cred *old,
effective, inheritable, permitted);
}
-int security_capable(const struct cred *cred, struct user_namespace *ns,
- int cap)
+int security_capable(const struct cred *cred,
+ struct user_namespace *ns,
+ int cap,
+ unsigned int opts)
{
- return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT);
-}
-
-int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
- int cap)
-{
- return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT);
+ return call_int_hook(capable, 0, cred, ns, cap, opts);
}
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -468,14 +858,40 @@ EXPORT_SYMBOL(security_add_mnt_opt);
int security_inode_alloc(struct inode *inode)
{
- inode->i_security = NULL;
- return call_int_hook(inode_alloc_security, 0, inode);
+ int rc = lsm_inode_alloc(inode);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(inode_alloc_security, 0, inode);
+ if (unlikely(rc))
+ security_inode_free(inode);
+ return rc;
+}
+
+static void inode_free_by_rcu(struct rcu_head *head)
+{
+ /*
+ * The rcu head is at the start of the inode blob
+ */
+ kmem_cache_free(lsm_inode_cache, head);
}
void security_inode_free(struct inode *inode)
{
integrity_inode_free(inode);
call_void_hook(inode_free_security, inode);
+ /*
+ * The inode may still be referenced in a path walk and
+ * a call to security_inode_permission() can be made
+ * after inode_free_security() is called. Ideally, the VFS
+ * wouldn't do this, but fixing that is a much harder
+ * job. For now, simply free the i_security via RCU, and
+ * leave the current inode->i_security pointer intact.
+ * The inode will be freed after the RCU grace period too.
+ */
+ if (inode->i_security)
+ call_rcu((struct rcu_head *)inode->i_security,
+ inode_free_by_rcu);
}
int security_dentry_init_security(struct dentry *dentry, int mode,
@@ -905,12 +1321,27 @@ int security_file_permission(struct file *file, int mask)
int security_file_alloc(struct file *file)
{
- return call_int_hook(file_alloc_security, 0, file);
+ int rc = lsm_file_alloc(file);
+
+ if (rc)
+ return rc;
+ rc = call_int_hook(file_alloc_security, 0, file);
+ if (unlikely(rc))
+ security_file_free(file);
+ return rc;
}
void security_file_free(struct file *file)
{
+ void *blob;
+
call_void_hook(file_free_security, file);
+
+ blob = file->f_security;
+ if (blob) {
+ file->f_security = NULL;
+ kmem_cache_free(lsm_file_cache, blob);
+ }
}
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1012,17 +1443,35 @@ int security_file_open(struct file *file)
int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
{
- return call_int_hook(task_alloc, 0, task, clone_flags);
+ int rc = lsm_task_alloc(task);
+
+ if (rc)
+ return rc;
+ rc = call_int_hook(task_alloc, 0, task, clone_flags);
+ if (unlikely(rc))
+ security_task_free(task);
+ return rc;
}
void security_task_free(struct task_struct *task)
{
call_void_hook(task_free, task);
+
+ kfree(task->security);
+ task->security = NULL;
}
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
- return call_int_hook(cred_alloc_blank, 0, cred, gfp);
+ int rc = lsm_cred_alloc(cred, gfp);
+
+ if (rc)
+ return rc;
+
+ rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
+ if (unlikely(rc))
+ security_cred_free(cred);
+ return rc;
}
void security_cred_free(struct cred *cred)
@@ -1035,11 +1484,22 @@ void security_cred_free(struct cred *cred)
return;
call_void_hook(cred_free, cred);
+
+ kfree(cred->security);
+ cred->security = NULL;
}
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
{
- return call_int_hook(cred_prepare, 0, new, old, gfp);
+ int rc = lsm_cred_alloc(new, gfp);
+
+ if (rc)
+ return rc;
+
+ rc = call_int_hook(cred_prepare, 0, new, old, gfp);
+ if (unlikely(rc))
+ security_cred_free(new);
+ return rc;
}
void security_transfer_creds(struct cred *new, const struct cred *old)
@@ -1220,22 +1680,40 @@ void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
int security_msg_msg_alloc(struct msg_msg *msg)
{
- return call_int_hook(msg_msg_alloc_security, 0, msg);
+ int rc = lsm_msg_msg_alloc(msg);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(msg_msg_alloc_security, 0, msg);
+ if (unlikely(rc))
+ security_msg_msg_free(msg);
+ return rc;
}
void security_msg_msg_free(struct msg_msg *msg)
{
call_void_hook(msg_msg_free_security, msg);
+ kfree(msg->security);
+ msg->security = NULL;
}
int security_msg_queue_alloc(struct kern_ipc_perm *msq)
{
- return call_int_hook(msg_queue_alloc_security, 0, msq);
+ int rc = lsm_ipc_alloc(msq);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(msg_queue_alloc_security, 0, msq);
+ if (unlikely(rc))
+ security_msg_queue_free(msq);
+ return rc;
}
void security_msg_queue_free(struct kern_ipc_perm *msq)
{
call_void_hook(msg_queue_free_security, msq);
+ kfree(msq->security);
+ msq->security = NULL;
}
int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
@@ -1262,12 +1740,21 @@ int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
int security_shm_alloc(struct kern_ipc_perm *shp)
{
- return call_int_hook(shm_alloc_security, 0, shp);
+ int rc = lsm_ipc_alloc(shp);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(shm_alloc_security, 0, shp);
+ if (unlikely(rc))
+ security_shm_free(shp);
+ return rc;
}
void security_shm_free(struct kern_ipc_perm *shp)
{
call_void_hook(shm_free_security, shp);
+ kfree(shp->security);
+ shp->security = NULL;
}
int security_shm_associate(struct kern_ipc_perm *shp, int shmflg)
@@ -1287,12 +1774,21 @@ int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmf
int security_sem_alloc(struct kern_ipc_perm *sma)
{
- return call_int_hook(sem_alloc_security, 0, sma);
+ int rc = lsm_ipc_alloc(sma);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(sem_alloc_security, 0, sma);
+ if (unlikely(rc))
+ security_sem_free(sma);
+ return rc;
}
void security_sem_free(struct kern_ipc_perm *sma)
{
call_void_hook(sem_free_security, sma);
+ kfree(sma->security);
+ sma->security = NULL;
}
int security_sem_associate(struct kern_ipc_perm *sma, int semflg)
@@ -1319,14 +1815,30 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
}
EXPORT_SYMBOL(security_d_instantiate);
-int security_getprocattr(struct task_struct *p, char *name, char **value)
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+ char **value)
{
- return call_int_hook(getprocattr, -EINVAL, p, name, value);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+ if (lsm != NULL && strcmp(lsm, hp->lsm))
+ continue;
+ return hp->hook.getprocattr(p, name, value);
+ }
+ return -EINVAL;
}
-int security_setprocattr(const char *name, void *value, size_t size)
+int security_setprocattr(const char *lsm, const char *name, void *value,
+ size_t size)
{
- return call_int_hook(setprocattr, -EINVAL, name, value, size);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
+ if (lsm != NULL && strcmp(lsm, hp->lsm))
+ continue;
+ return hp->hook.setprocattr(name, value, size);
+ }
+ return -EINVAL;
}
int security_netlink_send(struct sock *sk, struct sk_buff *skb)
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 8af7a690eb40..55f032f1fc2d 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -22,21 +22,6 @@ config SECURITY_SELINUX_BOOTPARAM
If you are unsure how to answer this question, answer N.
-config SECURITY_SELINUX_BOOTPARAM_VALUE
- int "NSA SELinux boot parameter default value"
- depends on SECURITY_SELINUX_BOOTPARAM
- range 0 1
- default 1
- help
- This option sets the default value for the kernel parameter
- 'selinux', which allows SELinux to be disabled at boot. If this
- option is set to 0 (zero), the SELinux kernel parameter will
- default to 0, disabling SELinux at bootup. If this option is
- set to 1 (one), the SELinux kernel parameter will default to 1,
- enabling SELinux at bootup.
-
- If you are unsure how to answer this question, answer 1.
-
config SECURITY_SELINUX_DISABLE
bool "NSA SELinux runtime disable"
depends on SECURITY_SELINUX
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index c7161f8792b2..ccf950409384 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -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 exports.o \
+ netnode.o netport.o ibpkey.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
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
deleted file mode 100644
index e75dd94e2d2b..000000000000
--- a/security/selinux/exports.c
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SELinux services exported to the rest of the kernel.
- *
- * Author: James Morris <jmorris@redhat.com>
- *
- * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
- * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
- * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/selinux.h>
-
-#include "security.h"
-
-bool selinux_is_enabled(void)
-{
- return selinux_enabled;
-}
-EXPORT_SYMBOL_GPL(selinux_is_enabled);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f0e36c3492ba..5d92167dbe05 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -79,7 +79,6 @@
#include <linux/personality.h>
#include <linux/audit.h>
#include <linux/string.h>
-#include <linux/selinux.h>
#include <linux/mutex.h>
#include <linux/posix-timers.h>
#include <linux/syslog.h>
@@ -121,9 +120,8 @@ __setup("enforcing=", enforcing_setup);
#define selinux_enforcing_boot 1
#endif
+int selinux_enabled __lsm_ro_after_init = 1;
#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
-int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
-
static int __init selinux_enabled_setup(char *str)
{
unsigned long enabled;
@@ -132,8 +130,6 @@ static int __init selinux_enabled_setup(char *str)
return 1;
}
__setup("selinux=", selinux_enabled_setup);
-#else
-int selinux_enabled = 1;
#endif
static unsigned int selinux_checkreqprot_boot =
@@ -149,9 +145,6 @@ static int __init checkreqprot_setup(char *str)
}
__setup("checkreqprot=", checkreqprot_setup);
-static struct kmem_cache *sel_inode_cache;
-static struct kmem_cache *file_security_cache;
-
/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
*
@@ -214,12 +207,8 @@ static void cred_init_security(void)
struct cred *cred = (struct cred *) current->real_cred;
struct task_security_struct *tsec;
- tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
- if (!tsec)
- panic("SELinux: Failed to initialize initial task.\n");
-
+ tsec = selinux_cred(cred);
tsec->osid = tsec->sid = SECINITSID_KERNEL;
- cred->security = tsec;
}
/*
@@ -229,7 +218,7 @@ static inline u32 cred_sid(const struct cred *cred)
{
const struct task_security_struct *tsec;
- tsec = cred->security;
+ tsec = selinux_cred(cred);
return tsec->sid;
}
@@ -250,13 +239,9 @@ static inline u32 task_sid(const struct task_struct *task)
static int inode_alloc_security(struct inode *inode)
{
- struct inode_security_struct *isec;
+ struct inode_security_struct *isec = selinux_inode(inode);
u32 sid = current_sid();
- isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
- if (!isec)
- return -ENOMEM;
-
spin_lock_init(&isec->lock);
INIT_LIST_HEAD(&isec->list);
isec->inode = inode;
@@ -264,7 +249,6 @@ static int inode_alloc_security(struct inode *inode)
isec->sclass = SECCLASS_FILE;
isec->task_sid = sid;
isec->initialized = LABEL_INVALID;
- inode->i_security = isec;
return 0;
}
@@ -281,7 +265,7 @@ static int __inode_security_revalidate(struct inode *inode,
struct dentry *dentry,
bool may_sleep)
{
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
might_sleep_if(may_sleep);
@@ -302,7 +286,7 @@ static int __inode_security_revalidate(struct inode *inode,
static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
{
- return inode->i_security;
+ return selinux_inode(inode);
}
static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
@@ -312,7 +296,7 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo
error = __inode_security_revalidate(inode, NULL, !rcu);
if (error)
return ERR_PTR(error);
- return inode->i_security;
+ return selinux_inode(inode);
}
/*
@@ -321,14 +305,14 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo
static struct inode_security_struct *inode_security(struct inode *inode)
{
__inode_security_revalidate(inode, NULL, true);
- return inode->i_security;
+ return selinux_inode(inode);
}
static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
{
struct inode *inode = d_backing_inode(dentry);
- return inode->i_security;
+ return selinux_inode(inode);
}
/*
@@ -339,22 +323,17 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
struct inode *inode = d_backing_inode(dentry);
__inode_security_revalidate(inode, dentry, true);
- return inode->i_security;
-}
-
-static void inode_free_rcu(struct rcu_head *head)
-{
- struct inode_security_struct *isec;
-
- isec = container_of(head, struct inode_security_struct, rcu);
- kmem_cache_free(sel_inode_cache, isec);
+ return selinux_inode(inode);
}
static void inode_free_security(struct inode *inode)
{
- struct inode_security_struct *isec = inode->i_security;
- struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
+ struct superblock_security_struct *sbsec;
+ if (!isec)
+ return;
+ sbsec = inode->i_sb->s_security;
/*
* As not all inode security structures are in a list, we check for
* empty list outside of the lock to make sure that we won't waste
@@ -370,42 +349,19 @@ static void inode_free_security(struct inode *inode)
list_del_init(&isec->list);
spin_unlock(&sbsec->isec_lock);
}
-
- /*
- * The inode may still be referenced in a path walk and
- * a call to selinux_inode_permission() can be made
- * after inode_free_security() is called. Ideally, the VFS
- * wouldn't do this, but fixing that is a much harder
- * job. For now, simply free the i_security via RCU, and
- * leave the current inode->i_security pointer intact.
- * The inode will be freed after the RCU grace period too.
- */
- call_rcu(&isec->rcu, inode_free_rcu);
}
static int file_alloc_security(struct file *file)
{
- struct file_security_struct *fsec;
+ struct file_security_struct *fsec = selinux_file(file);
u32 sid = current_sid();
- fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
- if (!fsec)
- return -ENOMEM;
-
fsec->sid = sid;
fsec->fown_sid = sid;
- file->f_security = fsec;
return 0;
}
-static void file_free_security(struct file *file)
-{
- struct file_security_struct *fsec = file->f_security;
- file->f_security = NULL;
- kmem_cache_free(file_security_cache, fsec);
-}
-
static int superblock_alloc_security(struct super_block *sb)
{
struct superblock_security_struct *sbsec;
@@ -501,7 +457,7 @@ static int may_context_mount_sb_relabel(u32 sid,
struct superblock_security_struct *sbsec,
const struct cred *cred)
{
- const struct task_security_struct *tsec = cred->security;
+ const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
rc = avc_has_perm(&selinux_state,
@@ -520,7 +476,7 @@ static int may_context_mount_inode_relabel(u32 sid,
struct superblock_security_struct *sbsec,
const struct cred *cred)
{
- const struct task_security_struct *tsec = cred->security;
+ const struct task_security_struct *tsec = selinux_cred(cred);
int rc;
rc = avc_has_perm(&selinux_state,
tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
@@ -1374,7 +1330,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
{
struct superblock_security_struct *sbsec = NULL;
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
u32 task_sid, sid = 0;
u16 sclass;
struct dentry *dentry;
@@ -1621,7 +1577,7 @@ static inline u32 signal_to_av(int sig)
/* Check whether a task is allowed to use a capability. */
static int cred_has_capability(const struct cred *cred,
- int cap, int audit, bool initns)
+ int cap, unsigned int opts, bool initns)
{
struct common_audit_data ad;
struct av_decision avd;
@@ -1648,7 +1604,7 @@ static int cred_has_capability(const struct cred *cred,
rc = avc_has_perm_noaudit(&selinux_state,
sid, sid, sclass, av, 0, &avd);
- if (audit == SECURITY_CAP_AUDIT) {
+ if (!(opts & CAP_OPT_NOAUDIT)) {
int rc2 = avc_audit(&selinux_state,
sid, sid, sclass, av, &avd, rc, &ad, 0);
if (rc2)
@@ -1674,7 +1630,7 @@ static int inode_has_perm(const struct cred *cred,
return 0;
sid = cred_sid(cred);
- isec = inode->i_security;
+ isec = selinux_inode(inode);
return avc_has_perm(&selinux_state,
sid, isec->sid, isec->sclass, perms, adp);
@@ -1740,7 +1696,7 @@ static int file_has_perm(const struct cred *cred,
struct file *file,
u32 av)
{
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct inode *inode = file_inode(file);
struct common_audit_data ad;
u32 sid = cred_sid(cred);
@@ -1806,7 +1762,7 @@ static int may_create(struct inode *dir,
struct dentry *dentry,
u16 tclass)
{
- const struct task_security_struct *tsec = current_security();
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
u32 sid, newsid;
@@ -1828,7 +1784,7 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- rc = selinux_determine_inode_label(current_security(), dir,
+ rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir,
&dentry->d_name, tclass, &newsid);
if (rc)
return rc;
@@ -2084,7 +2040,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
struct file *file)
{
u32 sid = task_sid(to);
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct dentry *dentry = file->f_path.dentry;
struct inode_security_struct *isec;
struct common_audit_data ad;
@@ -2168,9 +2124,9 @@ static int selinux_capset(struct cred *new, const struct cred *old,
*/
static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
- int cap, int audit)
+ int cap, unsigned int opts)
{
- return cred_has_capability(cred, cap, audit, ns == &init_user_ns);
+ return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
}
static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -2244,7 +2200,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
int rc, cap_sys_admin = 0;
rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
- SECURITY_CAP_NOAUDIT, true);
+ CAP_OPT_NOAUDIT, true);
if (rc == 0)
cap_sys_admin = 1;
@@ -2335,8 +2291,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
if (bprm->called_set_creds)
return 0;
- old_tsec = current_security();
- new_tsec = bprm->cred->security;
+ old_tsec = selinux_cred(current_cred());
+ new_tsec = selinux_cred(bprm->cred);
isec = inode_security(inode);
/* Default to the current task SID. */
@@ -2500,7 +2456,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
struct rlimit *rlim, *initrlim;
int rc, i;
- new_tsec = bprm->cred->security;
+ new_tsec = selinux_cred(bprm->cred);
if (new_tsec->sid == new_tsec->osid)
return;
@@ -2543,7 +2499,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
*/
static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
{
- const struct task_security_struct *tsec = current_security();
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
struct itimerval itimer;
u32 osid, sid;
int rc, i;
@@ -2780,7 +2736,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
u32 newsid;
int rc;
- rc = selinux_determine_inode_label(current_security(),
+ rc = selinux_determine_inode_label(selinux_cred(current_cred()),
d_inode(dentry->d_parent), name,
inode_mode_to_security_class(mode),
&newsid);
@@ -2800,14 +2756,14 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
int rc;
struct task_security_struct *tsec;
- rc = selinux_determine_inode_label(old->security,
+ rc = selinux_determine_inode_label(selinux_cred(old),
d_inode(dentry->d_parent), name,
inode_mode_to_security_class(mode),
&newsid);
if (rc)
return rc;
- tsec = new->security;
+ tsec = selinux_cred(new);
tsec->create_sid = newsid;
return 0;
}
@@ -2817,7 +2773,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
const char **name,
void **value, size_t *len)
{
- const struct task_security_struct *tsec = current_security();
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
struct superblock_security_struct *sbsec;
u32 newsid, clen;
int rc;
@@ -2827,7 +2783,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
newsid = tsec->create_sid;
- rc = selinux_determine_inode_label(current_security(),
+ rc = selinux_determine_inode_label(selinux_cred(current_cred()),
dir, qstr,
inode_mode_to_security_class(inode->i_mode),
&newsid);
@@ -2836,7 +2792,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
/* Possibly defer initialization to selinux_complete_init. */
if (sbsec->flags & SE_SBINITIALIZED) {
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
isec->sclass = inode_mode_to_security_class(inode->i_mode);
isec->sid = newsid;
isec->initialized = LABEL_INITIALIZED;
@@ -2936,7 +2892,7 @@ static noinline int audit_inode_permission(struct inode *inode,
unsigned flags)
{
struct common_audit_data ad;
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
int rc;
ad.type = LSM_AUDIT_DATA_INODE;
@@ -3031,11 +2987,11 @@ static int selinux_inode_getattr(const struct path *path)
static bool has_cap_mac_admin(bool audit)
{
const struct cred *cred = current_cred();
- int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT;
+ unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT;
- if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit))
+ if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts))
return false;
- if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true))
+ if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true))
return false;
return true;
}
@@ -3289,7 +3245,7 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
return -ENOMEM;
}
- tsec = new_creds->security;
+ tsec = selinux_cred(new_creds);
/* Get label from overlay inode and set it in create_sid */
selinux_inode_getsecid(d_inode(src), &sid);
tsec->create_sid = sid;
@@ -3330,7 +3286,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
static int selinux_file_permission(struct file *file, int mask)
{
struct inode *inode = file_inode(file);
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct inode_security_struct *isec;
u32 sid = current_sid();
@@ -3352,11 +3308,6 @@ static int selinux_file_alloc_security(struct file *file)
return file_alloc_security(file);
}
-static void selinux_file_free_security(struct file *file)
-{
- file_free_security(file);
-}
-
/*
* Check whether a task has the ioctl permission and cmd
* operation to an inode.
@@ -3365,7 +3316,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
u32 requested, u16 cmd)
{
struct common_audit_data ad;
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
struct inode *inode = file_inode(file);
struct inode_security_struct *isec;
struct lsm_ioctlop_audit ioctl;
@@ -3435,7 +3386,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
case KDSKBENT:
case KDSKBSENT:
error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
- SECURITY_CAP_AUDIT, true);
+ CAP_OPT_NONE, true);
break;
/* default case assumes that the command will go
@@ -3617,7 +3568,7 @@ static void selinux_file_set_fowner(struct file *file)
{
struct file_security_struct *fsec;
- fsec = file->f_security;
+ fsec = selinux_file(file);
fsec->fown_sid = current_sid();
}
@@ -3632,7 +3583,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
/* struct fown_struct is never outside the context of a struct file */
file = container_of(fown, struct file, f_owner);
- fsec = file->f_security;
+ fsec = selinux_file(file);
if (!signum)
perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
@@ -3656,7 +3607,7 @@ static int selinux_file_open(struct file *file)
struct file_security_struct *fsec;
struct inode_security_struct *isec;
- fsec = file->f_security;
+ fsec = selinux_file(file);
isec = inode_security(file_inode(file));
/*
* Save inode label and policy sequence number
@@ -3690,52 +3641,15 @@ static int selinux_task_alloc(struct task_struct *task,
}
/*
- * allocate the SELinux part of blank credentials
- */
-static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
-{
- struct task_security_struct *tsec;
-
- tsec = kzalloc(sizeof(struct task_security_struct), gfp);
- if (!tsec)
- return -ENOMEM;
-
- cred->security = tsec;
- return 0;
-}
-
-/*
- * detach and free the LSM part of a set of credentials
- */
-static void selinux_cred_free(struct cred *cred)
-{
- struct task_security_struct *tsec = cred->security;
-
- /*
- * cred->security == NULL if security_cred_alloc_blank() or
- * security_prepare_creds() returned an error.
- */
- BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
- cred->security = (void *) 0x7UL;
- kfree(tsec);
-}
-
-/*
* prepare a new set of credentials for modification
*/
static int selinux_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
- const struct task_security_struct *old_tsec;
- struct task_security_struct *tsec;
-
- old_tsec = old->security;
+ const struct task_security_struct *old_tsec = selinux_cred(old);
+ struct task_security_struct *tsec = selinux_cred(new);
- tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
- if (!tsec)
- return -ENOMEM;
-
- new->security = tsec;
+ *tsec = *old_tsec;
return 0;
}
@@ -3744,8 +3658,8 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
*/
static void selinux_cred_transfer(struct cred *new, const struct cred *old)
{
- const struct task_security_struct *old_tsec = old->security;
- struct task_security_struct *tsec = new->security;
+ const struct task_security_struct *old_tsec = selinux_cred(old);
+ struct task_security_struct *tsec = selinux_cred(new);
*tsec = *old_tsec;
}
@@ -3761,7 +3675,7 @@ static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
*/
static int selinux_kernel_act_as(struct cred *new, u32 secid)
{
- struct task_security_struct *tsec = new->security;
+ struct task_security_struct *tsec = selinux_cred(new);
u32 sid = current_sid();
int ret;
@@ -3786,7 +3700,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
{
struct inode_security_struct *isec = inode_security(inode);
- struct task_security_struct *tsec = new->security;
+ struct task_security_struct *tsec = selinux_cred(new);
u32 sid = current_sid();
int ret;
@@ -3832,7 +3746,7 @@ static int selinux_kernel_module_from_file(struct file *file)
ad.type = LSM_AUDIT_DATA_FILE;
ad.u.file = file;
- fsec = file->f_security;
+ fsec = selinux_file(file);
if (sid != fsec->sid) {
rc = avc_has_perm(&selinux_state,
sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
@@ -3998,7 +3912,7 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
static void selinux_task_to_inode(struct task_struct *p,
struct inode *inode)
{
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
u32 sid = task_sid(p);
spin_lock(&isec->lock);
@@ -4335,7 +4249,7 @@ static int sock_has_perm(struct sock *sk, u32 perms)
static int selinux_socket_create(int family, int type,
int protocol, int kern)
{
- const struct task_security_struct *tsec = current_security();
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
u32 newsid;
u16 secclass;
int rc;
@@ -4355,7 +4269,7 @@ static int selinux_socket_create(int family, int type,
static int selinux_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern)
{
- const struct task_security_struct *tsec = current_security();
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
struct sk_security_struct *sksec;
u16 sclass = socket_type_to_security_class(family, type, protocol);
@@ -5236,7 +5150,7 @@ static int selinux_secmark_relabel_packet(u32 sid)
const struct task_security_struct *__tsec;
u32 tsid;
- __tsec = current_security();
+ __tsec = selinux_cred(current_cred());
tsid = __tsec->sid;
return avc_has_perm(&selinux_state,
@@ -5711,51 +5625,22 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
return selinux_nlmsg_perm(sk, skb);
}
-static int ipc_alloc_security(struct kern_ipc_perm *perm,
- u16 sclass)
+static void ipc_init_security(struct ipc_security_struct *isec, u16 sclass)
{
- struct ipc_security_struct *isec;
-
- isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
- if (!isec)
- return -ENOMEM;
-
isec->sclass = sclass;
isec->sid = current_sid();
- perm->security = isec;
-
- return 0;
-}
-
-static void ipc_free_security(struct kern_ipc_perm *perm)
-{
- struct ipc_security_struct *isec = perm->security;
- perm->security = NULL;
- kfree(isec);
}
static int msg_msg_alloc_security(struct msg_msg *msg)
{
struct msg_security_struct *msec;
- msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
- if (!msec)
- return -ENOMEM;
-
+ msec = selinux_msg_msg(msg);
msec->sid = SECINITSID_UNLABELED;
- msg->security = msec;
return 0;
}
-static void msg_msg_free_security(struct msg_msg *msg)
-{
- struct msg_security_struct *msec = msg->security;
-
- msg->security = NULL;
- kfree(msec);
-}
-
static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
u32 perms)
{
@@ -5763,7 +5648,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
struct common_audit_data ad;
u32 sid = current_sid();
- isec = ipc_perms->security;
+ isec = selinux_ipc(ipc_perms);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = ipc_perms->key;
@@ -5777,11 +5662,6 @@ static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
return msg_msg_alloc_security(msg);
}
-static void selinux_msg_msg_free_security(struct msg_msg *msg)
-{
- msg_msg_free_security(msg);
-}
-
/* message queue security operations */
static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
{
@@ -5790,11 +5670,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
u32 sid = current_sid();
int rc;
- rc = ipc_alloc_security(msq, SECCLASS_MSGQ);
- if (rc)
- return rc;
-
- isec = msq->security;
+ isec = selinux_ipc(msq);
+ ipc_init_security(isec, SECCLASS_MSGQ);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
@@ -5802,16 +5679,7 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
rc = avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_MSGQ,
MSGQ__CREATE, &ad);
- if (rc) {
- ipc_free_security(msq);
- return rc;
- }
- return 0;
-}
-
-static void selinux_msg_queue_free_security(struct kern_ipc_perm *msq)
-{
- ipc_free_security(msq);
+ return rc;
}
static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
@@ -5820,7 +5688,7 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
struct common_audit_data ad;
u32 sid = current_sid();
- isec = msq->security;
+ isec = selinux_ipc(msq);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
@@ -5869,8 +5737,8 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
u32 sid = current_sid();
int rc;
- isec = msq->security;
- msec = msg->security;
+ isec = selinux_ipc(msq);
+ msec = selinux_msg_msg(msg);
/*
* First time through, need to assign label to the message
@@ -5917,8 +5785,8 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
u32 sid = task_sid(target);
int rc;
- isec = msq->security;
- msec = msg->security;
+ isec = selinux_ipc(msq);
+ msec = selinux_msg_msg(msg);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = msq->key;
@@ -5941,11 +5809,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
u32 sid = current_sid();
int rc;
- rc = ipc_alloc_security(shp, SECCLASS_SHM);
- if (rc)
- return rc;
-
- isec = shp->security;
+ isec = selinux_ipc(shp);
+ ipc_init_security(isec, SECCLASS_SHM);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
@@ -5953,16 +5818,7 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
rc = avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_SHM,
SHM__CREATE, &ad);
- if (rc) {
- ipc_free_security(shp);
- return rc;
- }
- return 0;
-}
-
-static void selinux_shm_free_security(struct kern_ipc_perm *shp)
-{
- ipc_free_security(shp);
+ return rc;
}
static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
@@ -5971,7 +5827,7 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
struct common_audit_data ad;
u32 sid = current_sid();
- isec = shp->security;
+ isec = selinux_ipc(shp);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = shp->key;
@@ -6038,11 +5894,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
u32 sid = current_sid();
int rc;
- rc = ipc_alloc_security(sma, SECCLASS_SEM);
- if (rc)
- return rc;
-
- isec = sma->security;
+ isec = selinux_ipc(sma);
+ ipc_init_security(isec, SECCLASS_SEM);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
@@ -6050,16 +5903,7 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
rc = avc_has_perm(&selinux_state,
sid, isec->sid, SECCLASS_SEM,
SEM__CREATE, &ad);
- if (rc) {
- ipc_free_security(sma);
- return rc;
- }
- return 0;
-}
-
-static void selinux_sem_free_security(struct kern_ipc_perm *sma)
-{
- ipc_free_security(sma);
+ return rc;
}
static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
@@ -6068,7 +5912,7 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
struct common_audit_data ad;
u32 sid = current_sid();
- isec = sma->security;
+ isec = selinux_ipc(sma);
ad.type = LSM_AUDIT_DATA_IPC;
ad.u.ipc_id = sma->key;
@@ -6154,7 +5998,7 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
{
- struct ipc_security_struct *isec = ipcp->security;
+ struct ipc_security_struct *isec = selinux_ipc(ipcp);
*secid = isec->sid;
}
@@ -6173,7 +6017,7 @@ static int selinux_getprocattr(struct task_struct *p,
unsigned len;
rcu_read_lock();
- __tsec = __task_cred(p)->security;
+ __tsec = selinux_cred(__task_cred(p));
if (current != p) {
error = avc_has_perm(&selinux_state,
@@ -6296,7 +6140,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
operation. See selinux_bprm_set_creds for the execve
checks and may_create for the file creation checks. The
operation will then fail if the context is not permitted. */
- tsec = new->security;
+ tsec = selinux_cred(new);
if (!strcmp(name, "exec")) {
tsec->exec_sid = sid;
} else if (!strcmp(name, "fscreate")) {
@@ -6380,7 +6224,7 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
static void selinux_inode_invalidate_secctx(struct inode *inode)
{
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
spin_lock(&isec->lock);
isec->initialized = LABEL_INVALID;
@@ -6425,7 +6269,7 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
if (!ksec)
return -ENOMEM;
- tsec = cred->security;
+ tsec = selinux_cred(cred);
if (tsec->keycreate_sid)
ksec->sid = tsec->keycreate_sid;
else
@@ -6688,6 +6532,14 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
}
#endif
+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),
+ .lbs_inode = sizeof(struct inode_security_struct),
+ .lbs_ipc = sizeof(struct ipc_security_struct),
+ .lbs_msg_msg = sizeof(struct msg_security_struct),
+};
+
static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6757,7 +6609,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
- LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
@@ -6771,8 +6622,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(file_open, selinux_file_open),
LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
- LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
- LSM_HOOK_INIT(cred_free, selinux_cred_free),
LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
@@ -6800,24 +6649,20 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
- LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security),
LSM_HOOK_INIT(msg_queue_alloc_security,
selinux_msg_queue_alloc_security),
- LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security),
LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
- LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security),
LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
- LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security),
LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
@@ -6928,16 +6773,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
static __init int selinux_init(void)
{
- if (!security_module_enable("selinux")) {
- selinux_enabled = 0;
- return 0;
- }
-
- if (!selinux_enabled) {
- pr_info("SELinux: Disabled at boot.\n");
- return 0;
- }
-
pr_info("SELinux: Initializing.\n");
memset(&selinux_state, 0, sizeof(selinux_state));
@@ -6951,12 +6786,6 @@ static __init int selinux_init(void)
default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
- sel_inode_cache = kmem_cache_create("selinux_inode_security",
- sizeof(struct inode_security_struct),
- 0, SLAB_PANIC, NULL);
- file_security_cache = kmem_cache_create("selinux_file_security",
- sizeof(struct file_security_struct),
- 0, SLAB_PANIC, NULL);
avc_init();
avtab_cache_init();
@@ -6999,6 +6828,9 @@ void selinux_complete_init(void)
all processes and objects when they are created. */
DEFINE_LSM(selinux) = {
.name = "selinux",
+ .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+ .enabled = &selinux_enabled,
+ .blobs = &selinux_blob_sizes,
.init = selinux_init,
};
diff --git a/security/selinux/include/audit.h b/security/selinux/include/audit.h
index 1bdf973433cc..36e1d44c0209 100644
--- a/security/selinux/include/audit.h
+++ b/security/selinux/include/audit.h
@@ -1,9 +1,6 @@
/*
* SELinux support for the Audit LSM hooks
*
- * Most of below header was moved from include/linux/selinux.h which
- * is released under below copyrights:
- *
* Author: James Morris <jmorris@redhat.com>
*
* Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index cc5e26b0161b..231262d8eac9 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -25,6 +25,8 @@
#include <linux/binfmts.h>
#include <linux/in.h>
#include <linux/spinlock.h>
+#include <linux/lsm_hooks.h>
+#include <linux/msg.h>
#include <net/net_namespace.h>
#include "flask.h"
#include "avc.h"
@@ -56,10 +58,7 @@ enum label_initialized {
struct inode_security_struct {
struct inode *inode; /* back pointer to inode object */
- union {
- struct list_head list; /* list of inode_security_struct */
- struct rcu_head rcu; /* for freeing the inode_security_struct */
- };
+ struct list_head list; /* list of inode_security_struct */
u32 task_sid; /* SID of creating task */
u32 sid; /* SID of this object */
u16 sclass; /* security class of this object */
@@ -158,4 +157,35 @@ struct bpf_security_struct {
u32 sid; /*SID of bpf obj creater*/
};
+extern struct lsm_blob_sizes selinux_blob_sizes;
+static inline struct task_security_struct *selinux_cred(const struct cred *cred)
+{
+ return cred->security + selinux_blob_sizes.lbs_cred;
+}
+
+static inline struct file_security_struct *selinux_file(const struct file *file)
+{
+ return file->f_security + selinux_blob_sizes.lbs_file;
+}
+
+static inline struct inode_security_struct *selinux_inode(
+ const struct inode *inode)
+{
+ if (unlikely(!inode->i_security))
+ return NULL;
+ return inode->i_security + selinux_blob_sizes.lbs_inode;
+}
+
+static inline struct msg_security_struct *selinux_msg_msg(
+ const struct msg_msg *msg_msg)
+{
+ return msg_msg->security + selinux_blob_sizes.lbs_msg_msg;
+}
+
+static inline struct ipc_security_struct *selinux_ipc(
+ const struct kern_ipc_perm *ipc)
+{
+ return ipc->security + selinux_blob_sizes.lbs_ipc;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index f3a5a138a096..145ee62f205a 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1378,7 +1378,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
goto out;
}
- isec = (struct inode_security_struct *)inode->i_security;
+ isec = selinux_inode(inode);
ret = security_genfs_sid(fsi->state, "selinuxfs", page,
SECCLASS_FILE, &sid);
if (ret) {
@@ -1953,7 +1953,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
}
inode->i_ino = ++fsi->last_ino;
- isec = (struct inode_security_struct *)inode->i_security;
+ isec = selinux_inode(inode);
isec->sid = SECINITSID_DEVNULL;
isec->sclass = SECCLASS_CHR_FILE;
isec->initialized = LABEL_INITIALIZED;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index dd44126c8d14..d6e7b4856d93 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -49,7 +49,6 @@
#include <linux/sched.h>
#include <linux/audit.h>
#include <linux/mutex.h>
-#include <linux/selinux.h>
#include <linux/flex_array.h>
#include <linux/vmalloc.h>
#include <net/netlabel.h>
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index bd7d18bdb147..7c57cb7e4146 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -79,7 +79,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
gfp_t gfp)
{
int rc;
- const struct task_security_struct *tsec = current_security();
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
struct xfrm_sec_ctx *ctx = NULL;
u32 str_len;
@@ -138,7 +138,7 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
*/
static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
{
- const struct task_security_struct *tsec = current_security();
+ const struct task_security_struct *tsec = selinux_cred(current_cred());
if (!ctx)
return 0;
diff --git a/security/smack/smack.h b/security/smack/smack.h
index f7db791fb566..9c7c95a5c497 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -24,6 +24,7 @@
#include <linux/list.h>
#include <linux/rculist.h>
#include <linux/lsm_audit.h>
+#include <linux/msg.h>
/*
* Use IPv6 port labeling if IPv6 is enabled and secmarks
@@ -336,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;
@@ -356,12 +358,38 @@ extern struct list_head smack_onlycap_list;
#define SMACK_HASH_SLOTS 16
extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
+static inline struct task_smack *smack_cred(const struct cred *cred)
+{
+ return cred->security + smack_blob_sizes.lbs_cred;
+}
+
+static inline struct smack_known **smack_file(const struct file *file)
+{
+ return (struct smack_known **)(file->f_security +
+ smack_blob_sizes.lbs_file);
+}
+
+static inline struct inode_smack *smack_inode(const struct inode *inode)
+{
+ return inode->i_security + smack_blob_sizes.lbs_inode;
+}
+
+static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg)
+{
+ return msg->security + smack_blob_sizes.lbs_msg_msg;
+}
+
+static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
+{
+ return ipc->security + smack_blob_sizes.lbs_ipc;
+}
+
/*
* Is the directory transmuting?
*/
static inline int smk_inode_transmutable(const struct inode *isp)
{
- struct inode_smack *sip = isp->i_security;
+ struct inode_smack *sip = smack_inode(isp);
return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
}
@@ -370,7 +398,7 @@ static inline int smk_inode_transmutable(const struct inode *isp)
*/
static inline struct smack_known *smk_of_inode(const struct inode *isp)
{
- struct inode_smack *sip = isp->i_security;
+ struct inode_smack *sip = smack_inode(isp);
return sip->smk_inode;
}
@@ -382,13 +410,19 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
return tsp->smk_task;
}
-static inline struct smack_known *smk_of_task_struct(const struct task_struct *t)
+static inline struct smack_known *smk_of_task_struct(
+ const struct task_struct *t)
{
struct smack_known *skp;
+ const struct cred *cred;
rcu_read_lock();
- skp = smk_of_task(__task_cred(t)->security);
+
+ cred = __task_cred(t);
+ skp = smk_of_task(smack_cred(cred));
+
rcu_read_unlock();
+
return skp;
}
@@ -405,7 +439,7 @@ static inline struct smack_known *smk_of_forked(const struct task_smack *tsp)
*/
static inline struct smack_known *smk_of_current(void)
{
- return smk_of_task(current_security());
+ return smk_of_task(smack_cred(current_cred()));
}
/*
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 9a4c0ad46518..fe2ce3a65822 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -275,7 +275,7 @@ out_audit:
int smk_curacc(struct smack_known *obj_known,
u32 mode, struct smk_audit_info *a)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_tskacc(tsp, obj_known, mode, a);
}
@@ -635,12 +635,12 @@ DEFINE_MUTEX(smack_onlycap_lock);
*/
bool smack_privileged_cred(int cap, const struct cred *cred)
{
- struct task_smack *tsp = cred->security;
+ struct task_smack *tsp = smack_cred(cred);
struct smack_known *skp = tsp->smk_task;
struct smack_known_list_elem *sklep;
int rc;
- rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT);
+ rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE);
if (rc)
return false;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 430d4f35e55c..2309c696c6c8 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -139,7 +139,7 @@ static int smk_bu_note(char *note, struct smack_known *sskp,
static int smk_bu_current(char *note, struct smack_known *oskp,
int mode, int rc)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (rc <= 0)
@@ -160,7 +160,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_task(struct task_struct *otp, int mode, int rc)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
struct smack_known *smk_task = smk_of_task_struct(otp);
char acc[SMK_NUM_ACCESS_TYPE + 1];
@@ -182,8 +182,8 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc)
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_inode(struct inode *inode, int mode, int rc)
{
- struct task_smack *tsp = current_security();
- struct inode_smack *isp = inode->i_security;
+ struct task_smack *tsp = smack_cred(current_cred());
+ struct inode_smack *isp = smack_inode(inode);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (isp->smk_flags & SMK_INODE_IMPURE)
@@ -212,10 +212,10 @@ static int smk_bu_inode(struct inode *inode, int mode, int rc)
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_file(struct file *file, int mode, int rc)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
struct smack_known *sskp = tsp->smk_task;
struct inode *inode = file_inode(file);
- struct inode_smack *isp = inode->i_security;
+ struct inode_smack *isp = smack_inode(inode);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (isp->smk_flags & SMK_INODE_IMPURE)
@@ -242,10 +242,10 @@ static int smk_bu_file(struct file *file, int mode, int rc)
static int smk_bu_credfile(const struct cred *cred, struct file *file,
int mode, int rc)
{
- struct task_smack *tsp = cred->security;
+ struct task_smack *tsp = smack_cred(cred);
struct smack_known *sskp = tsp->smk_task;
struct inode *inode = file_inode(file);
- struct inode_smack *isp = inode->i_security;
+ struct inode_smack *isp = smack_inode(inode);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (isp->smk_flags & SMK_INODE_IMPURE)
@@ -305,50 +305,35 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
}
/**
- * new_inode_smack - allocate an inode security blob
+ * init_inode_smack - initialize an inode security blob
+ * @isp: the blob to initialize
* @skp: a pointer to the Smack label entry to use in the blob
*
- * Returns the new blob or NULL if there's no memory available
*/
-static struct inode_smack *new_inode_smack(struct smack_known *skp)
+static void init_inode_smack(struct inode *inode, struct smack_known *skp)
{
- struct inode_smack *isp;
-
- isp = kmem_cache_zalloc(smack_inode_cache, GFP_NOFS);
- if (isp == NULL)
- return NULL;
+ struct inode_smack *isp = smack_inode(inode);
isp->smk_inode = skp;
isp->smk_flags = 0;
mutex_init(&isp->smk_lock);
-
- return isp;
}
/**
- * new_task_smack - allocate a task security blob
+ * init_task_smack - initialize a task security blob
+ * @tsp: blob to initialize
* @task: a pointer to the Smack label for the running task
* @forked: a pointer to the Smack label for the forked task
- * @gfp: type of the memory for the allocation
*
- * Returns the new blob or NULL if there's no memory available
*/
-static struct task_smack *new_task_smack(struct smack_known *task,
- struct smack_known *forked, gfp_t gfp)
+static void init_task_smack(struct task_smack *tsp, struct smack_known *task,
+ struct smack_known *forked)
{
- struct task_smack *tsp;
-
- tsp = kzalloc(sizeof(struct task_smack), gfp);
- if (tsp == NULL)
- return NULL;
-
tsp->smk_task = task;
tsp->smk_forked = forked;
INIT_LIST_HEAD(&tsp->smk_rules);
INIT_LIST_HEAD(&tsp->smk_relabel);
mutex_init(&tsp->smk_rules_lock);
-
- return tsp;
}
/**
@@ -448,7 +433,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
rcu_read_lock();
tracercred = __task_cred(tracer);
- tsp = tracercred->security;
+ tsp = smack_cred(tracercred);
tracer_known = smk_of_task(tsp);
if ((mode & PTRACE_MODE_ATTACH) &&
@@ -515,7 +500,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
int rc;
struct smack_known *skp;
- skp = smk_of_task(current_security());
+ skp = smk_of_task(smack_cred(current_cred()));
rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
return rc;
@@ -718,6 +703,13 @@ static int smack_set_mnt_opts(struct super_block *sb,
if (sp->smk_flags & SMK_SB_INITIALIZED)
return 0;
+ if (inode->i_security == NULL) {
+ int rc = lsm_inode_alloc(inode);
+
+ if (rc)
+ return rc;
+ }
+
if (!smack_privileged(CAP_MAC_ADMIN)) {
/*
* Unprivileged mounts don't get to specify Smack values.
@@ -782,17 +774,12 @@ static int smack_set_mnt_opts(struct super_block *sb,
/*
* Initialize the root inode.
*/
- isp = inode->i_security;
- if (isp == NULL) {
- isp = new_inode_smack(sp->smk_root);
- if (isp == NULL)
- return -ENOMEM;
- inode->i_security = isp;
- } else
- isp->smk_inode = sp->smk_root;
+ init_inode_smack(inode, sp->smk_root);
- if (transmute)
+ if (transmute) {
+ isp = smack_inode(inode);
isp->smk_flags |= SMK_INODE_TRANSMUTE;
+ }
return 0;
}
@@ -831,7 +818,7 @@ static int smack_sb_statfs(struct dentry *dentry)
static int smack_bprm_set_creds(struct linux_binprm *bprm)
{
struct inode *inode = file_inode(bprm->file);
- struct task_smack *bsp = bprm->cred->security;
+ struct task_smack *bsp = smack_cred(bprm->cred);
struct inode_smack *isp;
struct superblock_smack *sbsp;
int rc;
@@ -839,7 +826,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
if (bprm->called_set_creds)
return 0;
- isp = inode->i_security;
+ isp = smack_inode(inode);
if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
return 0;
@@ -890,49 +877,11 @@ static int smack_inode_alloc_security(struct inode *inode)
{
struct smack_known *skp = smk_of_current();
- inode->i_security = new_inode_smack(skp);
- if (inode->i_security == NULL)
- return -ENOMEM;
+ init_inode_smack(inode, skp);
return 0;
}
/**
- * smack_inode_free_rcu - Free inode_smack blob from cache
- * @head: the rcu_head for getting inode_smack pointer
- *
- * Call back function called from call_rcu() to free
- * the i_security blob pointer in inode
- */
-static void smack_inode_free_rcu(struct rcu_head *head)
-{
- struct inode_smack *issp;
-
- issp = container_of(head, struct inode_smack, smk_rcu);
- kmem_cache_free(smack_inode_cache, issp);
-}
-
-/**
- * smack_inode_free_security - free an inode blob using call_rcu()
- * @inode: the inode with a blob
- *
- * Clears the blob pointer in inode using RCU
- */
-static void smack_inode_free_security(struct inode *inode)
-{
- struct inode_smack *issp = inode->i_security;
-
- /*
- * The inode may still be referenced in a path walk and
- * a call to smack_inode_permission() can be made
- * after smack_inode_free_security() is called.
- * To avoid race condition free the i_security via RCU
- * and leave the current inode->i_security pointer intact.
- * The inode will be freed after the RCU grace period too.
- */
- call_rcu(&issp->smk_rcu, smack_inode_free_rcu);
-}
-
-/**
* smack_inode_init_security - copy out the smack from an inode
* @inode: the newly created inode
* @dir: containing directory object
@@ -947,7 +896,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, const char **name,
void **value, size_t *len)
{
- struct inode_smack *issp = inode->i_security;
+ struct inode_smack *issp = smack_inode(inode);
struct smack_known *skp = smk_of_current();
struct smack_known *isp = smk_of_inode(inode);
struct smack_known *dsp = smk_of_inode(dir);
@@ -1285,7 +1234,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
struct smack_known *skp;
- struct inode_smack *isp = d_backing_inode(dentry)->i_security;
+ struct inode_smack *isp = smack_inode(d_backing_inode(dentry));
if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
isp->smk_flags |= SMK_INODE_TRANSMUTE;
@@ -1366,7 +1315,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
if (rc != 0)
return rc;
- isp = d_backing_inode(dentry)->i_security;
+ isp = smack_inode(d_backing_inode(dentry));
/*
* Don't do anything special for these.
* XATTR_NAME_SMACKIPIN
@@ -1498,25 +1447,13 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid)
*/
static int smack_file_alloc_security(struct file *file)
{
- struct smack_known *skp = smk_of_current();
+ struct smack_known **blob = smack_file(file);
- file->f_security = skp;
+ *blob = smk_of_current();
return 0;
}
/**
- * smack_file_free_security - clear a file security blob
- * @file: the object
- *
- * The security blob for a file is a pointer to the master
- * label list, so no memory is freed.
- */
-static void smack_file_free_security(struct file *file)
-{
- file->f_security = NULL;
-}
-
-/**
* smack_file_ioctl - Smack check on ioctls
* @file: the object
* @cmd: what to do
@@ -1653,7 +1590,7 @@ static int smack_mmap_file(struct file *file,
if (unlikely(IS_PRIVATE(file_inode(file))))
return 0;
- isp = file_inode(file)->i_security;
+ isp = smack_inode(file_inode(file));
if (isp->smk_mmap == NULL)
return 0;
sbsp = file_inode(file)->i_sb->s_security;
@@ -1662,7 +1599,7 @@ static int smack_mmap_file(struct file *file,
return -EACCES;
mkp = isp->smk_mmap;
- tsp = current_security();
+ tsp = smack_cred(current_cred());
skp = smk_of_current();
rc = 0;
@@ -1740,7 +1677,9 @@ static int smack_mmap_file(struct file *file,
*/
static void smack_file_set_fowner(struct file *file)
{
- file->f_security = smk_of_current();
+ struct smack_known **blob = smack_file(file);
+
+ *blob = smk_of_current();
}
/**
@@ -1757,8 +1696,9 @@ static void smack_file_set_fowner(struct file *file)
static int smack_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
+ struct smack_known **blob;
struct smack_known *skp;
- struct smack_known *tkp = smk_of_task(tsk->cred->security);
+ struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred));
const struct cred *tcred;
struct file *file;
int rc;
@@ -1770,7 +1710,8 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
file = container_of(fown, struct file, f_owner);
/* we don't log here as rc can be overriden */
- skp = file->f_security;
+ blob = smack_file(file);
+ skp = *blob;
rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
@@ -1811,7 +1752,7 @@ static int smack_file_receive(struct file *file)
if (inode->i_sb->s_magic == SOCKFS_MAGIC) {
sock = SOCKET_I(inode);
ssp = sock->sk->sk_security;
- tsp = current_security();
+ tsp = smack_cred(current_cred());
/*
* If the receiving process can't write to the
* passed socket or if the passed socket can't
@@ -1853,7 +1794,7 @@ static int smack_file_receive(struct file *file)
*/
static int smack_file_open(struct file *file)
{
- struct task_smack *tsp = file->f_cred->security;
+ struct task_smack *tsp = smack_cred(file->f_cred);
struct inode *inode = file_inode(file);
struct smk_audit_info ad;
int rc;
@@ -1881,14 +1822,7 @@ static int smack_file_open(struct file *file)
*/
static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
- struct task_smack *tsp;
-
- tsp = new_task_smack(NULL, NULL, gfp);
- if (tsp == NULL)
- return -ENOMEM;
-
- cred->security = tsp;
-
+ init_task_smack(smack_cred(cred), NULL, NULL);
return 0;
}
@@ -1900,15 +1834,11 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
*/
static void smack_cred_free(struct cred *cred)
{
- struct task_smack *tsp = cred->security;
+ struct task_smack *tsp = smack_cred(cred);
struct smack_rule *rp;
struct list_head *l;
struct list_head *n;
- if (tsp == NULL)
- return;
- cred->security = NULL;
-
smk_destroy_label_list(&tsp->smk_relabel);
list_for_each_safe(l, n, &tsp->smk_rules) {
@@ -1916,7 +1846,6 @@ static void smack_cred_free(struct cred *cred)
list_del(&rp->list);
kfree(rp);
}
- kfree(tsp);
}
/**
@@ -1930,15 +1859,11 @@ static void smack_cred_free(struct cred *cred)
static int smack_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
- struct task_smack *old_tsp = old->security;
- struct task_smack *new_tsp;
+ struct task_smack *old_tsp = smack_cred(old);
+ struct task_smack *new_tsp = smack_cred(new);
int rc;
- new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp);
- if (new_tsp == NULL)
- return -ENOMEM;
-
- new->security = new_tsp;
+ init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task);
rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp);
if (rc != 0)
@@ -1946,10 +1871,7 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
gfp);
- if (rc != 0)
- return rc;
-
- return 0;
+ return rc;
}
/**
@@ -1961,15 +1883,14 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
*/
static void smack_cred_transfer(struct cred *new, const struct cred *old)
{
- struct task_smack *old_tsp = old->security;
- struct task_smack *new_tsp = new->security;
+ struct task_smack *old_tsp = smack_cred(old);
+ struct task_smack *new_tsp = smack_cred(new);
new_tsp->smk_task = old_tsp->smk_task;
new_tsp->smk_forked = old_tsp->smk_task;
mutex_init(&new_tsp->smk_rules_lock);
INIT_LIST_HEAD(&new_tsp->smk_rules);
-
/* cbs copy rule list */
}
@@ -1980,12 +1901,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
*
* Sets the secid to contain a u32 version of the smack label.
*/
-static void smack_cred_getsecid(const struct cred *c, u32 *secid)
+static void smack_cred_getsecid(const struct cred *cred, u32 *secid)
{
struct smack_known *skp;
rcu_read_lock();
- skp = smk_of_task(c->security);
+ skp = smk_of_task(smack_cred(cred));
*secid = skp->smk_secid;
rcu_read_unlock();
}
@@ -1999,7 +1920,7 @@ static void smack_cred_getsecid(const struct cred *c, u32 *secid)
*/
static int smack_kernel_act_as(struct cred *new, u32 secid)
{
- struct task_smack *new_tsp = new->security;
+ struct task_smack *new_tsp = smack_cred(new);
new_tsp->smk_task = smack_from_secid(secid);
return 0;
@@ -2016,8 +1937,8 @@ static int smack_kernel_act_as(struct cred *new, u32 secid)
static int smack_kernel_create_files_as(struct cred *new,
struct inode *inode)
{
- struct inode_smack *isp = inode->i_security;
- struct task_smack *tsp = new->security;
+ struct inode_smack *isp = smack_inode(inode);
+ struct task_smack *tsp = smack_cred(new);
tsp->smk_forked = isp->smk_inode;
tsp->smk_task = tsp->smk_forked;
@@ -2201,7 +2122,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
* specific behavior. This is not clean. For one thing
* we can't take privilege into account.
*/
- skp = smk_of_task(cred->security);
+ skp = smk_of_task(smack_cred(cred));
rc = smk_access(skp, tkp, MAY_DELIVER, &ad);
rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc);
return rc;
@@ -2216,7 +2137,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
*/
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{
- struct inode_smack *isp = inode->i_security;
+ struct inode_smack *isp = smack_inode(inode);
struct smack_known *skp = smk_of_task_struct(p);
isp->smk_inode = skp;
@@ -2679,7 +2600,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
const void *value, size_t size, int flags)
{
struct smack_known *skp;
- struct inode_smack *nsp = inode->i_security;
+ struct inode_smack *nsp = smack_inode(inode);
struct socket_smack *ssp;
struct socket *sock;
int rc = 0;
@@ -2888,24 +2809,13 @@ static int smack_flags_to_may(int flags)
*/
static int smack_msg_msg_alloc_security(struct msg_msg *msg)
{
- struct smack_known *skp = smk_of_current();
+ struct smack_known **blob = smack_msg_msg(msg);
- msg->security = skp;
+ *blob = smk_of_current();
return 0;
}
/**
- * smack_msg_msg_free_security - Clear the security blob for msg_msg
- * @msg: the object
- *
- * Clears the blob pointer
- */
-static void smack_msg_msg_free_security(struct msg_msg *msg)
-{
- msg->security = NULL;
-}
-
-/**
* smack_of_ipc - the smack pointer for the ipc
* @isp: the object
*
@@ -2913,7 +2823,9 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
*/
static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp)
{
- return (struct smack_known *)isp->security;
+ struct smack_known **blob = smack_ipc(isp);
+
+ return *blob;
}
/**
@@ -2924,24 +2836,13 @@ static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp)
*/
static int smack_ipc_alloc_security(struct kern_ipc_perm *isp)
{
- struct smack_known *skp = smk_of_current();
+ struct smack_known **blob = smack_ipc(isp);
- isp->security = skp;
+ *blob = smk_of_current();
return 0;
}
/**
- * smack_ipc_free_security - Clear the security blob for ipc
- * @isp: the object
- *
- * Clears the blob pointer
- */
-static void smack_ipc_free_security(struct kern_ipc_perm *isp)
-{
- isp->security = NULL;
-}
-
-/**
* smk_curacc_shm : check if current has access on shm
* @isp : the object
* @access : access requested
@@ -3238,7 +3139,8 @@ static int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp, struct msg_msg *msg
*/
static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
{
- struct smack_known *iskp = ipp->security;
+ struct smack_known **blob = smack_ipc(ipp);
+ struct smack_known *iskp = *blob;
int may = smack_flags_to_may(flag);
struct smk_audit_info ad;
int rc;
@@ -3259,7 +3161,8 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
*/
static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
{
- struct smack_known *iskp = ipp->security;
+ struct smack_known **blob = smack_ipc(ipp);
+ struct smack_known *iskp = *blob;
*secid = iskp->smk_secid;
}
@@ -3287,7 +3190,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
if (inode == NULL)
return;
- isp = inode->i_security;
+ isp = smack_inode(inode);
mutex_lock(&isp->smk_lock);
/*
@@ -3390,13 +3293,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
final = &smack_known_star;
/*
- * Fall through.
- *
* If a smack value has been set we want to use it,
* but since tmpfs isn't giving us the opportunity
* to set mount options simulate setting the
* superblock default.
*/
+ /* Fall through */
default:
/*
* This isn't an understood special case.
@@ -3528,7 +3430,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
*/
static int smack_setprocattr(const char *name, void *value, size_t size)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
struct cred *new;
struct smack_known *skp;
struct smack_known_list_elem *sklep;
@@ -3569,7 +3471,7 @@ static int smack_setprocattr(const char *name, void *value, size_t size)
if (new == NULL)
return -ENOMEM;
- tsp = new->security;
+ tsp = smack_cred(new);
tsp->smk_task = skp;
/*
* process can change its label only once
@@ -4214,7 +4116,7 @@ static void smack_inet_csk_clone(struct sock *sk,
static int smack_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
- struct smack_known *skp = smk_of_task(cred->security);
+ struct smack_known *skp = smk_of_task(smack_cred(cred));
key->security = skp;
return 0;
@@ -4245,7 +4147,7 @@ static int smack_key_permission(key_ref_t key_ref,
{
struct key *keyp;
struct smk_audit_info ad;
- struct smack_known *tkp = smk_of_task(cred->security);
+ struct smack_known *tkp = smk_of_task(smack_cred(cred));
int request = 0;
int rc;
@@ -4520,12 +4422,12 @@ static int smack_inode_copy_up(struct dentry *dentry, struct cred **new)
return -ENOMEM;
}
- tsp = new_creds->security;
+ tsp = smack_cred(new_creds);
/*
* Get label from overlay inode and set it in create_sid
*/
- isp = d_inode(dentry->d_parent)->i_security;
+ isp = smack_inode(d_inode(dentry->d_parent));
skp = isp->smk_inode;
tsp->smk_task = skp;
*new = new_creds;
@@ -4548,8 +4450,8 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
const struct cred *old,
struct cred *new)
{
- struct task_smack *otsp = old->security;
- struct task_smack *ntsp = new->security;
+ struct task_smack *otsp = smack_cred(old);
+ struct task_smack *ntsp = smack_cred(new);
struct inode_smack *isp;
int may;
@@ -4562,7 +4464,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
/*
* the attribute of the containing directory
*/
- isp = d_inode(dentry->d_parent)->i_security;
+ isp = smack_inode(d_inode(dentry->d_parent));
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
rcu_read_lock();
@@ -4582,6 +4484,14 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
return 0;
}
+struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
+ .lbs_cred = sizeof(struct task_smack),
+ .lbs_file = sizeof(struct smack_known *),
+ .lbs_inode = sizeof(struct inode_smack),
+ .lbs_ipc = sizeof(struct smack_known *),
+ .lbs_msg_msg = sizeof(struct smack_known *),
+};
+
static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
@@ -4597,7 +4507,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds),
LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security),
- LSM_HOOK_INIT(inode_free_security, smack_inode_free_security),
LSM_HOOK_INIT(inode_init_security, smack_inode_init_security),
LSM_HOOK_INIT(inode_link, smack_inode_link),
LSM_HOOK_INIT(inode_unlink, smack_inode_unlink),
@@ -4616,7 +4525,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
- LSM_HOOK_INIT(file_free_security, smack_file_free_security),
LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
LSM_HOOK_INIT(file_lock, smack_file_lock),
LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),
@@ -4652,23 +4560,19 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid),
LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security),
- LSM_HOOK_INIT(msg_msg_free_security, smack_msg_msg_free_security),
LSM_HOOK_INIT(msg_queue_alloc_security, smack_ipc_alloc_security),
- LSM_HOOK_INIT(msg_queue_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(msg_queue_associate, smack_msg_queue_associate),
LSM_HOOK_INIT(msg_queue_msgctl, smack_msg_queue_msgctl),
LSM_HOOK_INIT(msg_queue_msgsnd, smack_msg_queue_msgsnd),
LSM_HOOK_INIT(msg_queue_msgrcv, smack_msg_queue_msgrcv),
LSM_HOOK_INIT(shm_alloc_security, smack_ipc_alloc_security),
- LSM_HOOK_INIT(shm_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(shm_associate, smack_shm_associate),
LSM_HOOK_INIT(shm_shmctl, smack_shm_shmctl),
LSM_HOOK_INIT(shm_shmat, smack_shm_shmat),
LSM_HOOK_INIT(sem_alloc_security, smack_ipc_alloc_security),
- LSM_HOOK_INIT(sem_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(sem_associate, smack_sem_associate),
LSM_HOOK_INIT(sem_semctl, smack_sem_semctl),
LSM_HOOK_INIT(sem_semop, smack_sem_semop),
@@ -4759,23 +4663,23 @@ static __init void init_smack_known_list(void)
*/
static __init int smack_init(void)
{
- struct cred *cred;
+ struct cred *cred = (struct cred *) current->cred;
struct task_smack *tsp;
- if (!security_module_enable("smack"))
- return 0;
-
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
if (!smack_inode_cache)
return -ENOMEM;
- tsp = new_task_smack(&smack_known_floor, &smack_known_floor,
- GFP_KERNEL);
- if (tsp == NULL) {
- kmem_cache_destroy(smack_inode_cache);
- return -ENOMEM;
- }
+ /*
+ * Set the security state for the initial task.
+ */
+ tsp = smack_cred(cred);
+ init_task_smack(tsp, &smack_known_floor, &smack_known_floor);
+ /*
+ * Register with LSM
+ */
+ security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
smack_enabled = 1;
pr_info("Smack: Initializing.\n");
@@ -4789,20 +4693,9 @@ static __init int smack_init(void)
pr_info("Smack: IPv6 Netfilter enabled.\n");
#endif
- /*
- * Set the security state for the initial task.
- */
- cred = (struct cred *) current->cred;
- cred->security = tsp;
-
/* initialize the smack_known_list */
init_smack_known_list();
- /*
- * Register with LSM
- */
- security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
-
return 0;
}
@@ -4812,5 +4705,7 @@ static __init int smack_init(void)
*/
DEFINE_LSM(smack) = {
.name = "smack",
+ .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+ .blobs = &smack_blob_sizes,
.init = smack_init,
};
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 06b517075ec0..faf2ea3968b3 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -2208,14 +2208,14 @@ static const struct file_operations smk_logging_ops = {
static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_seq_start(s, pos, &tsp->smk_rules);
}
static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_seq_next(s, v, pos, &tsp->smk_rules);
}
@@ -2262,7 +2262,7 @@ static int smk_open_load_self(struct inode *inode, struct file *file)
static ssize_t smk_write_load_self(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
&tsp->smk_rules_lock, SMK_FIXED24_FMT);
@@ -2414,14 +2414,14 @@ static const struct file_operations smk_load2_ops = {
static void *load_self2_seq_start(struct seq_file *s, loff_t *pos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_seq_start(s, pos, &tsp->smk_rules);
}
static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_seq_next(s, v, pos, &tsp->smk_rules);
}
@@ -2467,7 +2467,7 @@ static int smk_open_load_self2(struct inode *inode, struct file *file)
static ssize_t smk_write_load_self2(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
&tsp->smk_rules_lock, SMK_LONG_FMT);
@@ -2681,14 +2681,14 @@ static const struct file_operations smk_syslog_ops = {
static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_seq_start(s, pos, &tsp->smk_relabel);
}
static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
return smk_seq_next(s, v, pos, &tsp->smk_relabel);
}
@@ -2736,7 +2736,7 @@ static int smk_open_relabel_self(struct inode *inode, struct file *file)
static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
char *data;
int rc;
LIST_HEAD(list_tmp);
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c
index 479b03a7a17e..3c96e8402e94 100644
--- a/security/tomoyo/audit.c
+++ b/security/tomoyo/audit.c
@@ -32,6 +32,7 @@ static char *tomoyo_print_bprm(struct linux_binprm *bprm,
int argv_count = bprm->argc;
int envp_count = bprm->envc;
bool truncated = false;
+
if (!buffer)
return NULL;
len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ ");
@@ -49,6 +50,7 @@ static char *tomoyo_print_bprm(struct linux_binprm *bprm,
while (offset < PAGE_SIZE) {
const char *kaddr = dump->data;
const unsigned char c = kaddr[offset++];
+
if (cp == last_start)
*cp++ = '"';
if (cp >= buffer + tomoyo_buffer_len - 32) {
@@ -154,19 +156,18 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
int pos;
u8 i;
+
if (!buffer)
return NULL;
tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
pos = snprintf(buffer, tomoyo_buffer_len - 1,
- "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
- "granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
- "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
- "fsuid=%u fsgid=%u }", stamp.year, stamp.month,
- stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile,
- tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid,
- tomoyo_sys_getpid(), tomoyo_sys_getppid(),
+ "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s granted=%s (global-pid=%u) task={ pid=%u ppid=%u uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
+ stamp.year, stamp.month, stamp.day, stamp.hour,
+ stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode],
+ tomoyo_yesno(r->granted), gpid, tomoyo_sys_getpid(),
+ tomoyo_sys_getppid(),
from_kuid(&init_user_ns, current_uid()),
from_kgid(&init_user_ns, current_gid()),
from_kuid(&init_user_ns, current_euid()),
@@ -185,6 +186,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
struct tomoyo_mini_stat *stat;
unsigned int dev;
umode_t mode;
+
if (!obj->stat_valid[i])
continue;
stat = &obj->stat[i];
@@ -193,8 +195,8 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
if (i & 1) {
pos += snprintf(buffer + pos,
tomoyo_buffer_len - 1 - pos,
- " path%u.parent={ uid=%u gid=%u "
- "ino=%lu perm=0%o }", (i >> 1) + 1,
+ " path%u.parent={ uid=%u gid=%u ino=%lu perm=0%o }",
+ (i >> 1) + 1,
from_kuid(&init_user_ns, stat->uid),
from_kgid(&init_user_ns, stat->gid),
(unsigned long)stat->ino,
@@ -202,8 +204,8 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
continue;
}
pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
- " path%u={ uid=%u gid=%u ino=%lu major=%u"
- " minor=%u perm=0%o type=%s", (i >> 1) + 1,
+ " path%u={ uid=%u gid=%u ino=%lu major=%u minor=%u perm=0%o type=%s",
+ (i >> 1) + 1,
from_kuid(&init_user_ns, stat->uid),
from_kgid(&init_user_ns, stat->gid),
(unsigned long)stat->ino,
@@ -249,6 +251,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
const char *symlink = NULL;
int pos;
const char *domainname = r->domain->domainname->name;
+
header = tomoyo_print_header(r);
if (!header)
return NULL;
@@ -256,6 +259,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
len += strlen(domainname) + strlen(header) + 10;
if (r->ee) {
struct file *file = r->ee->bprm->file;
+
realpath = tomoyo_realpath_from_path(&file->f_path);
bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
if (!realpath || !bprm_info)
@@ -275,6 +279,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
pos = snprintf(buf, len, "%s", header);
if (realpath) {
struct linux_binprm *bprm = r->ee->bprm;
+
pos += snprintf(buf + pos, len - pos,
" exec={ realpath=\"%s\" argc=%d envc=%d %s }",
realpath, bprm->argc, bprm->envc, bprm_info);
@@ -328,6 +333,7 @@ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
const u8 category = tomoyo_index2category[index] +
TOMOYO_MAX_MAC_INDEX;
struct tomoyo_profile *p;
+
if (!tomoyo_policy_loaded)
return false;
p = tomoyo_profile(ns, profile);
@@ -362,6 +368,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
char *buf;
struct tomoyo_log *entry;
bool quota_exceeded = false;
+
if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
r->matched_acl, r->granted))
goto out;
@@ -413,6 +420,7 @@ void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
{
va_list args;
int len;
+
va_start(args, fmt);
len = vsnprintf((char *) &len, 1, fmt, args) + 1;
va_end(args);
@@ -431,6 +439,7 @@ void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
void tomoyo_read_log(struct tomoyo_io_buffer *head)
{
struct tomoyo_log *ptr = NULL;
+
if (head->r.w_pos)
return;
kfree(head->read_buf);
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index c598aa00d5e3..57988d95d33d 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -197,6 +197,7 @@ static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
{
va_list args;
const int pos = strlen(buffer);
+
va_start(args, fmt);
vsnprintf(buffer + pos, len - pos - 1, fmt, args);
va_end(args);
@@ -214,6 +215,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)
while (head->r.w_pos) {
const char *w = head->r.w[0];
size_t len = strlen(w);
+
if (len) {
if (len > head->read_user_buf_avail)
len = head->read_user_buf_avail;
@@ -279,6 +281,7 @@ static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
size_t len;
size_t pos = head->r.avail;
int size = head->readbuf_size - pos;
+
if (size <= 0)
return;
va_start(args, fmt);
@@ -344,13 +347,14 @@ static bool tomoyo_namespace_enabled;
void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
{
unsigned int idx;
+
for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
INIT_LIST_HEAD(&ns->acl_group[idx]);
for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
INIT_LIST_HEAD(&ns->group_list[idx]);
for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
INIT_LIST_HEAD(&ns->policy_list[idx]);
- ns->profile_version = 20110903;
+ ns->profile_version = 20150505;
tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
}
@@ -433,6 +437,7 @@ static void tomoyo_print_number_union_nospace
u8 min_type = ptr->value_type[0];
const u8 max_type = ptr->value_type[1];
char buffer[128];
+
buffer[0] = '\0';
for (i = 0; i < 2; i++) {
switch (min_type) {
@@ -487,6 +492,7 @@ static struct tomoyo_profile *tomoyo_assign_profile
{
struct tomoyo_profile *ptr;
struct tomoyo_profile *entry;
+
if (profile >= TOMOYO_MAX_PROFILES)
return NULL;
ptr = ns->profile_ptr[profile];
@@ -530,6 +536,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
{
static struct tomoyo_profile tomoyo_null_profile;
struct tomoyo_profile *ptr = ns->profile_ptr[profile];
+
if (!ptr)
ptr = &tomoyo_null_profile;
return ptr;
@@ -546,6 +553,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
static s8 tomoyo_find_yesno(const char *string, const char *find)
{
const char *cp = strstr(string, find);
+
if (cp) {
cp += strlen(find);
if (!strncmp(cp, "=yes", 4))
@@ -569,6 +577,7 @@ static void tomoyo_set_uint(unsigned int *i, const char *string,
const char *find)
{
const char *cp = strstr(string, find);
+
if (cp)
sscanf(cp + strlen(find), "=%u", i);
}
@@ -587,6 +596,7 @@ static int tomoyo_set_mode(char *name, const char *value,
{
u8 i;
u8 config;
+
if (!strcmp(name, "CONFIG")) {
i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
config = profile->default_config;
@@ -595,10 +605,12 @@ static int tomoyo_set_mode(char *name, const char *value,
for (i = 0; i < TOMOYO_MAX_MAC_INDEX
+ TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
int len = 0;
+
if (i < TOMOYO_MAX_MAC_INDEX) {
const u8 c = tomoyo_index2category[i];
const char *category =
tomoyo_category_keywords[c];
+
len = strlen(category);
if (strncmp(name, category, len) ||
name[len++] != ':' || name[len++] != ':')
@@ -618,6 +630,7 @@ static int tomoyo_set_mode(char *name, const char *value,
config = TOMOYO_CONFIG_USE_DEFAULT;
} else {
u8 mode;
+
for (mode = 0; mode < 4; mode++)
if (strstr(value, tomoyo_mode[mode]))
/*
@@ -664,6 +677,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
unsigned int i;
char *cp;
struct tomoyo_profile *profile;
+
if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
== 1)
return 0;
@@ -683,6 +697,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
const struct tomoyo_path_info *new_comment
= tomoyo_get_name(cp);
const struct tomoyo_path_info *old_comment;
+
if (!new_comment)
return -ENOMEM;
spin_lock(&lock);
@@ -732,6 +747,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
const struct tomoyo_profile *profile;
+
if (head->r.eof)
return;
next:
@@ -760,6 +776,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
u8 i;
const struct tomoyo_path_info *comment =
profile->comment;
+
tomoyo_print_namespace(head);
tomoyo_io_printf(head, "%u-COMMENT=", index);
tomoyo_set_string(head, comment ? comment->name : "");
@@ -788,6 +805,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
+ TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
const u8 i = head->r.bit;
const u8 config = profile->config[i];
+
if (config == TOMOYO_CONFIG_USE_DEFAULT)
continue;
tomoyo_print_namespace(head);
@@ -847,10 +865,10 @@ static int tomoyo_update_manager_entry(const char *manager,
struct tomoyo_acl_param param = {
/* .ns = &tomoyo_kernel_namespace, */
.is_delete = is_delete,
- .list = &tomoyo_kernel_namespace.
- policy_list[TOMOYO_ID_MANAGER],
+ .list = &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER],
};
int error = is_delete ? -ENOENT : -ENOMEM;
+
if (!tomoyo_correct_domain(manager) &&
!tomoyo_correct_word(manager))
return -EINVAL;
@@ -894,10 +912,10 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
{
if (head->r.eof)
return;
- list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.
- policy_list[TOMOYO_ID_MANAGER]) {
+ list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER]) {
struct tomoyo_manager *ptr =
list_entry(head->r.acl, typeof(*ptr), head.list);
+
if (ptr->head.is_deleted)
continue;
if (!tomoyo_flush(head))
@@ -933,8 +951,7 @@ static bool tomoyo_manager(void)
exe = tomoyo_get_exe();
if (!exe)
return false;
- list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
- policy_list[TOMOYO_ID_MANAGER], head.list) {
+ list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], head.list) {
if (!ptr->head.is_deleted &&
(!tomoyo_pathcmp(domainname, ptr->manager) ||
!strcmp(exe, ptr->manager->name))) {
@@ -945,9 +962,10 @@ static bool tomoyo_manager(void)
if (!found) { /* Reduce error messages. */
static pid_t last_pid;
const pid_t pid = current->pid;
+
if (last_pid != pid) {
- printk(KERN_WARNING "%s ( %s ) is not permitted to "
- "update policies.\n", domainname->name, exe);
+ pr_warn("%s ( %s ) is not permitted to update policies.\n",
+ domainname->name, exe);
last_pid = pid;
}
}
@@ -974,19 +992,21 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
unsigned int pid;
struct tomoyo_domain_info *domain = NULL;
bool global_pid = false;
+
if (strncmp(data, "select ", 7))
return false;
data += 7;
if (sscanf(data, "pid=%u", &pid) == 1 ||
(global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
struct task_struct *p;
+
rcu_read_lock();
if (global_pid)
p = find_task_by_pid_ns(pid, &init_pid_ns);
else
p = find_task_by_vpid(pid);
if (p)
- domain = tomoyo_real_domain(p);
+ domain = tomoyo_task(p)->domain_info;
rcu_read_unlock();
} else if (!strncmp(data, "domain=", 7)) {
if (tomoyo_domain_def(data + 7))
@@ -1020,10 +1040,11 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
* Returns true if @a == @b, false otherwise.
*/
static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
- const struct tomoyo_acl_info *b)
+ const struct tomoyo_acl_info *b)
{
const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
+
return p1->domainname == p2->domainname;
}
@@ -1039,11 +1060,13 @@ static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
static int tomoyo_write_task(struct tomoyo_acl_param *param)
{
int error = -EINVAL;
+
if (tomoyo_str_starts(&param->data, "manual_domain_transition ")) {
struct tomoyo_task_acl e = {
.head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
.domainname = tomoyo_get_domainname(param),
};
+
if (e.domainname)
error = tomoyo_update_domain(&e.head, sizeof(e), param,
tomoyo_same_task_acl,
@@ -1110,7 +1133,7 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
};
static const struct {
const char *keyword;
- int (*write) (struct tomoyo_acl_param *);
+ int (*write)(struct tomoyo_acl_param *param);
} tomoyo_callback[5] = {
{ "file ", tomoyo_write_file },
{ "network inet ", tomoyo_write_inet_network },
@@ -1151,9 +1174,11 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
struct tomoyo_domain_info *domain = head->w.domain;
const bool is_delete = head->w.is_delete;
bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
- unsigned int profile;
+ unsigned int idx;
+
if (*data == '<') {
int ret = 0;
+
domain = NULL;
if (is_delete)
ret = tomoyo_delete_domain(data);
@@ -1167,23 +1192,27 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
if (!domain)
return -EINVAL;
ns = domain->ns;
- if (sscanf(data, "use_profile %u", &profile) == 1
- && profile < TOMOYO_MAX_PROFILES) {
- if (!tomoyo_policy_loaded || ns->profile_ptr[profile])
- domain->profile = (u8) profile;
+ if (sscanf(data, "use_profile %u", &idx) == 1
+ && idx < TOMOYO_MAX_PROFILES) {
+ if (!tomoyo_policy_loaded || ns->profile_ptr[idx])
+ if (!is_delete)
+ domain->profile = (u8) idx;
return 0;
}
- if (sscanf(data, "use_group %u\n", &profile) == 1
- && profile < TOMOYO_MAX_ACL_GROUPS) {
+ if (sscanf(data, "use_group %u\n", &idx) == 1
+ && idx < TOMOYO_MAX_ACL_GROUPS) {
if (!is_delete)
- domain->group = (u8) profile;
+ set_bit(idx, domain->group);
+ else
+ clear_bit(idx, domain->group);
return 0;
}
- for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) {
- const char *cp = tomoyo_dif[profile];
+ for (idx = 0; idx < TOMOYO_MAX_DOMAIN_INFO_FLAGS; idx++) {
+ const char *cp = tomoyo_dif[idx];
+
if (strncmp(data, cp, strlen(cp) - 1))
continue;
- domain->flags[profile] = !is_delete;
+ domain->flags[idx] = !is_delete;
return 0;
}
return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
@@ -1225,9 +1254,11 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
const struct tomoyo_envp *envp =
(typeof(envp)) (argv + cond->argc);
u16 skip;
+
for (skip = 0; skip < head->r.cond_index; skip++) {
const u8 left = condp->left;
const u8 right = condp->right;
+
condp++;
switch (left) {
case TOMOYO_ARGV_ENTRY:
@@ -1253,6 +1284,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
const u8 match = condp->equals;
const u8 left = condp->left;
const u8 right = condp->right;
+
if (!tomoyo_flush(head))
return false;
condp++;
@@ -1262,8 +1294,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
case TOMOYO_ARGV_ENTRY:
tomoyo_io_printf(head,
"exec.argv[%lu]%s=\"",
- argv->index, argv->
- is_not ? "!" : "");
+ argv->index, argv->is_not ? "!" : "");
tomoyo_set_string(head,
argv->value->name);
tomoyo_set_string(head, "\"");
@@ -1274,12 +1305,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
"exec.envp[\"");
tomoyo_set_string(head,
envp->name->name);
- tomoyo_io_printf(head, "\"]%s=", envp->
- is_not ? "!" : "");
+ tomoyo_io_printf(head, "\"]%s=", envp->is_not ? "!" : "");
if (envp->value) {
tomoyo_set_string(head, "\"");
- tomoyo_set_string(head, envp->
- value->name);
+ tomoyo_set_string(head, envp->value->name);
tomoyo_set_string(head, "\"");
} else {
tomoyo_set_string(head,
@@ -1375,6 +1404,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
struct tomoyo_path_acl *ptr =
container_of(acl, typeof(*ptr), head);
const u16 perm = ptr->perm;
+
for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
if (!(perm & (1 << bit)))
continue;
@@ -1395,6 +1425,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
} else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
struct tomoyo_task_acl *ptr =
container_of(acl, typeof(*ptr), head);
+
tomoyo_set_group(head, "task ");
tomoyo_set_string(head, "manual_domain_transition ");
tomoyo_set_string(head, ptr->domainname->name);
@@ -1404,6 +1435,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
struct tomoyo_path2_acl *ptr =
container_of(acl, typeof(*ptr), head);
const u8 perm = ptr->perm;
+
for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
if (!(perm & (1 << bit)))
continue;
@@ -1424,6 +1456,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
struct tomoyo_path_number_acl *ptr =
container_of(acl, typeof(*ptr), head);
const u8 perm = ptr->perm;
+
for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) {
if (!(perm & (1 << bit)))
continue;
@@ -1444,6 +1477,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
struct tomoyo_mkdev_acl *ptr =
container_of(acl, typeof(*ptr), head);
const u8 perm = ptr->perm;
+
for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) {
if (!(perm & (1 << bit)))
continue;
@@ -1490,6 +1524,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
->name);
} else {
char buf[128];
+
tomoyo_print_ip(buf, sizeof(buf), &ptr->address);
tomoyo_io_printf(head, "%s", buf);
}
@@ -1519,6 +1554,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
} else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
struct tomoyo_mount_acl *ptr =
container_of(acl, typeof(*ptr), head);
+
tomoyo_set_group(head, "file mount");
tomoyo_print_name_union(head, &ptr->dev_name);
tomoyo_print_name_union(head, &ptr->dir_name);
@@ -1562,6 +1598,7 @@ static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
list_for_each_cookie(head->r.acl, list) {
struct tomoyo_acl_info *ptr =
list_entry(head->r.acl, typeof(*ptr), list);
+
if (!tomoyo_print_entry(head, ptr))
return false;
}
@@ -1583,8 +1620,9 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
struct tomoyo_domain_info *domain =
list_entry(head->r.domain, typeof(*domain), list);
+ u8 i;
+
switch (head->r.step) {
- u8 i;
case 0:
if (domain->is_deleted &&
!head->r.print_this_domain_only)
@@ -1594,22 +1632,33 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
tomoyo_set_lf(head);
tomoyo_io_printf(head, "use_profile %u\n",
domain->profile);
- tomoyo_io_printf(head, "use_group %u\n",
- domain->group);
for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++)
if (domain->flags[i])
tomoyo_set_string(head, tomoyo_dif[i]);
+ head->r.index = 0;
head->r.step++;
- tomoyo_set_lf(head);
/* fall through */
case 1:
+ while (head->r.index < TOMOYO_MAX_ACL_GROUPS) {
+ i = head->r.index++;
+ if (!test_bit(i, domain->group))
+ continue;
+ tomoyo_io_printf(head, "use_group %u\n", i);
+ if (!tomoyo_flush(head))
+ return;
+ }
+ head->r.index = 0;
+ head->r.step++;
+ tomoyo_set_lf(head);
+ /* fall through */
+ case 2:
if (!tomoyo_read_domain2(head, &domain->acl_info_list))
return;
head->r.step++;
if (!tomoyo_set_lf(head))
return;
/* fall through */
- case 2:
+ case 3:
head->r.step = 0;
if (head->r.print_this_domain_only)
goto done;
@@ -1668,7 +1717,7 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
else
p = find_task_by_vpid(pid);
if (p)
- domain = tomoyo_real_domain(p);
+ domain = tomoyo_task(p)->domain_info;
rcu_read_unlock();
if (!domain)
return;
@@ -1711,6 +1760,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
.data = head->write_buf,
};
u8 i;
+
if (tomoyo_str_starts(&param.data, "aggregator "))
return tomoyo_write_aggregator(&param);
for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
@@ -1722,6 +1772,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
if (tomoyo_str_starts(&param.data, "acl_group ")) {
unsigned int group;
char *data;
+
group = simple_strtoul(param.data, &data, 10);
if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
return tomoyo_write_domain2
@@ -1746,12 +1797,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
struct list_head *list = &ns->group_list[idx];
+
list_for_each_cookie(head->r.group, list) {
struct tomoyo_group *group =
list_entry(head->r.group, typeof(*group), head.list);
+
list_for_each_cookie(head->r.acl, &group->member_list) {
struct tomoyo_acl_head *ptr =
list_entry(head->r.acl, typeof(*ptr), list);
+
if (ptr->is_deleted)
continue;
if (!tomoyo_flush(head))
@@ -1771,10 +1825,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
head)->number);
} else if (idx == TOMOYO_ADDRESS_GROUP) {
char buffer[128];
-
struct tomoyo_address_group *member =
container_of(ptr, typeof(*member),
head);
+
tomoyo_print_ip(buffer, sizeof(buffer),
&member->address);
tomoyo_io_printf(head, " %s", buffer);
@@ -1802,6 +1856,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
struct list_head *list = &ns->policy_list[idx];
+
list_for_each_cookie(head->r.acl, list) {
struct tomoyo_acl_head *acl =
container_of(head->r.acl, typeof(*acl), list);
@@ -1814,6 +1869,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
{
struct tomoyo_transition_control *ptr =
container_of(acl, typeof(*ptr), head);
+
tomoyo_print_namespace(head);
tomoyo_set_string(head, tomoyo_transition_type
[ptr->type]);
@@ -1829,6 +1885,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
{
struct tomoyo_aggregator *ptr =
container_of(acl, typeof(*ptr), head);
+
tomoyo_print_namespace(head);
tomoyo_set_string(head, "aggregator ");
tomoyo_set_string(head,
@@ -1858,6 +1915,7 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
{
struct tomoyo_policy_namespace *ns =
container_of(head->r.ns, typeof(*ns), namespace_list);
+
if (head->r.eof)
return;
while (head->r.step < TOMOYO_MAX_POLICY &&
@@ -1921,6 +1979,7 @@ static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
static int tomoyo_truncate(char *str)
{
char *start = str;
+
while (*(unsigned char *) str > (unsigned char) ' ')
str++;
*str = '\0';
@@ -1943,6 +2002,7 @@ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
char *symlink = NULL;
char *cp = strchr(header, '\n');
int len;
+
if (!cp)
return;
cp = strchr(cp + 1, '\n');
@@ -2002,6 +2062,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
static unsigned int tomoyo_serial;
struct tomoyo_query entry = { };
bool quota_exceeded = false;
+
va_start(args, fmt);
len = vsnprintf((char *) &len, 1, fmt, args) + 1;
va_end(args);
@@ -2063,8 +2124,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
(tomoyo_answer_wait, entry.answer ||
!atomic_read(&tomoyo_query_observers), HZ))
break;
- else
- entry.timer++;
+ entry.timer++;
}
spin_lock(&tomoyo_query_list_lock);
list_del(&entry.list);
@@ -2100,6 +2160,7 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
{
struct tomoyo_query *ptr;
struct tomoyo_domain_info *domain = NULL;
+
spin_lock(&tomoyo_query_list_lock);
list_for_each_entry(ptr, &tomoyo_query_list, list) {
if (ptr->serial != serial)
@@ -2142,15 +2203,15 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
unsigned int pos = 0;
size_t len = 0;
char *buf;
+
if (head->r.w_pos)
return;
- if (head->read_buf) {
- kfree(head->read_buf);
- head->read_buf = NULL;
- }
+ kfree(head->read_buf);
+ head->read_buf = NULL;
spin_lock(&tomoyo_query_list_lock);
list_for_each(tmp, &tomoyo_query_list) {
struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
if (pos++ != head->r.query_index)
continue;
len = ptr->query_len;
@@ -2168,6 +2229,7 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
spin_lock(&tomoyo_query_list_lock);
list_for_each(tmp, &tomoyo_query_list) {
struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
if (pos++ != head->r.query_index)
continue;
/*
@@ -2202,9 +2264,11 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
struct list_head *tmp;
unsigned int serial;
unsigned int answer;
+
spin_lock(&tomoyo_query_list_lock);
list_for_each(tmp, &tomoyo_query_list) {
struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
ptr->timer = 0;
}
spin_unlock(&tomoyo_query_list_lock);
@@ -2213,6 +2277,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
spin_lock(&tomoyo_query_list_lock);
list_for_each(tmp, &tomoyo_query_list) {
struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
if (ptr->serial != serial)
continue;
ptr->answer = answer;
@@ -2235,7 +2300,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
static void tomoyo_read_version(struct tomoyo_io_buffer *head)
{
if (!head->r.eof) {
- tomoyo_io_printf(head, "2.5.0");
+ tomoyo_io_printf(head, "2.6.0");
head->r.eof = true;
}
}
@@ -2287,6 +2352,7 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
{
u8 i;
unsigned int total = 0;
+
if (head->r.eof)
return;
for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) {
@@ -2295,9 +2361,9 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
tomoyo_stat_updated[i]);
if (tomoyo_stat_modified[i]) {
struct tomoyo_time stamp;
+
tomoyo_convert_time(tomoyo_stat_modified[i], &stamp);
- tomoyo_io_printf(head, " (Last: %04u/%02u/%02u "
- "%02u:%02u:%02u)",
+ tomoyo_io_printf(head, " (Last: %04u/%02u/%02u %02u:%02u:%02u)",
stamp.year, stamp.month, stamp.day,
stamp.hour, stamp.min, stamp.sec);
}
@@ -2305,6 +2371,7 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
}
for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) {
unsigned int used = tomoyo_memory_used[i];
+
total += used;
tomoyo_io_printf(head, "Memory used by %-22s %10u",
tomoyo_memory_headers[i], used);
@@ -2329,6 +2396,7 @@ static int tomoyo_write_stat(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
u8 i;
+
if (tomoyo_str_starts(&data, "Memory used by "))
for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++)
if (tomoyo_str_starts(&data, tomoyo_memory_headers[i]))
@@ -2457,6 +2525,7 @@ int tomoyo_open_control(const u8 type, struct file *file)
__poll_t tomoyo_poll_control(struct file *file, poll_table *wait)
{
struct tomoyo_io_buffer *head = file->private_data;
+
if (head->poll)
return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM;
return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
@@ -2472,6 +2541,7 @@ __poll_t tomoyo_poll_control(struct file *file, poll_table *wait)
static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head)
{
struct list_head *ns;
+
if (head->type != TOMOYO_EXCEPTIONPOLICY &&
head->type != TOMOYO_PROFILE)
return;
@@ -2517,7 +2587,7 @@ ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
int idx;
if (!head->read)
- return -ENOSYS;
+ return -EINVAL;
if (mutex_lock_interruptible(&head->io_sem))
return -EINTR;
head->read_user_buf = buffer;
@@ -2557,6 +2627,7 @@ static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
head->type == TOMOYO_PROFILE) {
if (*line == '<') {
char *cp = strchr(line, ' ');
+
if (cp) {
*cp++ = '\0';
head->w.ns = tomoyo_assign_namespace(line);
@@ -2589,8 +2660,9 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
size_t avail_len = buffer_len;
char *cp0 = head->write_buf;
int idx;
+
if (!head->write)
- return -ENOSYS;
+ return -EINVAL;
if (!access_ok(buffer, buffer_len))
return -EFAULT;
if (mutex_lock_interruptible(&head->io_sem))
@@ -2600,9 +2672,11 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
/* Read a line and dispatch it to the policy handler. */
while (avail_len > 0) {
char c;
+
if (head->w.avail >= head->writebuf_size - 1) {
const int len = head->writebuf_size * 2;
char *cp = kzalloc(len, GFP_NOFS);
+
if (!cp) {
error = -ENOMEM;
break;
@@ -2701,30 +2775,32 @@ void tomoyo_check_profile(void)
{
struct tomoyo_domain_info *domain;
const int idx = tomoyo_read_lock();
+
tomoyo_policy_loaded = true;
- printk(KERN_INFO "TOMOYO: 2.5.0\n");
+ pr_info("TOMOYO: 2.6.0\n");
list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
const u8 profile = domain->profile;
- const struct tomoyo_policy_namespace *ns = domain->ns;
- if (ns->profile_version != 20110903)
- printk(KERN_ERR
- "Profile version %u is not supported.\n",
+ struct tomoyo_policy_namespace *ns = domain->ns;
+
+ if (ns->profile_version == 20110903) {
+ pr_info_once("Converting profile version from %u to %u.\n",
+ 20110903, 20150505);
+ ns->profile_version = 20150505;
+ }
+ if (ns->profile_version != 20150505)
+ pr_err("Profile version %u is not supported.\n",
ns->profile_version);
else if (!ns->profile_ptr[profile])
- printk(KERN_ERR
- "Profile %u (used by '%s') is not defined.\n",
+ pr_err("Profile %u (used by '%s') is not defined.\n",
profile, domain->domainname->name);
else
continue;
- printk(KERN_ERR
- "Userland tools for TOMOYO 2.5 must be installed and "
- "policy must be initialized.\n");
- printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ "
- "for more information.\n");
+ pr_err("Userland tools for TOMOYO 2.6 must be installed and policy must be initialized.\n");
+ pr_err("Please see https://tomoyo.osdn.jp/2.6/ for more information.\n");
panic("STOP!");
}
tomoyo_read_unlock(idx);
- printk(KERN_INFO "Mandatory Access Control activated.\n");
+ pr_info("Mandatory Access Control activated.\n");
}
/**
@@ -2743,9 +2819,11 @@ void __init tomoyo_load_builtin_policy(void)
#include "builtin-policy.h"
u8 i;
const int idx = tomoyo_read_lock();
+
for (i = 0; i < 5; i++) {
struct tomoyo_io_buffer head = { };
char *start = "";
+
switch (i) {
case 0:
start = tomoyo_builtin_profile;
@@ -2775,6 +2853,7 @@ void __init tomoyo_load_builtin_policy(void)
}
while (1) {
char *end = strchr(start, '\n');
+
if (!end)
break;
*end = '\0';
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 539bcdd30bb8..050473df5809 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -10,6 +10,8 @@
#ifndef _SECURITY_TOMOYO_COMMON_H
#define _SECURITY_TOMOYO_COMMON_H
+#define pr_fmt(fmt) fmt
+
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -29,6 +31,7 @@
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/un.h>
+#include <linux/lsm_hooks.h>
#include <net/sock.h>
#include <net/af_unix.h>
#include <net/ip.h>
@@ -681,11 +684,12 @@ struct tomoyo_domain_info {
const struct tomoyo_path_info *domainname;
/* Namespace for this domain. Never NULL. */
struct tomoyo_policy_namespace *ns;
+ /* Group numbers to use. */
+ unsigned long group[TOMOYO_MAX_ACL_GROUPS / BITS_PER_LONG];
u8 profile; /* Profile number to use. */
- u8 group; /* Group number to use. */
bool is_deleted; /* Delete flag. */
bool flags[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
- atomic_t users; /* Number of referring credentials. */
+ atomic_t users; /* Number of referring tasks. */
};
/*
@@ -787,9 +791,9 @@ struct tomoyo_acl_param {
* interfaces.
*/
struct tomoyo_io_buffer {
- void (*read) (struct tomoyo_io_buffer *);
- int (*write) (struct tomoyo_io_buffer *);
- __poll_t (*poll) (struct file *file, poll_table *wait);
+ void (*read)(struct tomoyo_io_buffer *head);
+ int (*write)(struct tomoyo_io_buffer *head);
+ __poll_t (*poll)(struct file *file, poll_table *wait);
/* Exclusive lock for this structure. */
struct mutex io_sem;
char __user *read_user_buf;
@@ -906,12 +910,18 @@ struct tomoyo_policy_namespace {
struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS];
/* List for connecting to tomoyo_namespace_list list. */
struct list_head namespace_list;
- /* Profile version. Currently only 20110903 is defined. */
+ /* Profile version. Currently only 20150505 is defined. */
unsigned int profile_version;
/* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
const char *name;
};
+/* Structure for "struct task_struct"->security. */
+struct tomoyo_task {
+ struct tomoyo_domain_info *domain_info;
+ struct tomoyo_domain_info *old_domain_info;
+};
+
/********** Function prototypes. **********/
bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
@@ -1020,6 +1030,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param);
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
const bool transit);
+struct tomoyo_domain_info *tomoyo_domain(void);
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
const u8 idx);
@@ -1034,8 +1045,8 @@ void *tomoyo_commit_ok(void *data, const unsigned int size);
void __init tomoyo_load_builtin_policy(void);
void __init tomoyo_mm_init(void);
void tomoyo_check_acl(struct tomoyo_request_info *r,
- bool (*check_entry) (struct tomoyo_request_info *,
- const struct tomoyo_acl_info *));
+ bool (*check_entry)(struct tomoyo_request_info *,
+ const struct tomoyo_acl_info *));
void tomoyo_check_profile(void);
void tomoyo_convert_time(time64_t time, struct tomoyo_time *stamp);
void tomoyo_del_condition(struct list_head *element);
@@ -1062,6 +1073,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
/********** External variable definitions. **********/
extern bool tomoyo_policy_loaded;
+extern int tomoyo_enabled;
extern const char * const tomoyo_condition_keyword
[TOMOYO_MAX_CONDITION_KEYWORD];
extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
@@ -1085,6 +1097,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. **********/
@@ -1121,6 +1134,7 @@ static inline void tomoyo_read_unlock(int idx)
static inline pid_t tomoyo_sys_getppid(void)
{
pid_t pid;
+
rcu_read_lock();
pid = task_tgid_vnr(rcu_dereference(current->real_parent));
rcu_read_unlock();
@@ -1197,26 +1211,15 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
}
/**
- * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
- *
- * Returns pointer to "struct tomoyo_domain_info" for current thread.
- */
-static inline struct tomoyo_domain_info *tomoyo_domain(void)
-{
- return current_cred()->security;
-}
-
-/**
- * tomoyo_real_domain - Get "struct tomoyo_domain_info" for specified thread.
+ * tomoyo_task - Get "struct tomoyo_task" for specified thread.
*
- * @task: Pointer to "struct task_struct".
+ * @task - Pointer to "struct task_struct".
*
- * Returns pointer to "struct tomoyo_security" for specified thread.
+ * Returns pointer to "struct tomoyo_task" for specified thread.
*/
-static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
- *task)
+static inline struct tomoyo_task *tomoyo_task(struct task_struct *task)
{
- return task_cred_xxx(task, security);
+ return task->security + tomoyo_blob_sizes.lbs_task;
}
/**
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c
index 8d0e1b9c9c57..8f6d57c15df6 100644
--- a/security/tomoyo/condition.c
+++ b/security/tomoyo/condition.c
@@ -28,9 +28,11 @@ static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
{
int i;
struct tomoyo_path_info arg;
+
arg.name = arg_ptr;
for (i = 0; i < argc; argv++, checked++, i++) {
bool result;
+
if (index != argv->index)
continue;
*checked = 1;
@@ -62,12 +64,14 @@ static bool tomoyo_envp(const char *env_name, const char *env_value,
int i;
struct tomoyo_path_info name;
struct tomoyo_path_info value;
+
name.name = env_name;
tomoyo_fill_path_info(&name);
value.name = env_value;
tomoyo_fill_path_info(&value);
for (i = 0; i < envc; envp++, checked++, i++) {
bool result;
+
if (!tomoyo_path_matches_pattern(&name, envp->name))
continue;
*checked = 1;
@@ -113,6 +117,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
bool result = true;
u8 local_checked[32];
u8 *checked;
+
if (argc + envc <= sizeof(local_checked)) {
checked = local_checked;
memset(local_checked, 0, sizeof(local_checked));
@@ -131,6 +136,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
/* Read. */
const char *kaddr = dump->data;
const unsigned char c = kaddr[offset++];
+
if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
if (c == '\\') {
arg_ptr[arg_len++] = '\\';
@@ -160,6 +166,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
argv_count--;
} else if (envp_count) {
char *cp = strchr(arg_ptr, '=');
+
if (cp) {
*cp = '\0';
if (!tomoyo_envp(arg_ptr, cp + 1,
@@ -182,6 +189,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
out:
if (result) {
int i;
+
/* Check not-yet-checked entries. */
for (i = 0; i < argc; i++) {
if (checked[i])
@@ -229,6 +237,7 @@ static bool tomoyo_scan_exec_realpath(struct file *file,
{
bool result;
struct tomoyo_path_info exe;
+
if (!file)
return false;
exe.name = tomoyo_realpath_from_path(&file->f_path);
@@ -250,6 +259,7 @@ static bool tomoyo_scan_exec_realpath(struct file *file,
static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
{
char *cp = start + strlen(start) - 1;
+
if (cp == start || *start++ != '"' || *cp != '"')
return NULL;
*cp = '\0';
@@ -270,6 +280,7 @@ static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
struct tomoyo_name_union *ptr)
{
char *filename = param->data;
+
if (*filename == '@')
return tomoyo_parse_name_union(param, ptr);
ptr->filename = tomoyo_get_dqword(filename);
@@ -310,6 +321,7 @@ static bool tomoyo_parse_envp(char *left, char *right,
const struct tomoyo_path_info *name;
const struct tomoyo_path_info *value;
char *cp = left + strlen(left) - 1;
+
if (*cp-- != ']' || *cp != '"')
goto out;
*cp = '\0';
@@ -364,6 +376,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
static u8 tomoyo_condition_type(const char *word)
{
u8 i;
+
for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
if (!strcmp(word, tomoyo_condition_keyword[i]))
break;
@@ -395,6 +408,7 @@ static struct tomoyo_condition *tomoyo_commit_condition
{
struct tomoyo_condition *ptr;
bool found = false;
+
if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
ptr = NULL;
@@ -442,12 +456,14 @@ static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
{
char * const pos = param->data;
bool flag;
+
if (*pos == '<') {
e->transit = tomoyo_get_domainname(param);
goto done;
}
{
char *cp = strchr(pos, ' ');
+
if (cp)
*cp = '\0';
flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
@@ -489,6 +505,7 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
tomoyo_get_transit_preference(param, &e);
char * const end_of_string = start_of_string + strlen(start_of_string);
char *pos;
+
rerun:
pos = start_of_string;
while (1) {
@@ -498,6 +515,7 @@ rerun:
char *cp;
char *right_word;
bool is_not;
+
if (!*left_word)
break;
/*
@@ -622,8 +640,8 @@ rerun:
}
store_value:
if (!condp) {
- dprintk(KERN_WARNING "%u: dry_run left=%u right=%u "
- "match=%u\n", __LINE__, left, right, !is_not);
+ dprintk(KERN_WARNING "%u: dry_run left=%u right=%u match=%u\n",
+ __LINE__, left, right, !is_not);
continue;
}
condp->left = left;
@@ -660,6 +678,7 @@ store_value:
envp = (struct tomoyo_envp *) (argv + e.argc);
{
bool flag = false;
+
for (pos = start_of_string; pos < end_of_string; pos++) {
if (*pos)
continue;
@@ -698,6 +717,7 @@ void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
struct inode *inode;
+
switch (i) {
case TOMOYO_PATH1:
dentry = obj->path1.dentry;
@@ -718,6 +738,7 @@ void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
inode = d_backing_inode(dentry);
if (inode) {
struct tomoyo_mini_stat *stat = &obj->stat[i];
+
stat->uid = inode->i_uid;
stat->gid = inode->i_gid;
stat->ino = inode->i_ino;
@@ -726,8 +747,7 @@ void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
stat->rdev = inode->i_rdev;
obj->stat_valid[i] = true;
}
- if (i & 1) /* i == TOMOYO_PATH1_PARENT ||
- i == TOMOYO_PATH2_PARENT */
+ if (i & 1) /* TOMOYO_PATH1_PARENT or TOMOYO_PATH2_PARENT */
dput(dentry);
}
}
@@ -758,6 +778,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r,
u16 argc;
u16 envc;
struct linux_binprm *bprm = NULL;
+
if (!cond)
return true;
condc = cond->condc;
@@ -780,6 +801,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r,
const u8 right = condp->right;
bool is_bitop[2] = { false, false };
u8 j;
+
condp++;
/* Check argv[] and envp[] later. */
if (left == TOMOYO_ARGV_ENTRY || left == TOMOYO_ENVP_ENTRY)
@@ -787,10 +809,11 @@ bool tomoyo_condition(struct tomoyo_request_info *r,
/* Check string expressions. */
if (right == TOMOYO_NAME_UNION) {
const struct tomoyo_name_union *ptr = names_p++;
+ struct tomoyo_path_info *symlink;
+ struct tomoyo_execve *ee;
+ struct file *file;
+
switch (left) {
- struct tomoyo_path_info *symlink;
- struct tomoyo_execve *ee;
- struct file *file;
case TOMOYO_SYMLINK_TARGET:
symlink = obj ? obj->symlink_target : NULL;
if (!symlink ||
@@ -812,6 +835,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r,
for (j = 0; j < 2; j++) {
const u8 index = j ? right : left;
unsigned long value = 0;
+
switch (index) {
case TOMOYO_TASK_UID:
value = from_kuid(&init_user_ns, current_uid());
@@ -874,31 +898,31 @@ bool tomoyo_condition(struct tomoyo_request_info *r,
value = S_ISVTX;
break;
case TOMOYO_MODE_OWNER_READ:
- value = S_IRUSR;
+ value = 0400;
break;
case TOMOYO_MODE_OWNER_WRITE:
- value = S_IWUSR;
+ value = 0200;
break;
case TOMOYO_MODE_OWNER_EXECUTE:
- value = S_IXUSR;
+ value = 0100;
break;
case TOMOYO_MODE_GROUP_READ:
- value = S_IRGRP;
+ value = 0040;
break;
case TOMOYO_MODE_GROUP_WRITE:
- value = S_IWGRP;
+ value = 0020;
break;
case TOMOYO_MODE_GROUP_EXECUTE:
- value = S_IXGRP;
+ value = 0010;
break;
case TOMOYO_MODE_OTHERS_READ:
- value = S_IROTH;
+ value = 0004;
break;
case TOMOYO_MODE_OTHERS_WRITE:
- value = S_IWOTH;
+ value = 0002;
break;
case TOMOYO_MODE_OTHERS_EXECUTE:
- value = S_IXOTH;
+ value = 0001;
break;
case TOMOYO_EXEC_ARGC:
if (!bprm)
@@ -923,6 +947,7 @@ bool tomoyo_condition(struct tomoyo_request_info *r,
{
u8 stat_index;
struct tomoyo_mini_stat *stat;
+
switch (index) {
case TOMOYO_PATH1_UID:
case TOMOYO_PATH1_GID:
@@ -1036,12 +1061,14 @@ bool tomoyo_condition(struct tomoyo_request_info *r,
if (left == TOMOYO_NUMBER_UNION) {
/* Fetch values now. */
const struct tomoyo_number_union *ptr = numbers_p++;
+
min_v[0] = ptr->values[0];
max_v[0] = ptr->values[1];
}
if (right == TOMOYO_NUMBER_UNION) {
/* Fetch values now. */
const struct tomoyo_number_union *ptr = numbers_p++;
+
if (ptr->group) {
if (tomoyo_number_matches_group(min_v[0],
max_v[0],
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index f6758dad981f..8526a0a74023 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -30,10 +30,10 @@ struct tomoyo_domain_info tomoyo_kernel_domain;
*/
int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
struct tomoyo_acl_param *param,
- bool (*check_duplicate) (const struct tomoyo_acl_head
- *,
- const struct tomoyo_acl_head
- *))
+ bool (*check_duplicate)(const struct tomoyo_acl_head
+ *,
+ const struct tomoyo_acl_head
+ *))
{
int error = param->is_delete ? -ENOENT : -ENOMEM;
struct tomoyo_acl_head *entry;
@@ -90,13 +90,13 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
*/
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
struct tomoyo_acl_param *param,
- bool (*check_duplicate) (const struct tomoyo_acl_info
- *,
- const struct tomoyo_acl_info
- *),
- bool (*merge_duplicate) (struct tomoyo_acl_info *,
- struct tomoyo_acl_info *,
- const bool))
+ bool (*check_duplicate)(const struct tomoyo_acl_info
+ *,
+ const struct tomoyo_acl_info
+ *),
+ bool (*merge_duplicate)(struct tomoyo_acl_info *,
+ struct tomoyo_acl_info *,
+ const bool))
{
const bool is_delete = param->is_delete;
int error = is_delete ? -ENOENT : -ENOMEM;
@@ -157,13 +157,13 @@ out:
* Caller holds tomoyo_read_lock().
*/
void tomoyo_check_acl(struct tomoyo_request_info *r,
- bool (*check_entry) (struct tomoyo_request_info *,
- const struct tomoyo_acl_info *))
+ bool (*check_entry)(struct tomoyo_request_info *,
+ const struct tomoyo_acl_info *))
{
const struct tomoyo_domain_info *domain = r->domain;
struct tomoyo_acl_info *ptr;
- bool retried = false;
const struct list_head *list = &domain->acl_info_list;
+ u16 i = 0;
retry:
list_for_each_entry_rcu(ptr, list, list) {
@@ -177,9 +177,10 @@ retry:
r->granted = true;
return;
}
- if (!retried) {
- retried = true;
- list = &domain->ns->acl_group[domain->group];
+ for (; i < TOMOYO_MAX_ACL_GROUPS; i++) {
+ if (!test_bit(i, domain->group))
+ continue;
+ list = &domain->ns->acl_group[i++];
goto retry;
}
r->granted = false;
@@ -198,6 +199,7 @@ LIST_HEAD(tomoyo_domain_list);
static const char *tomoyo_last_word(const char *name)
{
const char *cp = strrchr(name, ' ');
+
if (cp)
return cp + 1;
return name;
@@ -220,6 +222,7 @@ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
const struct tomoyo_transition_control *p2 = container_of(b,
typeof(*p2),
head);
+
return p1->type == p2->type && p1->is_last_name == p2->is_last_name
&& p1->domainname == p2->domainname
&& p1->program == p2->program;
@@ -240,6 +243,7 @@ int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
int error = param->is_delete ? -ENOENT : -ENOMEM;
char *program = param->data;
char *domainname = strstr(program, " from ");
+
if (domainname) {
*domainname = '\0';
domainname += 6;
@@ -293,6 +297,7 @@ static inline bool tomoyo_scan_transition
const enum tomoyo_transition_type type)
{
const struct tomoyo_transition_control *ptr;
+
list_for_each_entry_rcu(ptr, list, head.list) {
if (ptr->head.is_deleted || ptr->type != type)
continue;
@@ -338,9 +343,11 @@ static enum tomoyo_transition_type tomoyo_transition_type
{
const char *last_name = tomoyo_last_word(domainname->name);
enum tomoyo_transition_type type = TOMOYO_TRANSITION_CONTROL_NO_RESET;
+
while (type < TOMOYO_MAX_TRANSITION_TYPE) {
const struct list_head * const list =
&ns->policy_list[TOMOYO_ID_TRANSITION_CONTROL];
+
if (!tomoyo_scan_transition(list, domainname, program,
last_name, type)) {
type++;
@@ -375,6 +382,7 @@ static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
head);
const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
head);
+
return p1->original_name == p2->original_name &&
p1->aggregated_name == p2->aggregated_name;
}
@@ -394,6 +402,7 @@ int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
int error = param->is_delete ? -ENOENT : -ENOMEM;
const char *original_name = tomoyo_read_token(param);
const char *aggregated_name = tomoyo_read_token(param);
+
if (!tomoyo_correct_word(original_name) ||
!tomoyo_correct_path(aggregated_name))
return -EINVAL;
@@ -426,6 +435,7 @@ static struct tomoyo_policy_namespace *tomoyo_find_namespace
(const char *name, const unsigned int len)
{
struct tomoyo_policy_namespace *ns;
+
list_for_each_entry(ns, &tomoyo_namespace_list, namespace_list) {
if (strncmp(name, ns->name, len) ||
(name[len] && name[len] != ' '))
@@ -451,6 +461,7 @@ struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
struct tomoyo_policy_namespace *entry;
const char *cp = domainname;
unsigned int len = 0;
+
while (*cp && *cp++ != ' ')
len++;
ptr = tomoyo_find_namespace(domainname, len);
@@ -466,6 +477,7 @@ struct tomoyo_policy_namespace *tomoyo_assign_namespace(const char *domainname)
ptr = tomoyo_find_namespace(domainname, len);
if (!ptr && tomoyo_memory_ok(entry)) {
char *name = (char *) (entry + 1);
+
ptr = entry;
memmove(name, domainname, len);
name[len] = '\0';
@@ -490,6 +502,7 @@ static bool tomoyo_namespace_jump(const char *domainname)
{
const char *namespace = tomoyo_current_namespace()->name;
const int len = strlen(namespace);
+
return strncmp(domainname, namespace, len) ||
(domainname[len] && domainname[len] != ' ');
}
@@ -510,6 +523,7 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
struct tomoyo_domain_info e = { };
struct tomoyo_domain_info *entry = tomoyo_find_domain(domainname);
bool created = false;
+
if (entry) {
if (transit) {
/*
@@ -546,8 +560,9 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
*/
if (transit) {
const struct tomoyo_domain_info *domain = tomoyo_domain();
+
e.profile = domain->profile;
- e.group = domain->group;
+ memcpy(e.group, domain->group, sizeof(e.group));
}
e.domainname = tomoyo_get_name(domainname);
if (!e.domainname)
@@ -569,12 +584,17 @@ out:
if (entry && transit) {
if (created) {
struct tomoyo_request_info r;
+ int i;
+
tomoyo_init_request_info(&r, entry,
TOMOYO_MAC_FILE_EXECUTE);
r.granted = false;
tomoyo_write_log(&r, "use_profile %u\n",
entry->profile);
- tomoyo_write_log(&r, "use_group %u\n", entry->group);
+ for (i = 0; i < TOMOYO_MAX_ACL_GROUPS; i++)
+ if (test_bit(i, entry->group))
+ tomoyo_write_log(&r, "use_group %u\n",
+ i);
tomoyo_update_stat(TOMOYO_STAT_POLICY_UPDATES);
}
}
@@ -712,6 +732,7 @@ retry:
struct tomoyo_aggregator *ptr;
struct list_head *list =
&old_domain->ns->policy_list[TOMOYO_ID_AGGREGATOR];
+
/* Check 'aggregator' directive. */
candidate = &exename;
list_for_each_entry_rcu(ptr, list, head.list) {
@@ -747,6 +768,7 @@ retry:
*/
if (ee->transition) {
const char *domainname = ee->transition->name;
+
reject_on_transition_failure = true;
if (!strcmp(domainname, "keep"))
goto force_keep_domain;
@@ -758,6 +780,7 @@ retry:
goto force_initialize_domain;
if (!strcmp(domainname, "parent")) {
char *cp;
+
strncpy(ee->tmp, old_domain->domainname->name,
TOMOYO_EXEC_TMPSIZE - 1);
cp = strrchr(ee->tmp, ' ');
@@ -822,8 +845,7 @@ force_jump_domain:
if (domain)
retval = 0;
else if (reject_on_transition_failure) {
- printk(KERN_WARNING "ERROR: Domain '%s' not ready.\n",
- ee->tmp);
+ pr_warn("ERROR: Domain '%s' not ready.\n", ee->tmp);
retval = -ENOMEM;
} else if (ee->r.mode == TOMOYO_CONFIG_ENFORCING)
retval = -ENOMEM;
@@ -834,16 +856,20 @@ force_jump_domain:
ee->r.granted = false;
tomoyo_write_log(&ee->r, "%s", tomoyo_dif
[TOMOYO_DIF_TRANSITION_FAILED]);
- printk(KERN_WARNING
- "ERROR: Domain '%s' not defined.\n", ee->tmp);
+ pr_warn("ERROR: Domain '%s' not defined.\n", ee->tmp);
}
}
out:
if (!domain)
domain = old_domain;
/* Update reference count on "struct tomoyo_domain_info". */
- atomic_inc(&domain->users);
- bprm->cred->security = domain;
+ {
+ struct tomoyo_task *s = tomoyo_task(current);
+
+ s->old_domain_info = s->domain_info;
+ s->domain_info = domain;
+ atomic_inc(&domain->users);
+ }
kfree(exename.name);
if (!retval) {
ee->r.domain = domain;
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 2a374b4da8f5..86f7d1b90212 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -214,6 +214,7 @@ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r)
const u8 type = r->param.path_number.operation;
u8 radix;
char buffer[64];
+
switch (type) {
case TOMOYO_TYPE_CREATE:
case TOMOYO_TYPE_MKDIR:
@@ -253,6 +254,7 @@ static bool tomoyo_check_path_acl(struct tomoyo_request_info *r,
{
const struct tomoyo_path_acl *acl = container_of(ptr, typeof(*acl),
head);
+
if (acl->perm & (1 << r->param.path.operation)) {
r->param.path.matched_path =
tomoyo_compare_name_union(r->param.path.filename,
@@ -275,6 +277,7 @@ static bool tomoyo_check_path_number_acl(struct tomoyo_request_info *r,
{
const struct tomoyo_path_number_acl *acl =
container_of(ptr, typeof(*acl), head);
+
return (acl->perm & (1 << r->param.path_number.operation)) &&
tomoyo_compare_number_union(r->param.path_number.number,
&acl->number) &&
@@ -295,6 +298,7 @@ static bool tomoyo_check_path2_acl(struct tomoyo_request_info *r,
{
const struct tomoyo_path2_acl *acl =
container_of(ptr, typeof(*acl), head);
+
return (acl->perm & (1 << r->param.path2.operation)) &&
tomoyo_compare_name_union(r->param.path2.filename1, &acl->name1)
&& tomoyo_compare_name_union(r->param.path2.filename2,
@@ -314,6 +318,7 @@ static bool tomoyo_check_mkdev_acl(struct tomoyo_request_info *r,
{
const struct tomoyo_mkdev_acl *acl =
container_of(ptr, typeof(*acl), head);
+
return (acl->perm & (1 << r->param.mkdev.operation)) &&
tomoyo_compare_number_union(r->param.mkdev.mode,
&acl->mode) &&
@@ -338,6 +343,7 @@ static bool tomoyo_same_path_acl(const struct tomoyo_acl_info *a,
{
const struct tomoyo_path_acl *p1 = container_of(a, typeof(*p1), head);
const struct tomoyo_path_acl *p2 = container_of(b, typeof(*p2), head);
+
return tomoyo_same_name_union(&p1->name, &p2->name);
}
@@ -358,6 +364,7 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
->perm;
u16 perm = *a_perm;
const u16 b_perm = container_of(b, struct tomoyo_path_acl, head)->perm;
+
if (is_delete)
perm &= ~b_perm;
else
@@ -384,6 +391,7 @@ static int tomoyo_update_path_acl(const u16 perm,
.perm = perm
};
int error;
+
if (!tomoyo_parse_name_union(param, &e.name))
error = -EINVAL;
else
@@ -407,6 +415,7 @@ static bool tomoyo_same_mkdev_acl(const struct tomoyo_acl_info *a,
{
const struct tomoyo_mkdev_acl *p1 = container_of(a, typeof(*p1), head);
const struct tomoyo_mkdev_acl *p2 = container_of(b, typeof(*p2), head);
+
return tomoyo_same_name_union(&p1->name, &p2->name) &&
tomoyo_same_number_union(&p1->mode, &p2->mode) &&
tomoyo_same_number_union(&p1->major, &p2->major) &&
@@ -431,6 +440,7 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
u8 perm = *a_perm;
const u8 b_perm = container_of(b, struct tomoyo_mkdev_acl, head)
->perm;
+
if (is_delete)
perm &= ~b_perm;
else
@@ -457,6 +467,7 @@ static int tomoyo_update_mkdev_acl(const u8 perm,
.perm = perm
};
int error;
+
if (!tomoyo_parse_name_union(param, &e.name) ||
!tomoyo_parse_number_union(param, &e.mode) ||
!tomoyo_parse_number_union(param, &e.major) ||
@@ -486,6 +497,7 @@ static bool tomoyo_same_path2_acl(const struct tomoyo_acl_info *a,
{
const struct tomoyo_path2_acl *p1 = container_of(a, typeof(*p1), head);
const struct tomoyo_path2_acl *p2 = container_of(b, typeof(*p2), head);
+
return tomoyo_same_name_union(&p1->name1, &p2->name1) &&
tomoyo_same_name_union(&p1->name2, &p2->name2);
}
@@ -507,6 +519,7 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
->perm;
u8 perm = *a_perm;
const u8 b_perm = container_of(b, struct tomoyo_path2_acl, head)->perm;
+
if (is_delete)
perm &= ~b_perm;
else
@@ -533,6 +546,7 @@ static int tomoyo_update_path2_acl(const u8 perm,
.perm = perm
};
int error;
+
if (!tomoyo_parse_name_union(param, &e.name1) ||
!tomoyo_parse_name_union(param, &e.name2))
error = -EINVAL;
@@ -621,6 +635,7 @@ static bool tomoyo_same_path_number_acl(const struct tomoyo_acl_info *a,
head);
const struct tomoyo_path_number_acl *p2 = container_of(b, typeof(*p2),
head);
+
return tomoyo_same_name_union(&p1->name, &p2->name) &&
tomoyo_same_number_union(&p1->number, &p2->number);
}
@@ -643,6 +658,7 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
u8 perm = *a_perm;
const u8 b_perm = container_of(b, struct tomoyo_path_number_acl, head)
->perm;
+
if (is_delete)
perm &= ~b_perm;
else
@@ -667,6 +683,7 @@ static int tomoyo_update_path_number_acl(const u8 perm,
.perm = perm
};
int error;
+
if (!tomoyo_parse_name_union(param, &e.name) ||
!tomoyo_parse_number_union(param, &e.number))
error = -EINVAL;
@@ -947,6 +964,7 @@ static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
{
const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
+
return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
@@ -966,6 +984,7 @@ static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
{
struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
int error;
+
if (!tomoyo_parse_name_union(param, &e.dev_name) ||
!tomoyo_parse_name_union(param, &e.dir_name) ||
!tomoyo_parse_name_union(param, &e.fs_type) ||
@@ -995,6 +1014,7 @@ int tomoyo_write_file(struct tomoyo_acl_param *param)
u16 perm = 0;
u8 type;
const char *operation = tomoyo_read_token(param);
+
for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
perm |= 1 << type;
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
index e22bea811c57..9537832fca18 100644
--- a/security/tomoyo/gc.c
+++ b/security/tomoyo/gc.c
@@ -77,11 +77,13 @@ static bool tomoyo_name_used_by_io_buffer(const char *string)
spin_lock(&tomoyo_io_buffer_list_lock);
list_for_each_entry(head, &tomoyo_io_buffer_list, list) {
int i;
+
head->users++;
spin_unlock(&tomoyo_io_buffer_list_lock);
mutex_lock(&head->io_sem);
for (i = 0; i < TOMOYO_MAX_IO_READ_QUEUE; i++) {
const char *w = head->r.w[i];
+
if (w < string || w > string + size)
continue;
in_use = true;
@@ -108,6 +110,7 @@ static inline void tomoyo_del_transition_control(struct list_head *element)
{
struct tomoyo_transition_control *ptr =
container_of(element, typeof(*ptr), head.list);
+
tomoyo_put_name(ptr->domainname);
tomoyo_put_name(ptr->program);
}
@@ -123,6 +126,7 @@ static inline void tomoyo_del_aggregator(struct list_head *element)
{
struct tomoyo_aggregator *ptr =
container_of(element, typeof(*ptr), head.list);
+
tomoyo_put_name(ptr->original_name);
tomoyo_put_name(ptr->aggregated_name);
}
@@ -138,6 +142,7 @@ static inline void tomoyo_del_manager(struct list_head *element)
{
struct tomoyo_manager *ptr =
container_of(element, typeof(*ptr), head.list);
+
tomoyo_put_name(ptr->manager);
}
@@ -152,6 +157,7 @@ static void tomoyo_del_acl(struct list_head *element)
{
struct tomoyo_acl_info *acl =
container_of(element, typeof(*acl), list);
+
tomoyo_put_condition(acl->cond);
switch (acl->type) {
case TOMOYO_TYPE_PATH_ACL:
@@ -226,6 +232,7 @@ static void tomoyo_del_acl(struct list_head *element)
{
struct tomoyo_task_acl *entry =
container_of(acl, typeof(*entry), head);
+
tomoyo_put_name(entry->domainname);
}
break;
@@ -247,6 +254,7 @@ static inline void tomoyo_del_domain(struct list_head *element)
container_of(element, typeof(*domain), list);
struct tomoyo_acl_info *acl;
struct tomoyo_acl_info *tmp;
+
/*
* Since this domain is referenced from neither
* "struct tomoyo_io_buffer" nor "struct cred"->security, we can delete
@@ -286,6 +294,7 @@ void tomoyo_del_condition(struct list_head *element)
= (const struct tomoyo_argv *) (names_p + names_count);
const struct tomoyo_envp *envp
= (const struct tomoyo_envp *) (argv + argc);
+
for (i = 0; i < numbers_count; i++)
tomoyo_put_number_union(numbers_p++);
for (i = 0; i < names_count; i++)
@@ -321,6 +330,7 @@ static inline void tomoyo_del_path_group(struct list_head *element)
{
struct tomoyo_path_group *member =
container_of(element, typeof(*member), head.list);
+
tomoyo_put_name(member->member_name);
}
@@ -335,6 +345,7 @@ static inline void tomoyo_del_group(struct list_head *element)
{
struct tomoyo_group *group =
container_of(element, typeof(*group), head.list);
+
tomoyo_put_name(group->group_name);
}
@@ -476,6 +487,7 @@ static void tomoyo_collect_member(const enum tomoyo_policy_id id,
{
struct tomoyo_acl_head *member;
struct tomoyo_acl_head *tmp;
+
list_for_each_entry_safe(member, tmp, member_list, list) {
if (!member->is_deleted)
continue;
@@ -495,6 +507,7 @@ static void tomoyo_collect_acl(struct list_head *list)
{
struct tomoyo_acl_info *acl;
struct tomoyo_acl_info *tmp;
+
list_for_each_entry_safe(acl, tmp, list, list) {
if (!acl->is_deleted)
continue;
@@ -513,10 +526,12 @@ static void tomoyo_collect_entry(void)
int i;
enum tomoyo_policy_id id;
struct tomoyo_policy_namespace *ns;
+
mutex_lock(&tomoyo_policy_lock);
{
struct tomoyo_domain_info *domain;
struct tomoyo_domain_info *tmp;
+
list_for_each_entry_safe(domain, tmp, &tomoyo_domain_list,
list) {
tomoyo_collect_acl(&domain->acl_info_list);
@@ -534,6 +549,7 @@ static void tomoyo_collect_entry(void)
{
struct tomoyo_shared_acl_head *ptr;
struct tomoyo_shared_acl_head *tmp;
+
list_for_each_entry_safe(ptr, tmp, &tomoyo_condition_list,
list) {
if (atomic_read(&ptr->users) > 0)
@@ -547,6 +563,7 @@ static void tomoyo_collect_entry(void)
struct list_head *list = &ns->group_list[i];
struct tomoyo_group *group;
struct tomoyo_group *tmp;
+
switch (i) {
case 0:
id = TOMOYO_ID_PATH_GROUP;
@@ -574,6 +591,7 @@ static void tomoyo_collect_entry(void)
struct list_head *list = &tomoyo_name_list[i];
struct tomoyo_shared_acl_head *ptr;
struct tomoyo_shared_acl_head *tmp;
+
list_for_each_entry_safe(ptr, tmp, list, list) {
if (atomic_read(&ptr->users) > 0)
continue;
@@ -595,6 +613,7 @@ static int tomoyo_gc_thread(void *unused)
{
/* Garbage collector thread is exclusive. */
static DEFINE_MUTEX(tomoyo_gc_mutex);
+
if (!mutex_trylock(&tomoyo_gc_mutex))
goto out;
tomoyo_collect_entry();
diff --git a/security/tomoyo/group.c b/security/tomoyo/group.c
index 21b0cc3a7e1a..a37c7dc66e44 100644
--- a/security/tomoyo/group.c
+++ b/security/tomoyo/group.c
@@ -75,11 +75,13 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type)
{
struct tomoyo_group *group = tomoyo_get_group(param, type);
int error = -EINVAL;
+
if (!group)
return -ENOMEM;
param->list = &group->member_list;
if (type == TOMOYO_PATH_GROUP) {
struct tomoyo_path_group e = { };
+
e.member_name = tomoyo_get_name(tomoyo_read_token(param));
if (!e.member_name) {
error = -ENOMEM;
@@ -90,6 +92,7 @@ int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type)
tomoyo_put_name(e.member_name);
} else if (type == TOMOYO_NUMBER_GROUP) {
struct tomoyo_number_group e = { };
+
if (param->data[0] == '@' ||
!tomoyo_parse_number_union(param, &e.number))
goto out;
@@ -129,6 +132,7 @@ tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
const struct tomoyo_group *group)
{
struct tomoyo_path_group *member;
+
list_for_each_entry_rcu(member, &group->member_list, head.list) {
if (member->head.is_deleted)
continue;
@@ -156,6 +160,7 @@ bool tomoyo_number_matches_group(const unsigned long min,
{
struct tomoyo_number_group *member;
bool matched = false;
+
list_for_each_entry_rcu(member, &group->member_list, head.list) {
if (member->head.is_deleted)
continue;
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c
index 81b951652051..3445ae6fd479 100644
--- a/security/tomoyo/load_policy.c
+++ b/security/tomoyo/load_policy.c
@@ -37,11 +37,12 @@ __setup("TOMOYO_loader=", tomoyo_loader_setup);
static bool tomoyo_policy_loader_exists(void)
{
struct path path;
+
if (!tomoyo_loader)
tomoyo_loader = CONFIG_SECURITY_TOMOYO_POLICY_LOADER;
if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
- printk(KERN_INFO "Not activating Mandatory Access Control "
- "as %s does not exist.\n", tomoyo_loader);
+ pr_info("Not activating Mandatory Access Control as %s does not exist.\n",
+ tomoyo_loader);
return false;
}
path_put(&path);
@@ -96,8 +97,7 @@ void tomoyo_load_policy(const char *filename)
if (!tomoyo_policy_loader_exists())
return;
done = true;
- printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
- tomoyo_loader);
+ pr_info("Calling %s to load policy. Please wait.\n", tomoyo_loader);
argv[0] = (char *) tomoyo_loader;
argv[1] = NULL;
envp[0] = "HOME=/";
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c
index 12477e0b0a11..2e7fcfa923c9 100644
--- a/security/tomoyo/memory.c
+++ b/security/tomoyo/memory.c
@@ -19,9 +19,9 @@ void tomoyo_warn_oom(const char *function)
/* Reduce error messages. */
static pid_t tomoyo_last_pid;
const pid_t pid = current->pid;
+
if (tomoyo_last_pid != pid) {
- printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
- function);
+ pr_warn("ERROR: Out of memory at %s.\n", function);
tomoyo_last_pid = pid;
}
if (!tomoyo_policy_loaded)
@@ -48,6 +48,7 @@ bool tomoyo_memory_ok(void *ptr)
{
if (ptr) {
const size_t s = ksize(ptr);
+
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] += s;
if (!tomoyo_memory_quota[TOMOYO_MEMORY_POLICY] ||
tomoyo_memory_used[TOMOYO_MEMORY_POLICY] <=
@@ -73,6 +74,7 @@ bool tomoyo_memory_ok(void *ptr)
void *tomoyo_commit_ok(void *data, const unsigned int size)
{
void *ptr = kzalloc(size, GFP_NOFS);
+
if (tomoyo_memory_ok(ptr)) {
memmove(ptr, data, size);
memset(data, 0, size);
@@ -98,6 +100,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
struct list_head *list;
const char *group_name = tomoyo_read_token(param);
bool found = false;
+
if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
return NULL;
e.group_name = tomoyo_get_name(group_name);
@@ -116,6 +119,7 @@ struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
}
if (!found) {
struct tomoyo_group *entry = tomoyo_commit_ok(&e, sizeof(e));
+
if (entry) {
INIT_LIST_HEAD(&entry->member_list);
atomic_set(&entry->head.users, 1);
@@ -191,6 +195,7 @@ struct tomoyo_policy_namespace tomoyo_kernel_namespace;
void __init tomoyo_mm_init(void)
{
int idx;
+
for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
INIT_LIST_HEAD(&tomoyo_name_list[idx]);
tomoyo_kernel_namespace.name = "<kernel>";
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
index 7dc7f59b7dde..2755971f50df 100644
--- a/security/tomoyo/mount.c
+++ b/security/tomoyo/mount.c
@@ -49,6 +49,7 @@ static bool tomoyo_check_mount_acl(struct tomoyo_request_info *r,
{
const struct tomoyo_mount_acl *acl =
container_of(ptr, typeof(*acl), head);
+
return tomoyo_compare_number_union(r->param.mount.flags,
&acl->flags) &&
tomoyo_compare_name_union(r->param.mount.type,
@@ -89,6 +90,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r,
struct tomoyo_path_info rdir;
int need_dev = 0;
int error = -ENOMEM;
+
r->obj = &obj;
/* Get fstype. */
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index 6ff8c21e4fff..85e6e31dd1e5 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -94,11 +94,13 @@ static char *tomoyo_get_absolute_path(const struct path *path, char * const buff
const int buflen)
{
char *pos = ERR_PTR(-ENOMEM);
+
if (buflen >= 256) {
/* go to whatever namespace root we are under */
pos = d_absolute_path(path, buffer, buflen - 1);
if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
struct inode *inode = d_backing_inode(path->dentry);
+
if (inode && S_ISDIR(inode->i_mode)) {
buffer[buflen - 2] = '/';
buffer[buflen - 1] = '\0';
@@ -123,10 +125,12 @@ static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
const int buflen)
{
char *pos = ERR_PTR(-ENOMEM);
+
if (buflen >= 256) {
pos = dentry_path_raw(dentry, buffer, buflen - 1);
if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
struct inode *inode = d_backing_inode(dentry);
+
if (inode && S_ISDIR(inode->i_mode)) {
buffer[buflen - 2] = '/';
buffer[buflen - 1] = '\0';
@@ -150,12 +154,14 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
{
struct super_block *sb = dentry->d_sb;
char *pos = tomoyo_get_dentry_path(dentry, buffer, buflen);
+
if (IS_ERR(pos))
return pos;
/* Convert from $PID to self if $PID is current thread. */
if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
char *ep;
const pid_t pid = (pid_t) simple_strtoul(pos + 1, &ep, 10);
+
if (*ep == '/' && pid && pid ==
task_tgid_nr_ns(current, sb->s_fs_info)) {
pos = ep - 5;
@@ -170,6 +176,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
goto prepend_filesystem_name;
{
struct inode *inode = d_backing_inode(sb->s_root);
+
/*
* Use filesystem name if filesystem does not support rename()
* operation.
@@ -182,6 +189,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
char name[64];
int name_len;
const dev_t dev = sb->s_dev;
+
name[sizeof(name) - 1] = '\0';
snprintf(name, sizeof(name) - 1, "dev(%u,%u):", MAJOR(dev),
MINOR(dev));
@@ -197,6 +205,7 @@ prepend_filesystem_name:
{
const char *name = sb->s_type->name;
const int name_len = strlen(name);
+
pos -= name_len + 1;
if (pos < buffer)
goto out;
@@ -223,10 +232,10 @@ static char *tomoyo_get_socket_name(const struct path *path, char * const buffer
struct inode *inode = d_backing_inode(path->dentry);
struct socket *sock = inode ? SOCKET_I(inode) : NULL;
struct sock *sk = sock ? sock->sk : NULL;
+
if (sk) {
- snprintf(buffer, buflen, "socket:[family=%u:type=%u:"
- "protocol=%u]", sk->sk_family, sk->sk_type,
- sk->sk_protocol);
+ snprintf(buffer, buflen, "socket:[family=%u:type=%u:protocol=%u]",
+ sk->sk_family, sk->sk_type, sk->sk_protocol);
} else {
snprintf(buffer, buflen, "socket:[unknown]");
}
@@ -255,12 +264,14 @@ char *tomoyo_realpath_from_path(const struct path *path)
unsigned int buf_len = PAGE_SIZE / 2;
struct dentry *dentry = path->dentry;
struct super_block *sb;
+
if (!dentry)
return NULL;
sb = dentry->d_sb;
while (1) {
char *pos;
struct inode *inode;
+
buf_len <<= 1;
kfree(buf);
buf = kmalloc(buf_len, GFP_NOFS);
@@ -323,6 +334,7 @@ char *tomoyo_realpath_nofollow(const char *pathname)
if (pathname && kern_path(pathname, 0, &path) == 0) {
char *buf = tomoyo_realpath_from_path(&path);
+
path_put(&path);
return buf;
}
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 1d3d7e7a1f05..546281c5b233 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -21,6 +21,7 @@ static bool tomoyo_check_task_acl(struct tomoyo_request_info *r,
{
const struct tomoyo_task_acl *acl = container_of(ptr, typeof(*acl),
head);
+
return !tomoyo_pathcmp(r->param.task.domainname, acl->domainname);
}
@@ -42,6 +43,7 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
{
char *data;
int error;
+
if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
return -ENOMEM;
data = memdup_user_nul(buf, count);
@@ -52,6 +54,7 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
const int idx = tomoyo_read_lock();
struct tomoyo_path_info name;
struct tomoyo_request_info r;
+
name.name = data;
tomoyo_fill_path_info(&name);
/* Check "task manual_domain_transition" permission. */
@@ -67,18 +70,14 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
if (!new_domain) {
error = -ENOENT;
} else {
- struct cred *cred = prepare_creds();
- if (!cred) {
- error = -ENOMEM;
- } else {
- struct tomoyo_domain_info *old_domain =
- cred->security;
- cred->security = new_domain;
- atomic_inc(&new_domain->users);
- atomic_dec(&old_domain->users);
- commit_creds(cred);
- error = 0;
- }
+ struct tomoyo_task *s = tomoyo_task(current);
+ struct tomoyo_domain_info *old_domain =
+ s->domain_info;
+
+ s->domain_info = new_domain;
+ atomic_inc(&new_domain->users);
+ atomic_dec(&old_domain->users);
+ error = 0;
}
}
tomoyo_read_unlock(idx);
@@ -104,6 +103,7 @@ static ssize_t tomoyo_read_self(struct file *file, char __user *buf,
const char *domain = tomoyo_domain()->domainname->name;
loff_t len = strlen(domain);
loff_t pos = *ppos;
+
if (pos >= len || !count)
return 0;
len -= pos;
@@ -234,10 +234,14 @@ static void __init tomoyo_create_entry(const char *name, const umode_t mode,
*/
static int __init tomoyo_initerface_init(void)
{
+ struct tomoyo_domain_info *domain;
struct dentry *tomoyo_dir;
+ if (!tomoyo_enabled)
+ return 0;
+ domain = tomoyo_domain();
/* Don't create securityfs entries unless registered. */
- if (current_cred()->security != &tomoyo_kernel_domain)
+ if (domain != &tomoyo_kernel_domain)
return 0;
tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 1b5b5097efd7..716c92ec941a 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -9,17 +9,19 @@
#include "common.h"
/**
- * tomoyo_cred_alloc_blank - Target for security_cred_alloc_blank().
+ * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
*
- * @new: Pointer to "struct cred".
- * @gfp: Memory allocation flags.
- *
- * Returns 0.
+ * Returns pointer to "struct tomoyo_domain_info" for current thread.
*/
-static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
+struct tomoyo_domain_info *tomoyo_domain(void)
{
- new->security = NULL;
- return 0;
+ struct tomoyo_task *s = tomoyo_task(current);
+
+ if (s->old_domain_info && !current->in_execve) {
+ atomic_dec(&s->old_domain_info->users);
+ s->old_domain_info = NULL;
+ }
+ return s->domain_info;
}
/**
@@ -34,42 +36,38 @@ static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
static int tomoyo_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
- struct tomoyo_domain_info *domain = old->security;
- new->security = domain;
- if (domain)
- atomic_inc(&domain->users);
+ /* Restore old_domain_info saved by previous execve() request. */
+ struct tomoyo_task *s = tomoyo_task(current);
+
+ if (s->old_domain_info && !current->in_execve) {
+ atomic_dec(&s->domain_info->users);
+ s->domain_info = s->old_domain_info;
+ s->old_domain_info = NULL;
+ }
return 0;
}
/**
- * tomoyo_cred_transfer - Target for security_transfer_creds().
+ * tomoyo_bprm_committed_creds - Target for security_bprm_committed_creds().
*
- * @new: Pointer to "struct cred".
- * @old: Pointer to "struct cred".
+ * @bprm: Pointer to "struct linux_binprm".
*/
-static void tomoyo_cred_transfer(struct cred *new, const struct cred *old)
+static void tomoyo_bprm_committed_creds(struct linux_binprm *bprm)
{
- tomoyo_cred_prepare(new, old, 0);
-}
+ /* Clear old_domain_info saved by execve() request. */
+ struct tomoyo_task *s = tomoyo_task(current);
-/**
- * tomoyo_cred_free - Target for security_cred_free().
- *
- * @cred: Pointer to "struct cred".
- */
-static void tomoyo_cred_free(struct cred *cred)
-{
- struct tomoyo_domain_info *domain = cred->security;
- if (domain)
- atomic_dec(&domain->users);
+ atomic_dec(&s->old_domain_info->users);
+ s->old_domain_info = NULL;
}
+#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
/**
* tomoyo_bprm_set_creds - Target for security_bprm_set_creds().
*
* @bprm: Pointer to "struct linux_binprm".
*
- * Returns 0 on success, negative value otherwise.
+ * Returns 0.
*/
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
{
@@ -79,29 +77,15 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
*/
if (bprm->called_set_creds)
return 0;
-#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
/*
* Load policy if /sbin/tomoyo-init exists and /sbin/init is requested
* for the first time.
*/
if (!tomoyo_policy_loaded)
tomoyo_load_policy(bprm->filename);
-#endif
- /*
- * Release reference to "struct tomoyo_domain_info" stored inside
- * "bprm->cred->security". New reference to "struct tomoyo_domain_info"
- * stored inside "bprm->cred->security" will be acquired later inside
- * tomoyo_find_next_domain().
- */
- atomic_dec(&((struct tomoyo_domain_info *)
- bprm->cred->security)->users);
- /*
- * Tell tomoyo_bprm_check_security() is called for the first time of an
- * execve operation.
- */
- bprm->cred->security = NULL;
return 0;
}
+#endif
/**
* tomoyo_bprm_check_security - Target for security_bprm_check().
@@ -112,23 +96,24 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
*/
static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
{
- struct tomoyo_domain_info *domain = bprm->cred->security;
+ struct tomoyo_task *s = tomoyo_task(current);
/*
* Execute permission is checked against pathname passed to do_execve()
* using current domain.
*/
- if (!domain) {
+ if (!s->old_domain_info) {
const int idx = tomoyo_read_lock();
const int err = tomoyo_find_next_domain(bprm);
+
tomoyo_read_unlock(idx);
return err;
}
/*
* Read permission is checked against interpreters using next domain.
*/
- return tomoyo_check_open_permission(domain, &bprm->file->f_path,
- O_RDONLY);
+ return tomoyo_check_open_permission(s->domain_info,
+ &bprm->file->f_path, O_RDONLY);
}
/**
@@ -167,6 +152,7 @@ static int tomoyo_path_truncate(const struct path *path)
static int tomoyo_path_unlink(const struct path *parent, struct dentry *dentry)
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+
return tomoyo_path_perm(TOMOYO_TYPE_UNLINK, &path, NULL);
}
@@ -183,6 +169,7 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry,
umode_t mode)
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+
return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
mode & S_IALLUGO);
}
@@ -198,6 +185,7 @@ static int tomoyo_path_mkdir(const struct path *parent, struct dentry *dentry,
static int tomoyo_path_rmdir(const struct path *parent, struct dentry *dentry)
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+
return tomoyo_path_perm(TOMOYO_TYPE_RMDIR, &path, NULL);
}
@@ -214,6 +202,7 @@ static int tomoyo_path_symlink(const struct path *parent, struct dentry *dentry,
const char *old_name)
{
struct path path = { .mnt = parent->mnt, .dentry = dentry };
+
return tomoyo_path_perm(TOMOYO_TYPE_SYMLINK, &path, old_name);
}
@@ -271,6 +260,7 @@ static int tomoyo_path_link(struct dentry *old_dentry, const struct path *new_di
{
struct path path1 = { .mnt = new_dir->mnt, .dentry = old_dentry };
struct path path2 = { .mnt = new_dir->mnt, .dentry = new_dentry };
+
return tomoyo_path2_perm(TOMOYO_TYPE_LINK, &path1, &path2);
}
@@ -291,6 +281,7 @@ static int tomoyo_path_rename(const struct path *old_parent,
{
struct path path1 = { .mnt = old_parent->mnt, .dentry = old_dentry };
struct path path2 = { .mnt = new_parent->mnt, .dentry = new_dentry };
+
return tomoyo_path2_perm(TOMOYO_TYPE_RENAME, &path1, &path2);
}
@@ -322,11 +313,11 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
*/
static int tomoyo_file_open(struct file *f)
{
- int flags = f->f_flags;
/* Don't check read permission here if called from do_execve(). */
if (current->in_execve)
return 0;
- return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path, flags);
+ return tomoyo_check_open_permission(tomoyo_domain(), &f->f_path,
+ f->f_flags);
}
/**
@@ -370,6 +361,7 @@ static int tomoyo_path_chmod(const struct path *path, umode_t mode)
static int tomoyo_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
{
int error = 0;
+
if (uid_valid(uid))
error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path,
from_kuid(&init_user_ns, uid));
@@ -419,6 +411,7 @@ static int tomoyo_sb_mount(const char *dev_name, const struct path *path,
static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
{
struct path path = { .mnt = mnt, .dentry = mnt->mnt_root };
+
return tomoyo_path_perm(TOMOYO_TYPE_UMOUNT, &path, NULL);
}
@@ -493,16 +486,61 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
return tomoyo_socket_sendmsg_permission(sock, msg, size);
}
+struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = {
+ .lbs_task = sizeof(struct tomoyo_task),
+};
+
+/**
+ * tomoyo_task_alloc - Target for security_task_alloc().
+ *
+ * @task: Pointer to "struct task_struct".
+ * @flags: clone() flags.
+ *
+ * Returns 0.
+ */
+static int tomoyo_task_alloc(struct task_struct *task,
+ unsigned long clone_flags)
+{
+ struct tomoyo_task *old = tomoyo_task(current);
+ struct tomoyo_task *new = tomoyo_task(task);
+
+ new->domain_info = old->domain_info;
+ atomic_inc(&new->domain_info->users);
+ new->old_domain_info = NULL;
+ return 0;
+}
+
+/**
+ * tomoyo_task_free - Target for security_task_free().
+ *
+ * @task: Pointer to "struct task_struct".
+ */
+static void tomoyo_task_free(struct task_struct *task)
+{
+ struct tomoyo_task *s = tomoyo_task(task);
+
+ if (s->domain_info) {
+ atomic_dec(&s->domain_info->users);
+ s->domain_info = NULL;
+ }
+ if (s->old_domain_info) {
+ atomic_dec(&s->old_domain_info->users);
+ s->old_domain_info = NULL;
+ }
+}
+
/*
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
*/
static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
- LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank),
LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare),
- LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer),
- LSM_HOOK_INIT(cred_free, tomoyo_cred_free),
+ LSM_HOOK_INIT(bprm_committed_creds, tomoyo_bprm_committed_creds),
+ LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc),
+ LSM_HOOK_INIT(task_free, tomoyo_task_free),
+#ifndef CONFIG_SECURITY_TOMOYO_OMIT_USERSPACE_LOADER
LSM_HOOK_INIT(bprm_set_creds, tomoyo_bprm_set_creds),
+#endif
LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security),
LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl),
LSM_HOOK_INIT(file_open, tomoyo_file_open),
@@ -531,6 +569,8 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
/* Lock for GC. */
DEFINE_SRCU(tomoyo_ss);
+int tomoyo_enabled __lsm_ro_after_init = 1;
+
/**
* tomoyo_init - Register TOMOYO Linux as a LSM module.
*
@@ -538,19 +578,23 @@ DEFINE_SRCU(tomoyo_ss);
*/
static int __init tomoyo_init(void)
{
- struct cred *cred = (struct cred *) current_cred();
+ struct tomoyo_task *s = tomoyo_task(current);
- if (!security_module_enable("tomoyo"))
- return 0;
/* register ourselves with the security framework */
security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo");
- printk(KERN_INFO "TOMOYO Linux initialized\n");
- cred->security = &tomoyo_kernel_domain;
+ pr_info("TOMOYO Linux initialized\n");
+ s->domain_info = &tomoyo_kernel_domain;
+ atomic_inc(&tomoyo_kernel_domain.users);
+ s->old_domain_info = NULL;
tomoyo_mm_init();
+
return 0;
}
DEFINE_LSM(tomoyo) = {
.name = "tomoyo",
+ .enabled = &tomoyo_enabled,
+ .flags = LSM_FLAG_LEGACY_MAJOR,
+ .blobs = &tomoyo_blob_sizes,
.init = tomoyo_init,
};
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index badffc8271c8..0517cbdd7275 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -91,6 +91,7 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = {
void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp)
{
struct tm tm;
+
time64_to_tm(time64, 0, &tm);
stamp->sec = tm.tm_sec;
stamp->min = tm.tm_min;
@@ -113,6 +114,7 @@ void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp)
bool tomoyo_permstr(const char *string, const char *keyword)
{
const char *cp = strstr(string, keyword);
+
if (cp)
return cp == string || *(cp - 1) == '/';
return false;
@@ -132,6 +134,7 @@ char *tomoyo_read_token(struct tomoyo_acl_param *param)
{
char *pos = param->data;
char *del = strchr(pos, ' ');
+
if (del)
*del++ = '\0';
else
@@ -152,6 +155,7 @@ const struct tomoyo_path_info *tomoyo_get_domainname
{
char *start = param->data;
char *pos = start;
+
while (*pos) {
if (*pos++ != ' ' || *pos++ == '/')
continue;
@@ -181,8 +185,10 @@ u8 tomoyo_parse_ulong(unsigned long *result, char **str)
const char *cp = *str;
char *ep;
int base = 10;
+
if (*cp == '0') {
char c = *(cp + 1);
+
if (c == 'x' || c == 'X') {
base = 16;
cp += 2;
@@ -240,6 +246,7 @@ bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
struct tomoyo_name_union *ptr)
{
char *filename;
+
if (param->data[0] == '@') {
param->data++;
ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP);
@@ -266,6 +273,7 @@ bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
char *data;
u8 type;
unsigned long v;
+
memset(ptr, 0, sizeof(*ptr));
if (param->data[0] == '@') {
param->data++;
@@ -429,6 +437,7 @@ static bool tomoyo_correct_word2(const char *string, size_t len)
unsigned char c;
unsigned char d;
unsigned char e;
+
if (!len)
goto out;
while (len--) {
@@ -533,6 +542,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname)
return true;
while (1) {
const unsigned char *cp = strchr(domainname, ' ');
+
if (!cp)
break;
if (*domainname != '/' ||
@@ -554,6 +564,7 @@ bool tomoyo_domain_def(const unsigned char *buffer)
{
const unsigned char *cp;
int len;
+
if (*buffer != '<')
return false;
cp = strchr(buffer, ' ');
@@ -668,6 +679,9 @@ static bool tomoyo_file_matches_pattern2(const char *filename,
{
while (filename < filename_end && pattern < pattern_end) {
char c;
+ int i;
+ int j;
+
if (*pattern != '\\') {
if (*filename++ != *pattern++)
return false;
@@ -676,8 +690,6 @@ static bool tomoyo_file_matches_pattern2(const char *filename,
c = *filename;
pattern++;
switch (*pattern) {
- int i;
- int j;
case '?':
if (c == '/') {
return false;
@@ -985,6 +997,7 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
struct tomoyo_domain_info *domain, const u8 index)
{
u8 profile;
+
memset(r, 0, sizeof(*r));
if (!domain)
domain = tomoyo_domain();
@@ -1018,6 +1031,7 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
u16 perm;
u8 i;
+
if (ptr->is_deleted)
continue;
switch (ptr->type) {
@@ -1062,9 +1076,8 @@ bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
domain->flags[TOMOYO_DIF_QUOTA_WARNED] = true;
/* r->granted = false; */
tomoyo_write_log(r, "%s", tomoyo_dif[TOMOYO_DIF_QUOTA_WARNED]);
- printk(KERN_WARNING "WARNING: "
- "Domain '%s' has too many ACLs to hold. "
- "Stopped learning mode.\n", domain->domainname->name);
+ pr_warn("WARNING: Domain '%s' has too many ACLs to hold. Stopped learning mode.\n",
+ domain->domainname->name);
}
return false;
}
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 02514fe558b4..57cc60722dd3 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -479,9 +479,15 @@ static void __init yama_init_sysctl(void)
static inline void yama_init_sysctl(void) { }
#endif /* CONFIG_SYSCTL */
-void __init yama_add_hooks(void)
+static int __init yama_init(void)
{
pr_info("Yama: becoming mindful.\n");
security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama");
yama_init_sysctl();
+ return 0;
}
+
+DEFINE_LSM(yama) = {
+ .name = "yama",
+ .init = yama_init,
+};