Commit 2233975c authored by James Morris's avatar James Morris

Merge tag 'blob-stacking-security-next' of...

Merge tag 'blob-stacking-security-next' of https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux into next-general

LSM: Module stacking for SARA and Landlock

The combined series of LSM refactoring and addition of blob-sharing for
SARA and Landlock.

From Casey:

v5: Include Kees Cook's rework of the lsm command
    line interface.
v4: Finer granularity in the patches and other
    cleanups suggested by Kees Cook.
    Removed dead code created by the removal of SELinux
    credential blob poisoning.
v3: Add ipc blob for SARA and task blob for Landlock.
    Removing the SELinux cred blob pointer poisoning
    results selinux_is_enabled() being unused, so it and
    all it's overhead has been removed.
    Broke up the cred infrastructure patch.
v2: Reduce the patchset to what is required to support
    the proposed SARA and LandLock security modules

The SARA security module is intended to be used
in conjunction with other security modules. It requires
state to be maintained for the credential, which
in turn requires a mechanism for sharing the credential
security blob. It also uses the ipc security blob. The
module also requires mechanism for user space manipulation
of the credential information, hence an additional
subdirectory in /proc/.../attr.

The LandLock security module provides user configurable
policy in the secmark mechanism. It requires data in
the credential, file, inode and task security blobs. For
this to be used along side the existing "major" security
modules mechanism for sharing these blobs are provided.

A side effect of providing sharing of the crendential
security blob is that the TOMOYO module can be used at
the same time as the other "major" modules.

The mechanism for configuring which security modules are
enabled has to change when stacking in enabled. Any
module that uses just the security blobs that are shared
can be selected. Additionally, one other "major" module
can be selected.

The security module stacking issues around networking and
IPC are not addressed here as they are beyond what is
required for TOMOYO, SARA and LandLock.
parents 49e41801 a5e2fe7e
......@@ -17,9 +17,8 @@ MAC extensions, other extensions can be built using the LSM to provide
specific changes to system operation when these tweaks are not available
in the core functionality of Linux itself.
Without a specific LSM built into the kernel, the default LSM will be the
Linux capabilities system. Most LSMs choose to extend the capabilities
system, building their checks on top of the defined capability hooks.
The Linux capabilities modules will always be included. This may be
followed by any number of "minor" modules and at most one "major" module.
For more details on capabilities, see ``capabilities(7)`` in the Linux
man-pages project.
......@@ -30,6 +29,14 @@ order in which checks are made. The capability module will always
be first, followed by any "minor" modules (e.g. Yama) and then
the one "major" module (e.g. SELinux) if there is one configured.
Process attributes associated with "major" security modules should
be accessed and maintained using the special files in ``/proc/.../attr``.
A security module may maintain a module specific subdirectory there,
named after the module. ``/proc/.../attr/smack`` is provided by the Smack
security module and contains all its special files. The files directly
in ``/proc/.../attr`` remain as legacy interfaces for modules that provide
subdirectories.
.. toctree::
:maxdepth: 1
......
......@@ -2319,6 +2319,10 @@
lsm.debug [SECURITY] Enable LSM initialization debugging output.
lsm=lsm1,...,lsmN
[SECURITY] Choose order of LSM initialization. This
overrides CONFIG_LSM.
machvec= [IA-64] Force the use of a particular machine-vector
(machvec) in a generic kernel.
Example: machvec=hpzx1_swiotlb
......
......@@ -140,9 +140,13 @@ struct pid_entry {
#define REG(NAME, MODE, fops) \
NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})
#define ONE(NAME, MODE, show) \
NOD(NAME, (S_IFREG|(MODE)), \
NOD(NAME, (S_IFREG|(MODE)), \
NULL, &proc_single_file_operations, \
{ .proc_show = show } )
#define ATTR(LSM, NAME, MODE) \
NOD(NAME, (S_IFREG|(MODE)), \
NULL, &proc_pid_attr_operations, \
{ .lsm = LSM })
/*
* Count the number of hardlinks for the pid_entry table, excluding the .
......@@ -2525,7 +2529,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
if (!task)
return -ESRCH;
length = security_getprocattr(task,
length = security_getprocattr(task, PROC_I(inode)->op.lsm,
(char*)file->f_path.dentry->d_name.name,
&p);
put_task_struct(task);
......@@ -2574,7 +2578,9 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
if (rv < 0)
goto out_free;
rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count);
rv = security_setprocattr(PROC_I(inode)->op.lsm,
file->f_path.dentry->d_name.name, page,
count);
mutex_unlock(&current->signal->cred_guard_mutex);
out_free:
kfree(page);
......@@ -2588,13 +2594,53 @@ static const struct file_operations proc_pid_attr_operations = {
.llseek = generic_file_llseek,
};
#define LSM_DIR_OPS(LSM) \
static int proc_##LSM##_attr_dir_iterate(struct file *filp, \
struct dir_context *ctx) \
{ \
return proc_pident_readdir(filp, ctx, \
LSM##_attr_dir_stuff, \
ARRAY_SIZE(LSM##_attr_dir_stuff)); \
} \
\
static const struct file_operations proc_##LSM##_attr_dir_ops = { \
.read = generic_read_dir, \
.iterate = proc_##LSM##_attr_dir_iterate, \
.llseek = default_llseek, \
}; \
\
static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \
struct dentry *dentry, unsigned int flags) \
{ \
return proc_pident_lookup(dir, dentry, \
LSM##_attr_dir_stuff, \
ARRAY_SIZE(LSM##_attr_dir_stuff)); \
} \
\
static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
.lookup = proc_##LSM##_attr_dir_lookup, \
.getattr = pid_getattr, \
.setattr = proc_setattr, \
}
#ifdef CONFIG_SECURITY_SMACK
static const struct pid_entry smack_attr_dir_stuff[] = {
ATTR("smack", "current", 0666),
};
LSM_DIR_OPS(smack);
#endif
static const struct pid_entry attr_dir_stuff[] = {
REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
REG("prev", S_IRUGO, proc_pid_attr_operations),
REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
ATTR(NULL, "current", 0666),
ATTR(NULL, "prev", 0444),
ATTR(NULL, "exec", 0666),
ATTR(NULL, "fscreate", 0666),
ATTR(NULL, "keycreate", 0666),
ATTR(NULL, "sockcreate", 0666),
#ifdef CONFIG_SECURITY_SMACK
DIR("smack", 0555,
proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
#endif
};
static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
......
......@@ -81,6 +81,7 @@ union proc_op {
int (*proc_show)(struct seq_file *m,
struct pid_namespace *ns, struct pid *pid,
struct task_struct *task);
const char *lsm;
};
struct proc_inode {
......
......@@ -15,7 +15,6 @@
#include <linux/capability.h>
#include <linux/init.h>
#include <linux/key.h>
#include <linux/selinux.h>
#include <linux/atomic.h>
#include <linux/uidgid.h>
#include <linux/sched.h>
......
......@@ -2027,6 +2027,18 @@ struct security_hook_list {
char *lsm;
} __randomize_layout;
/*
* Security blob size or offset data.
*/
struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
int lbs_inode;
int lbs_ipc;
int lbs_msg_msg;
int lbs_task;
};
/*
* Initializing a security_hook_list structure takes
* up a lot of space in a source file. This macro takes
......@@ -2042,9 +2054,21 @@ extern char *lsm_names;
extern void security_add_hooks(struct security_hook_list *hooks, int count,
char *lsm);
#define LSM_FLAG_LEGACY_MAJOR BIT(0)
#define LSM_FLAG_EXCLUSIVE BIT(1)
enum lsm_order {
LSM_ORDER_FIRST = -1, /* This is only for capabilities. */
LSM_ORDER_MUTABLE = 0,
};
struct lsm_info {
const char *name; /* Required. */
enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
unsigned long flags; /* Optional: flags describing LSM */
int *enabled; /* Optional: controlled by CONFIG_LSM */
int (*init)(void); /* Required. */
struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
};
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
......@@ -2084,17 +2108,11 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
#define __lsm_ro_after_init __ro_after_init
#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
extern int __init security_module_enable(const char *module);
extern void __init capability_add_hooks(void);
#ifdef CONFIG_SECURITY_YAMA
extern void __init yama_add_hooks(void);
#else
static inline void __init yama_add_hooks(void) { }
#endif
#ifdef CONFIG_SECURITY_LOADPIN
void __init loadpin_add_hooks(void);
#else
static inline void loadpin_add_hooks(void) { };
extern int lsm_inode_alloc(struct inode *inode);
#ifdef CONFIG_SECURITY
void __init lsm_early_cred(struct cred *cred);
void __init lsm_early_task(struct task_struct *task);
#endif
#endif /* ! __LINUX_LSM_HOOKS_H */
......@@ -366,8 +366,10 @@ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd);
int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
unsigned nsops, int alter);
void security_d_instantiate(struct dentry *dentry, struct inode *inode);
int security_getprocattr(struct task_struct *p, char *name, char **value);
int security_setprocattr(const char *name, void *value, size_t size);
int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
char **value);
int security_setprocattr(const char *lsm, const char *name, void *value,
size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
......@@ -1112,15 +1114,18 @@ static inline int security_sem_semop(struct kern_ipc_perm *sma,
return 0;
}
static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
static inline void security_d_instantiate(struct dentry *dentry,
struct inode *inode)
{ }
static inline int security_getprocattr(struct task_struct *p, char *name, char **value)
static inline int security_getprocattr(struct task_struct *p, const char *lsm,
char *name, char **value)
{
return -EINVAL;
}
static inline int security_setprocattr(char *name, void *value, size_t size)
static inline int security_setprocattr(const char *lsm, char *name,
void *value, size_t size)
{
return -EINVAL;
}
......
/*
* 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.
*/
#ifndef _LINUX_SELINUX_H
#define _LINUX_SELINUX_H
struct selinux_audit_rule;
struct audit_context;
struct kern_ipc_perm;
#ifdef CONFIG_SECURITY_SELINUX
/**
* selinux_is_enabled - is SELinux enabled?
*/
bool selinux_is_enabled(void);
#else
static inline bool selinux_is_enabled(void)
{
return false;
}
#endif /* CONFIG_SECURITY_SELINUX */
#endif /* _LINUX_SELINUX_H */
......@@ -760,19 +760,6 @@ bool creds_are_invalid(const struct cred *cred)
{
if (cred->magic != CRED_MAGIC)
return true;
#ifdef CONFIG_SECURITY_SELINUX
/*
* cred->security == NULL if security_cred_alloc_blank() or
* security_prepare_creds() returned an error.
*/
if (selinux_is_enabled() && cred->security) {
if ((unsigned long) cred->security < PAGE_SIZE)
return true;
if ((*(u32 *)cred->security & 0xffffff00) ==
(POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
return true;
}
#endif
return false;
}
EXPORT_SYMBOL(creds_are_invalid);
......
......@@ -239,42 +239,15 @@ source "security/yama/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,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
......@@ -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
......
......@@ -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);
......
......@@ -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;
}
/*
* 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);
}
}
......
......@@ -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;
}
......@@ -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,10 @@ 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;
lsm_early_cred(cred);
lsm_early_task(current);
set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
return 0;
}
......@@ -1663,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();
......@@ -1729,5 +1723,8 @@ static int __init apparmor_init(void)
DEFINE_LSM(apparmor) = {
.name = "apparmor",
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.enabled = &apparmor_enabled,
.blobs = &apparmor_blob_sizes,
.init = apparmor_init,
};
......@@ -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);
......
......@@ -1362,10 +1362,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 */
......@@ -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");
This diff is collapsed.
......@@ -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
......
......@@ -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
......
/*
* 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);
This diff is collapsed.
/*
* 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>
......
......@@ -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_ */
......@@ -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;
......
......@@ -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>
......
......@@ -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;
......
......@@ -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()));
}
/*
......
......@@ -275,7 +275,7 @@ int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
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,7 +635,7 @@ 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;
......
This diff is collapsed.
......@@ -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);
......
......@@ -29,6 +29,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>
......@@ -1062,6 +1063,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 +1087,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
extern struct lsm_blob_sizes tomoyo_blob_sizes;
/********** Inlined functions. **********/
......@@ -1196,6 +1199,17 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
atomic_dec(&group->head.users);
}
/**
* tomoyo_cred - Get a pointer to the tomoyo cred security blob
* @cred - the relevant cred
*
* Returns pointer to the tomoyo cred blob.
*/
static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
{
return cred->security + tomoyo_blob_sizes.lbs_cred;
}
/**
* tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
*
......@@ -1203,7 +1217,9 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
*/
static inline struct tomoyo_domain_info *tomoyo_domain(void)
{
return current_cred()->security;
struct tomoyo_domain_info **blob = tomoyo_cred(current_cred());
return *blob;
}
/**
......@@ -1216,7 +1232,9 @@ static inline struct tomoyo_domain_info *tomoyo_domain(void)
static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
*task)
{
return task_cred_xxx(task, security);
struct tomoyo_domain_info **blob = tomoyo_cred(get_task_cred(task));
return *blob;
}
/**
......
......@@ -678,6 +678,7 @@ static int tomoyo_environ(struct tomoyo_execve *ee)
*/
int tomoyo_find_next_domain(struct linux_binprm *bprm)
{
struct tomoyo_domain_info **blob;
struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL;
const char *original_name = bprm->filename;
......@@ -843,7 +844,8 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
domain = old_domain;
/* Update reference count on "struct tomoyo_domain_info". */
atomic_inc(&domain->users);
bprm->cred->security = domain;
blob = tomoyo_cred(bprm->cred);
*blob = domain;
kfree(exename.name);
if (!retval) {
ee->r.domain = domain;
......
......@@ -71,9 +71,12 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
if (!cred) {
error = -ENOMEM;
} else {
struct tomoyo_domain_info *old_domain =
cred->security;
cred->security = new_domain;
struct tomoyo_domain_info **blob;
struct tomoyo_domain_info *old_domain;
blob = tomoyo_cred(cred);
old_domain = *blob;
*blob = new_domain;
atomic_inc(&new_domain->users);
atomic_dec(&old_domain->users);
commit_creds(cred);
......@@ -234,10 +237,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);
......
......@@ -18,7 +18,9 @@
*/
static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp)
{
new->security = NULL;
struct tomoyo_domain_info **blob = tomoyo_cred(new);
*blob = NULL;
return 0;
}
......@@ -34,8 +36,13 @@ 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;
struct tomoyo_domain_info **old_blob = tomoyo_cred(old);
struct tomoyo_domain_info **new_blob = tomoyo_cred(new);
struct tomoyo_domain_info *domain;
domain = *old_blob;
*new_blob = domain;
if (domain)
atomic_inc(&domain->users);
return 0;
......@@ -59,7 +66,9 @@ static void tomoyo_cred_transfer(struct cred *new, const struct cred *old)
*/
static void tomoyo_cred_free(struct cred *cred)
{
struct tomoyo_domain_info *domain = cred->security;
struct tomoyo_domain_info **blob = tomoyo_cred(cred);
struct tomoyo_domain_info *domain = *blob;
if (domain)
atomic_dec(&domain->users);
}
......@@ -73,6 +82,9 @@ static void tomoyo_cred_free(struct cred *cred)
*/
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
{
struct tomoyo_domain_info **blob;
struct tomoyo_domain_info *domain;
/*
* Do only if this function is called for the first time of an execve
* operation.
......@@ -93,13 +105,14 @@ static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
* stored inside "bprm->cred->security" will be acquired later inside
* tomoyo_find_next_domain().
*/
atomic_dec(&((struct tomoyo_domain_info *)
bprm->cred->security)->users);
blob = tomoyo_cred(bprm->cred);
domain = *blob;
atomic_dec(&domain->users);
/*
* Tell tomoyo_bprm_check_security() is called for the first time of an
* execve operation.
*/
bprm->cred->security = NULL;
*blob = NULL;
return 0;
}
......@@ -112,8 +125,11 @@ 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_domain_info **blob;
struct tomoyo_domain_info *domain;
blob = tomoyo_cred(bprm->cred);
domain = *blob;
/*
* Execute permission is checked against pathname passed to do_execve()
* using current domain.
......@@ -493,6 +509,10 @@ 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_cred = sizeof(struct tomoyo_domain_info *),
};
/*
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
......@@ -531,6 +551,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.
*
......@@ -539,18 +561,23 @@ DEFINE_SRCU(tomoyo_ss);
static int __init tomoyo_init(void)
{
struct cred *cred = (struct cred *) current_cred();
struct tomoyo_domain_info **blob;
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;
lsm_early_cred(cred);
blob = tomoyo_cred(cred);
*blob = &tomoyo_kernel_domain;
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,
};
......@@ -477,9 +477,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,
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment