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 ...
This commit is contained in:
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
{
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
@@ -36,17 +39,6 @@ int aa_set_current_hat(struct aa_label *label, u64 token);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user