2018-09-22 00:00:21

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

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.

git://github.com/cschaufler/lsm-stacking.git#stacking-4.19-rc2-saralock-v4

Signed-off-by: Casey Schaufler <[email protected]>
---
Documentation/admin-guide/LSM/index.rst | 23 +-
fs/proc/base.c | 64 ++++-
fs/proc/internal.h | 1 +
include/linux/cred.h | 1 -
include/linux/lsm_hooks.h | 24 +-
include/linux/security.h | 15 +-
include/linux/selinux.h | 35 ---
kernel/cred.c | 13 -
security/Kconfig | 92 +++++++
security/apparmor/domain.c | 2 +-
security/apparmor/include/cred.h | 24 +-
security/apparmor/include/file.h | 9 +-
security/apparmor/include/lib.h | 4 +
security/apparmor/include/task.h | 18 +-
security/apparmor/lsm.c | 68 +++--
security/apparmor/task.c | 6 +-
security/security.c | 438 ++++++++++++++++++++++++++++++--
security/selinux/Makefile | 2 +-
security/selinux/exports.c | 23 --
security/selinux/hooks.c | 333 +++++++-----------------
security/selinux/include/audit.h | 3 -
security/selinux/include/objsec.h | 48 +++-
security/selinux/selinuxfs.c | 4 +-
security/selinux/ss/services.c | 1 -
security/selinux/xfrm.c | 4 +-
security/smack/smack.h | 55 +++-
security/smack/smack_access.c | 4 +-
security/smack/smack_lsm.c | 315 ++++++++---------------
security/smack/smackfs.c | 18 +-
security/tomoyo/common.h | 26 +-
security/tomoyo/domain.c | 4 +-
security/tomoyo/securityfs_if.c | 15 +-
security/tomoyo/tomoyo.c | 57 ++++-
33 files changed, 1098 insertions(+), 651 deletions(-)



2018-09-22 00:17:33

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 01/19] procfs: add smack subdir to attrs

Back in 2007 I made what turned out to be a rather serious
mistake in the implementation of the Smack security module.
The SELinux module used an interface in /proc to manipulate
the security context on processes. Rather than use a similar
interface, I used the same interface. The AppArmor team did
likewise. Now /proc/.../attr/current will tell you the
security "context" of the process, but it will be different
depending on the security module you're using.

This patch provides a subdirectory in /proc/.../attr for
Smack. Smack user space can use the "current" file in
this subdirectory and never have to worry about getting
SELinux attributes by mistake. Programs that use the
old interface will continue to work (or fail, as the case
may be) as before.

The proposed S.A.R.A security module is dependent on
the mechanism to create its own attr subdirectory.

The original implementation is by Kees Cook.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
Documentation/admin-guide/LSM/index.rst | 13 +++--
fs/proc/base.c | 64 +++++++++++++++++++++----
fs/proc/internal.h | 1 +
include/linux/security.h | 15 ++++--
security/security.c | 24 ++++++++--
5 files changed, 96 insertions(+), 21 deletions(-)

diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst
index c980dfe9abf1..9842e21afd4a 100644
--- a/Documentation/admin-guide/LSM/index.rst
+++ b/Documentation/admin-guide/LSM/index.rst
@@ -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

diff --git a/fs/proc/base.c b/fs/proc/base.c
index ccf86f16d9f0..bd2dd85310fe 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -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 .
@@ -2503,7 +2507,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);
@@ -2552,7 +2556,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);
@@ -2566,13 +2572,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)
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 5185d7f6a51e..d4f9989063d0 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -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 {
diff --git a/include/linux/security.h b/include/linux/security.h
index 75f4156c84d7..418de5d20ffb 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -390,8 +390,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);
@@ -1139,15 +1141,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;
}
diff --git a/security/security.c b/security/security.c
index 736e78da1ab9..3dfe75d0d373 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1288,14 +1288,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)
--
2.17.1



2018-09-22 00:17:48

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 02/19] Smack: Abstract use of cred security blob

Don't use the cred->security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/smack/smack.h | 17 +++++++++--
security/smack/smack_access.c | 4 +--
security/smack/smack_lsm.c | 57 +++++++++++++++++------------------
security/smack/smackfs.c | 18 +++++------
4 files changed, 53 insertions(+), 43 deletions(-)

diff --git a/security/smack/smack.h b/security/smack/smack.h
index f7db791fb566..01a922856eba 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -356,6 +356,11 @@ 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;
+}
+
/*
* Is the directory transmuting?
*/
@@ -382,13 +387,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 +416,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..489d49a20b47 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -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;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 340fc30ad85d..68ee3ae8f25c 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -122,7 +122,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)
@@ -143,7 +143,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];

@@ -165,7 +165,7 @@ 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 task_smack *tsp = smack_cred(current_cred());
struct inode_smack *isp = inode->i_security;
char acc[SMK_NUM_ACCESS_TYPE + 1];

@@ -195,7 +195,7 @@ 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;
@@ -225,7 +225,7 @@ 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;
@@ -429,7 +429,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
}

rcu_read_lock();
- tsp = __task_cred(tracer)->security;
+ tsp = smack_cred(__task_cred(tracer));
tracer_known = smk_of_task(tsp);

if ((mode & PTRACE_MODE_ATTACH) &&
@@ -496,7 +496,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;
@@ -913,7 +913,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;
@@ -1744,7 +1744,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;

@@ -1840,7 +1840,7 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
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));
struct file *file;
int rc;
struct smk_audit_info ad;
@@ -1888,7 +1888,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
@@ -1930,7 +1930,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;
@@ -1977,7 +1977,7 @@ 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;
@@ -2007,7 +2007,7 @@ 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 *old_tsp = smack_cred(old);
struct task_smack *new_tsp;
int rc;

@@ -2038,15 +2038,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 */
}

@@ -2057,12 +2056,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();
}
@@ -2076,7 +2075,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;
@@ -2094,7 +2093,7 @@ 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 task_smack *tsp = smack_cred(new);

tsp->smk_forked = isp->smk_inode;
tsp->smk_task = tsp->smk_forked;
@@ -2278,7 +2277,7 @@ static int smack_task_kill(struct task_struct *p, struct 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;
@@ -3605,7 +3604,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;
@@ -3646,7 +3645,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
@@ -4291,7 +4290,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;
@@ -4322,7 +4321,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;

@@ -4591,7 +4590,7 @@ 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
@@ -4619,8 +4618,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;

diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index f6482e53d55a..9d2dde608298 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);
--
2.17.1



2018-09-22 00:17:55

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 03/19] SELinux: Abstract use of cred security blob

Don't use the cred->security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
security/selinux/hooks.c | 54 +++++++++++++++----------------
security/selinux/include/objsec.h | 5 +++
security/selinux/xfrm.c | 4 +--
3 files changed, 34 insertions(+), 29 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index ad9a9b8e9979..9d6cdd21acb6 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -228,7 +228,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;
}

@@ -464,7 +464,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,
@@ -483,7 +483,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,
@@ -1949,7 +1949,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;
@@ -1971,7 +1971,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;
@@ -2478,8 +2478,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. */
@@ -2643,7 +2643,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;

@@ -2686,7 +2686,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;
@@ -2989,7 +2989,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);
@@ -3009,14 +3009,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;
}
@@ -3026,7 +3026,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;
@@ -3036,7 +3036,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);
@@ -3498,7 +3498,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;
@@ -3918,7 +3918,7 @@ static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
*/
static void selinux_cred_free(struct cred *cred)
{
- struct task_security_struct *tsec = cred->security;
+ struct task_security_struct *tsec = selinux_cred(cred);

/*
* cred->security == NULL if security_cred_alloc_blank() or
@@ -3938,7 +3938,7 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
const struct task_security_struct *old_tsec;
struct task_security_struct *tsec;

- old_tsec = old->security;
+ old_tsec = selinux_cred(old);

tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
if (!tsec)
@@ -3953,8 +3953,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;
}
@@ -3970,7 +3970,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;

@@ -3995,7 +3995,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;

@@ -4544,7 +4544,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;
@@ -4564,7 +4564,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);
@@ -5442,7 +5442,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,
@@ -6379,7 +6379,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,
@@ -6502,7 +6502,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")) {
@@ -6631,7 +6631,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
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index cc5e26b0161b..734b6833bdff 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -158,4 +158,9 @@ struct bpf_security_struct {
u32 sid; /*SID of bpf obj creater*/
};

+static inline struct task_security_struct *selinux_cred(const struct cred *cred)
+{
+ return cred->security;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 91dc3783ed94..8ffe7e1053c4 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;
--
2.17.1



2018-09-22 00:18:29

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 04/19] SELinux: Remove cred security blob poisoning

The SELinux specific credential poisioning only makes sense
if SELinux is managing the credentials. As the intent of this
patch set is to move the blob management out of the modules
and into the infrastructure, the SELinux specific code has
to go. The poisioning could be introduced into the infrastructure
at some later date.

Signed-off-by: Casey Schaufler <[email protected]>
---
kernel/cred.c | 13 -------------
security/selinux/hooks.c | 6 ------
2 files changed, 19 deletions(-)

diff --git a/kernel/cred.c b/kernel/cred.c
index ecf03657e71c..fa2061ee4955 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -704,19 +704,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);
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9d6cdd21acb6..80614ca25a2b 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3920,12 +3920,6 @@ static void selinux_cred_free(struct cred *cred)
{
struct task_security_struct *tsec = selinux_cred(cred);

- /*
- * 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);
}

--
2.17.1



2018-09-22 00:18:49

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 05/19] SELinux: Remove unused selinux_is_enabled

There are no longer users of selinux_is_enabled().
Remove it. As selinux_is_enabled() is the only reason
for include/linux/selinux.h remove that as well.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/cred.h | 1 -
include/linux/selinux.h | 35 --------------------------------
security/selinux/Makefile | 2 +-
security/selinux/exports.c | 23 ---------------------
security/selinux/hooks.c | 1 -
security/selinux/include/audit.h | 3 ---
security/selinux/ss/services.c | 1 -
7 files changed, 1 insertion(+), 65 deletions(-)
delete mode 100644 include/linux/selinux.h
delete mode 100644 security/selinux/exports.c

diff --git a/include/linux/cred.h b/include/linux/cred.h
index 7eed6101c791..2e715e202e6a 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -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>
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
deleted file mode 100644
index 44f459612690..000000000000
--- a/include/linux/selinux.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SELinux services exported to the rest of the kernel.
- *
- * Author: James Morris <[email protected]>
- *
- * Copyright (C) 2005 Red Hat, Inc., James Morris <[email protected]>
- * Copyright (C) 2006 Trusted Computer Solutions, Inc. <[email protected]>
- * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <[email protected]>
- *
- * 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 */
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 <[email protected]>
- *
- * Copyright (C) 2005 Red Hat, Inc., James Morris <[email protected]>
- * Copyright (C) 2006 Trusted Computer Solutions, Inc. <[email protected]>
- * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <[email protected]>
- *
- * 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 80614ca25a2b..82b28ee878c4 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>
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 <[email protected]>
*
* Copyright (C) 2005 Red Hat, Inc., James Morris <[email protected]>
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index f3def298a90e..e2235f1a99aa 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>
--
2.17.1



2018-09-22 00:19:21

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 08/19] Infrastructure management of the cred security blob

Move management of the cred security blob out of the
security modules and into the security infrastructre.
Instead of allocating and freeing space the security
modules tell the infrastructure how much space they
require.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 14 ++++
security/Kconfig | 11 ++++
security/apparmor/lsm.c | 18 +++++
security/security.c | 106 +++++++++++++++++++++++++++++-
security/selinux/hooks.c | 58 +++++-----------
security/selinux/include/objsec.h | 2 +
security/smack/smack_lsm.c | 85 +++++++++---------------
security/tomoyo/common.h | 2 +-
security/tomoyo/tomoyo.c | 16 ++++-
9 files changed, 212 insertions(+), 100 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 97a020c616ad..0bef312efd45 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2024,6 +2024,13 @@ struct security_hook_list {
char *lsm;
} __randomize_layout;

+/*
+ * Security blob size or offset data.
+ */
+struct lsm_blob_sizes {
+ int lbs_cred;
+};
+
/*
* Initializing a security_hook_list structure takes
* up a lot of space in a source file. This macro takes
@@ -2036,6 +2043,7 @@ struct security_hook_list {
extern struct security_hook_heads security_hook_heads;
extern char *lsm_names;

+extern void security_add_blobs(struct lsm_blob_sizes *needed);
extern void security_add_hooks(struct security_hook_list *hooks, int count,
char *lsm);

@@ -2082,4 +2090,10 @@ void __init loadpin_add_hooks(void);
static inline void loadpin_add_hooks(void) { };
#endif

+extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
+
+#ifdef CONFIG_SECURITY
+void lsm_early_cred(struct cred *cred);
+#endif
+
#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/Kconfig b/security/Kconfig
index 27d8b2688f75..22f7664c4977 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -36,6 +36,17 @@ config SECURITY_WRITABLE_HOOKS
bool
default n

+config SECURITY_LSM_DEBUG
+ bool "Enable debugging of the LSM infrastructure"
+ depends on SECURITY
+ help
+ This allows you to choose debug messages related to
+ security modules configured into your kernel. These
+ messages may be helpful in determining how a security
+ module is using security blobs.
+
+ If you are unsure how to answer this question, answer N.
+
config SECURITYFS
bool "Enable the securityfs filesystem"
help
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 4f51705c3c71..c2566aaa138e 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1126,6 +1126,13 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
ctx->label = aa_get_current_label();
}

+/*
+ * The cred blob is a pointer to, not an instance of, an aa_task_ctx.
+ */
+struct lsm_blob_sizes apparmor_blob_sizes = {
+ .lbs_cred = 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),
@@ -1455,6 +1462,7 @@ static int __init set_init_ctx(void)
if (!ctx)
return -ENOMEM;

+ lsm_early_cred(cred);
set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
task_ctx(current) = ctx;

@@ -1540,8 +1548,18 @@ static inline int apparmor_init_sysctl(void)

static int __init apparmor_init(void)
{
+ static int finish;
int error;

+ if (!finish) {
+ if (apparmor_enabled && security_module_enable("apparmor"))
+ security_add_blobs(&apparmor_blob_sizes);
+ else
+ apparmor_enabled = false;
+ finish = 1;
+ return 0;
+ }
+
if (!apparmor_enabled || !security_module_enable("apparmor")) {
aa_info_message("AppArmor disabled by boot time parameter");
apparmor_enabled = false;
diff --git a/security/security.c b/security/security.c
index 3dfe75d0d373..ff7df14f6db1 100644
--- a/security/security.c
+++ b/security/security.c
@@ -41,6 +41,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);

char *lsm_names;
+static struct lsm_blob_sizes blob_sizes;
+
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
CONFIG_DEFAULT_SECURITY;
@@ -85,10 +87,22 @@ int __init security_init(void)
loadpin_add_hooks();

/*
- * Load all the remaining security modules.
+ * The first call to a module specific init function
+ * updates the blob size requirements.
+ */
+ do_security_initcalls();
+
+ /*
+ * The second call to a module specific init function
+ * adds hooks to the hook lists and does any other early
+ * initializations required.
*/
do_security_initcalls();

+#ifdef CONFIG_SECURITY_LSM_DEBUG
+ pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
+#endif
+
return 0;
}

@@ -198,6 +212,73 @@ 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.
+ */
+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 if it's not already there
+ */
+void lsm_early_cred(struct cred *cred)
+{
+ int rc;
+
+ if (cred == NULL)
+ panic("%s: NULL cred.\n", __func__);
+ if (cred->security != NULL)
+ return;
+ rc = lsm_cred_alloc(cred, GFP_KERNEL);
+ if (rc)
+ panic("%s: Early cred alloc failed.\n", __func__);
+}
+
+static void __init lsm_set_size(int *need, int *lbs)
+{
+ int offset;
+
+ if (*need > 0) {
+ offset = *lbs;
+ *lbs += *need;
+ *need = offset;
+ }
+}
+
+/**
+ * security_add_blobs - Report blob sizes
+ * @needed: the size of blobs needed by the module
+ *
+ * Each LSM has to register its blobs with the infrastructure.
+ * The "needed" data tells the infrastructure how much memory
+ * the module requires for each of its blobs. On return the
+ * structure is filled with the offset that module should use
+ * from the blob pointer.
+ */
+void __init security_add_blobs(struct lsm_blob_sizes *needed)
+{
+ lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+}
+
/*
* Hook list operation macros.
*
@@ -998,17 +1079,36 @@ void security_task_free(struct task_struct *task)

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 (rc)
+ security_cred_free(cred);
+ return rc;
}

void security_cred_free(struct cred *cred)
{
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 (rc)
+ security_cred_free(new);
+ return rc;
}

void security_transfer_creds(struct cred *new, const struct cred *old)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 82b28ee878c4..b629cc302088 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -212,12 +212,9 @@ 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");
-
+ lsm_early_cred(cred);
+ tsec = selinux_cred(cred);
tsec->osid = tsec->sid = SECINITSID_KERNEL;
- cred->security = tsec;
}

/*
@@ -3897,47 +3894,16 @@ static int selinux_task_alloc(struct task_struct *task,
sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
}

-/*
- * 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 = selinux_cred(cred);
-
- 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 = selinux_cred(old);
-
- tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
- if (!tsec)
- return -ENOMEM;
+ const struct task_security_struct *old_tsec = selinux_cred(old);
+ struct task_security_struct *tsec = selinux_cred(new);

- new->security = tsec;
+ *tsec = *old_tsec;
return 0;
}

@@ -6887,6 +6853,10 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
}
#endif

+struct lsm_blob_sizes selinux_blob_sizes = {
+ .lbs_cred = sizeof(struct task_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),
@@ -6969,8 +6939,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),
@@ -7126,11 +7094,19 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {

static __init int selinux_init(void)
{
+ static int finish;
+
if (!security_module_enable("selinux")) {
selinux_enabled = 0;
return 0;
}

+ if (!finish) {
+ security_add_blobs(&selinux_blob_sizes);
+ finish = 1;
+ return 0;
+ }
+
if (!selinux_enabled) {
pr_info("SELinux: Disabled at boot.\n");
return 0;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 734b6833bdff..ad511c3d2eb7 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -25,6 +25,7 @@
#include <linux/binfmts.h>
#include <linux/in.h>
#include <linux/spinlock.h>
+#include <linux/lsm_hooks.h>
#include <net/net_namespace.h>
#include "flask.h"
#include "avc.h"
@@ -158,6 +159,7 @@ 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;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 68ee3ae8f25c..a06ea8aa89c4 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -309,29 +309,20 @@ static struct inode_smack *new_inode_smack(struct smack_known *skp)
}

/**
- * 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;
}

/**
@@ -1958,14 +1949,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;
}

@@ -1982,10 +1966,6 @@ static void smack_cred_free(struct cred *cred)
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) {
@@ -1993,7 +1973,6 @@ static void smack_cred_free(struct cred *cred)
list_del(&rp->list);
kfree(rp);
}
- kfree(tsp);
}

/**
@@ -2008,14 +1987,10 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
struct task_smack *old_tsp = smack_cred(old);
- struct task_smack *new_tsp;
+ 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)
@@ -2023,10 +1998,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;
}

/**
@@ -4652,6 +4624,10 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
return 0;
}

+struct lsm_blob_sizes smack_blob_sizes = {
+ .lbs_cred = sizeof(struct task_smack),
+};
+
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),
@@ -4830,23 +4806,35 @@ static __init void init_smack_known_list(void)
*/
static __init int smack_init(void)
{
- struct cred *cred;
+ static int finish;
+ struct cred *cred = (struct cred *) current->cred;
struct task_smack *tsp;

if (!security_module_enable("smack"))
return 0;

+ if (!finish) {
+ security_add_blobs(&smack_blob_sizes);
+ finish = 1;
+ 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;
- }
+ lsm_early_cred(cred);

+ /*
+ * 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");
@@ -4860,20 +4848,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;
}

diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index c9d8c49e3210..0110bebe86e2 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -1206,7 +1206,7 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
*/
static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
{
- return (struct tomoyo_domain_info **)&cred->security;
+ return cred->security;
}

/**
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 25739888921f..bb84e6ec3886 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -509,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 = {
+ .lbs_cred = sizeof(struct tomoyo_domain_info *),
+};
+
/*
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
@@ -556,16 +560,26 @@ bool tomoyo_enabled;
*/
static int __init tomoyo_init(void)
{
+ static int finish;
struct cred *cred = (struct cred *) current_cred();
struct tomoyo_domain_info **blob;

- if (!security_module_enable("tomoyo"))
+ if (!security_module_enable("tomoyo")) {
+ tomoyo_enabled = false;
return 0;
+ }
tomoyo_enabled = true;

+ if (!finish) {
+ security_add_blobs(&tomoyo_blob_sizes);
+ finish = 1;
+ 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");
+ lsm_early_cred(cred);
blob = tomoyo_cred(cred);
*blob = &tomoyo_kernel_domain;
tomoyo_mm_init();
--
2.17.1



2018-09-22 00:19:49

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 11/19] LSM: Infrastructure management of the file security

Move management of the file->f_security blob out of the
individual security modules and into the infrastructure.
The modules no longer allocate or free the data, instead
they tell the infrastructure how much space they require.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 1 +
security/apparmor/lsm.c | 19 +++++++-------
security/security.c | 54 +++++++++++++++++++++++++++++++++++---
security/selinux/hooks.c | 25 ++----------------
security/smack/smack.h | 2 +-
security/smack/smack_lsm.c | 14 +---------
6 files changed, 66 insertions(+), 49 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 0bef312efd45..167ffbd4d0c0 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2029,6 +2029,7 @@ struct security_hook_list {
*/
struct lsm_blob_sizes {
int lbs_cred;
+ int lbs_file;
};

/*
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index c2566aaa138e..15716b6ff860 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -431,21 +431,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)
@@ -1131,6 +1131,7 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
*/
struct lsm_blob_sizes apparmor_blob_sizes = {
.lbs_cred = sizeof(struct aa_task_ctx *),
+ .lbs_file = sizeof(struct aa_file_ctx),
};

static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
diff --git a/security/security.c b/security/security.c
index ff7df14f6db1..5430cae73cf6 100644
--- a/security/security.c
+++ b/security/security.c
@@ -40,6 +40,8 @@
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;
+
char *lsm_names;
static struct lsm_blob_sizes blob_sizes;

@@ -92,6 +94,13 @@ int __init security_init(void)
*/
do_security_initcalls();

+ /*
+ * 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);
/*
* The second call to a module specific init function
* adds hooks to the hook lists and does any other early
@@ -101,6 +110,7 @@ int __init security_init(void)

#ifdef CONFIG_SECURITY_LSM_DEBUG
pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
+ pr_info("LSM: file blob size = %d\n", blob_sizes.lbs_file);
#endif

return 0;
@@ -277,6 +287,28 @@ static void __init lsm_set_size(int *need, int *lbs)
void __init security_add_blobs(struct lsm_blob_sizes *needed)
{
lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_size(&needed->lbs_file, &blob_sizes.lbs_file);
+}
+
+/**
+ * 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.
+ */
+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;
}

/*
@@ -962,12 +994,28 @@ 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;
+
+ if (!lsm_file_cache)
+ return;
+
call_void_hook(file_free_security, file);
+
+ blob = file->f_security;
+ file->f_security = NULL;
+ kmem_cache_free(lsm_file_cache, blob);
}

int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1085,7 +1133,7 @@ int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
return rc;

rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
- if (rc)
+ if (unlikely(rc))
security_cred_free(cred);
return rc;
}
@@ -1106,7 +1154,7 @@ int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
return rc;

rc = call_int_hook(cred_prepare, 0, new, old, gfp);
- if (rc)
+ if (unlikely(rc))
security_cred_free(new);
return rc;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 641a8ce726ff..fdda53552224 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -148,7 +148,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
@@ -380,27 +379,15 @@ static void inode_free_security(struct inode *inode)

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 = selinux_file(file);
- 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;
@@ -3557,11 +3544,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.
@@ -6855,6 +6837,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)

struct lsm_blob_sizes selinux_blob_sizes = {
.lbs_cred = sizeof(struct task_security_struct),
+ .lbs_file = sizeof(struct file_security_struct),
};

static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
@@ -6925,7 +6908,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),
@@ -7128,9 +7110,6 @@ static __init int selinux_init(void)
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();
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 22ca30379209..62a22ad8ce92 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -363,7 +363,7 @@ static inline struct task_smack *smack_cred(const struct cred *cred)

static inline struct smack_known **smack_file(const struct file *file)
{
- return (struct smack_known **)&file->f_security;
+ return file->f_security;
}

/*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 9ec595f0c3f1..d1430341798f 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1577,18 +1577,6 @@ static int smack_file_alloc_security(struct file *file)
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
@@ -4630,6 +4618,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,

struct lsm_blob_sizes smack_blob_sizes = {
.lbs_cred = sizeof(struct task_smack),
+ .lbs_file = sizeof(struct smack_known *),
};

static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
@@ -4667,7 +4656,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),
--
2.17.1



2018-09-22 00:20:02

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 10/19] Smack: Abstract use of file security blob

Don't use the file->f_security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/smack/smack.h | 5 +++++
security/smack/smack_lsm.c | 12 ++++++++----
2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/security/smack/smack.h b/security/smack/smack.h
index 01a922856eba..22ca30379209 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -361,6 +361,11 @@ static inline struct task_smack *smack_cred(const struct cred *cred)
return cred->security;
}

+static inline struct smack_known **smack_file(const struct file *file)
+{
+ return (struct smack_known **)&file->f_security;
+}
+
/*
* Is the directory transmuting?
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index a06ea8aa89c4..9ec595f0c3f1 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1571,9 +1571,9 @@ 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;
}

@@ -1813,7 +1813,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();
}

/**
@@ -1830,6 +1832,7 @@ 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(smack_cred(tsk->cred));
struct file *file;
@@ -1842,7 +1845,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);
if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))
--
2.17.1



2018-09-22 00:20:12

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 06/19] AppArmor: Abstract use of cred security blob

Don't use the cred->security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/apparmor/domain.c | 2 +-
security/apparmor/include/cred.h | 16 +++++++++++++++-
security/apparmor/lsm.c | 10 +++++-----
security/apparmor/task.c | 6 +++---
4 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index 08c88de0ffda..726910bba84b 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -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/cred.h b/security/apparmor/include/cred.h
index e287b7d0d4be..a90eae76d7c1 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;
+
+ 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;
+
+ AA_BUG(!blob);
+ *blob = label;
+}

/**
* aa_cred_raw_label - obtain cred's label
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 8b8b70620bbe..4f51705c3c71 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -57,7 +57,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);
}

/*
@@ -65,7 +65,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;
}

@@ -75,7 +75,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;
}

@@ -84,7 +84,7 @@ 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)
@@ -1455,7 +1455,7 @@ static int __init set_init_ctx(void)
if (!ctx)
return -ENOMEM;

- cred_label(cred) = aa_get_label(ns_unconfined(root_ns));
+ set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
task_ctx(current) = ctx;

return 0;
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);
--
2.17.1



2018-09-22 00:20:21

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 07/19] TOMOYO: Abstract use of cred security blob

Don't use the cred->security pointer directly.
Provide helper functions that provide the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/tomoyo/common.h | 21 +++++++++++++++--
security/tomoyo/domain.c | 4 +++-
security/tomoyo/securityfs_if.c | 15 +++++++++----
security/tomoyo/tomoyo.c | 40 +++++++++++++++++++++++++--------
4 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 539bcdd30bb8..c9d8c49e3210 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -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 bool tomoyo_enabled;
extern const char * const tomoyo_condition_keyword
[TOMOYO_MAX_CONDITION_KEYWORD];
extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
@@ -1196,6 +1198,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 (struct tomoyo_domain_info **)&cred->security;
+}
+
/**
* tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
*
@@ -1203,7 +1216,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 +1231,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;
}

/**
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index f6758dad981f..b7469fdbff01 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -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;
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 1d3d7e7a1f05..768dff9608b1 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -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);
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 9f932e2d6852..25739888921f 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -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.
@@ -531,6 +547,8 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
/* Lock for GC. */
DEFINE_SRCU(tomoyo_ss);

+bool tomoyo_enabled;
+
/**
* tomoyo_init - Register TOMOYO Linux as a LSM module.
*
@@ -539,13 +557,17 @@ 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;
+ tomoyo_enabled = true;
+
/* 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;
+ blob = tomoyo_cred(cred);
+ *blob = &tomoyo_kernel_domain;
tomoyo_mm_init();
return 0;
}
--
2.17.1



2018-09-22 00:20:30

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 15/19] LSM: Infrastructure management of the task security

Move management of the task_struct->security blob out
of the individual security modules and into the security
infrastructure. Instead of allocating the blobs from within
the modules the modules tell the infrastructure how much
space is required, and the space is allocated there.
The only user of this blob is AppArmor. The AppArmor use
is abstracted to avoid future conflict.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 2 ++
security/apparmor/include/task.h | 18 +++--------
security/apparmor/lsm.c | 15 ++-------
security/security.c | 54 +++++++++++++++++++++++++++++++-
4 files changed, 62 insertions(+), 27 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 416b20c3795b..6057c603b979 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2031,6 +2031,7 @@ struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
int lbs_inode;
+ int lbs_task;
};

/*
@@ -2098,6 +2099,7 @@ extern int lsm_inode_alloc(struct inode *inode);
#ifdef CONFIG_SECURITY
void lsm_early_cred(struct cred *cred);
void lsm_early_inode(struct inode *inode);
+void lsm_early_task(struct task_struct *task);
#endif

#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h
index 55edaa1d83f8..039c1e60887a 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;
+}

/*
* 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);
}
}

diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 15716b6ff860..c97dc3dbb515 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -91,19 +91,14 @@ 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;
}
@@ -1132,6 +1127,7 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
struct lsm_blob_sizes apparmor_blob_sizes = {
.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 = {
@@ -1457,15 +1453,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;

lsm_early_cred(cred);
+ lsm_early_task(current);
set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
- task_ctx(current) = ctx;

return 0;
}
diff --git a/security/security.c b/security/security.c
index a8f00fdff4d8..7e11de7eec21 100644
--- a/security/security.c
+++ b/security/security.c
@@ -117,6 +117,7 @@ int __init security_init(void)
pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
pr_info("LSM: file blob size = %d\n", blob_sizes.lbs_file);
pr_info("LSM: inode blob size = %d\n", blob_sizes.lbs_inode);
+ pr_info("LSM: task blob size = %d\n", blob_sizes.lbs_task);
#endif

return 0;
@@ -301,6 +302,7 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
lsm_set_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_set_size(&needed->lbs_task, &blob_sizes.lbs_task);
}

/**
@@ -364,6 +366,46 @@ void lsm_early_inode(struct inode *inode)
panic("%s: Early inode alloc failed.\n", __func__);
}

+/**
+ * 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.
+ */
+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_early_task - during initialization allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules if it's not already there
+ */
+void lsm_early_task(struct task_struct *task)
+{
+ int rc;
+
+ if (task == NULL)
+ panic("%s: task cred.\n", __func__);
+ if (task->security != NULL)
+ return;
+ rc = lsm_task_alloc(task);
+ if (rc)
+ panic("%s: Early task alloc failed.\n", __func__);
+}
+
/*
* Hook list operation macros.
*
@@ -1196,12 +1238,22 @@ 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)
--
2.17.1



2018-09-22 00:21:01

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 17/19] Smack: Abstract use of ipc security blobs

Don't use the ipc->security pointer directly.
Don't use the msg_msg->security pointer directly.
Provide helper functions that provides the security blob pointers.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/smack/smack.h | 11 +++++++++++
security/smack/smack_lsm.c | 14 +++++++++-----
2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/security/smack/smack.h b/security/smack/smack.h
index add19b7efc96..52cea142fcf6 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
@@ -371,6 +372,16 @@ static inline struct inode_smack *smack_inode(const struct inode *inode)
return inode->i_security;
}

+static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg)
+{
+ return (struct smack_known **)&msg->security;
+}
+
+static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
+{
+ return (struct smack_known **)&ipc->security;
+}
+
/*
* Is the directory transmuting?
*/
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 6617abb51732..4afc8899f83f 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2905,7 +2905,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;
}

/**
@@ -2916,9 +2918,9 @@ 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;
}

@@ -3230,7 +3232,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;
@@ -3251,7 +3254,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;
}
--
2.17.1



2018-09-22 00:21:13

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 14/19] LSM: Infrastructure management of the inode security

Move management of the inode->i_security blob out
of the individual security modules and into the security
infrastructure. Instead of allocating the blobs from within
the modules the modules tell the infrastructure how much
space is required, and the space is allocated there.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 3 ++
security/security.c | 83 ++++++++++++++++++++++++++++++-
security/selinux/hooks.c | 32 +-----------
security/selinux/include/objsec.h | 5 +-
security/smack/smack_lsm.c | 70 ++++----------------------
5 files changed, 98 insertions(+), 95 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 167ffbd4d0c0..416b20c3795b 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2030,6 +2030,7 @@ struct security_hook_list {
struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
+ int lbs_inode;
};

/*
@@ -2092,9 +2093,11 @@ static inline void loadpin_add_hooks(void) { };
#endif

extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
+extern int lsm_inode_alloc(struct inode *inode);

#ifdef CONFIG_SECURITY
void lsm_early_cred(struct cred *cred);
+void lsm_early_inode(struct inode *inode);
#endif

#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/security.c b/security/security.c
index 5430cae73cf6..a8f00fdff4d8 100644
--- a/security/security.c
+++ b/security/security.c
@@ -41,6 +41,7 @@ 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;
@@ -101,6 +102,10 @@ int __init security_init(void)
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);
/*
* The second call to a module specific init function
* adds hooks to the hook lists and does any other early
@@ -111,6 +116,7 @@ int __init security_init(void)
#ifdef CONFIG_SECURITY_LSM_DEBUG
pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
pr_info("LSM: file blob size = %d\n", blob_sizes.lbs_file);
+ pr_info("LSM: inode blob size = %d\n", blob_sizes.lbs_inode);
#endif

return 0;
@@ -288,6 +294,13 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
{
lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
lsm_set_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_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
}

/**
@@ -311,6 +324,46 @@ int lsm_file_alloc(struct file *file)
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_early_inode - during initialization allocate a composite inode blob
+ * @inode: the inode that needs a blob
+ *
+ * Allocate the inode blob for all the modules if it's not already there
+ */
+void lsm_early_inode(struct inode *inode)
+{
+ int rc;
+
+ if (inode == NULL)
+ panic("%s: NULL inode.\n", __func__);
+ if (inode->i_security != NULL)
+ return;
+ rc = lsm_inode_alloc(inode);
+ if (rc)
+ panic("%s: Early inode alloc failed.\n", __func__);
+}
+
/*
* Hook list operation macros.
*
@@ -557,14 +610,40 @@ EXPORT_SYMBOL(security_sb_parse_opts_str);

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,
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 248ae907320f..389e51ef48a5 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -147,8 +147,6 @@ static int __init checkreqprot_setup(char *str)
}
__setup("checkreqprot=", checkreqprot_setup);

-static struct kmem_cache *sel_inode_cache;
-
/**
* selinux_secmark_enabled - Check to see if SECMARK is currently enabled
*
@@ -244,13 +242,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;
@@ -258,7 +252,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;
}
@@ -336,14 +329,6 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
return selinux_inode(inode);
}

-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);
-}
-
static void inode_free_security(struct inode *inode)
{
struct inode_security_struct *isec = selinux_inode(inode);
@@ -364,17 +349,6 @@ 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)
@@ -6838,6 +6812,7 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
struct lsm_blob_sizes selinux_blob_sizes = {
.lbs_cred = sizeof(struct task_security_struct),
.lbs_file = sizeof(struct file_security_struct),
+ .lbs_inode = sizeof(struct inode_security_struct),
};

static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
@@ -7107,9 +7082,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);
avc_init();

avtab_cache_init();
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index ea1687e737ad..591adb374d69 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -57,10 +57,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 */
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 364699ad55b9..6617abb51732 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -288,24 +288,18 @@ 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;
}

/**
@@ -824,17 +818,13 @@ static int smack_set_mnt_opts(struct super_block *sb,
/*
* Initialize the root inode.
*/
- isp = smack_inode(inode);
- 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;
+ lsm_early_inode(inode);
+ init_inode_smack(inode, sp->smk_root);

- if (transmute)
+ if (transmute) {
+ isp = smack_inode(inode);
isp->smk_flags |= SMK_INODE_TRANSMUTE;
+ }

return 0;
}
@@ -963,48 +953,10 @@ 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 = smack_inode(inode);
-
- /*
- * 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
@@ -4619,6 +4571,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
struct lsm_blob_sizes smack_blob_sizes = {
.lbs_cred = sizeof(struct task_smack),
.lbs_file = sizeof(struct smack_known *),
+ .lbs_inode = sizeof(struct inode_smack),
};

static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
@@ -4637,7 +4590,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),
--
2.17.1



2018-09-22 00:21:22

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 12/19] SELinux: Abstract use of inode security blob

Don't use the inode->i_security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
security/selinux/hooks.c | 26 +++++++++++++-------------
security/selinux/include/objsec.h | 6 ++++++
security/selinux/selinuxfs.c | 4 ++--
3 files changed, 21 insertions(+), 15 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index fdda53552224..248ae907320f 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -275,7 +275,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);

@@ -296,7 +296,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)
@@ -306,7 +306,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);
}

/*
@@ -315,14 +315,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);
}

/*
@@ -333,7 +333,7 @@ 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;
+ return selinux_inode(inode);
}

static void inode_free_rcu(struct rcu_head *head)
@@ -346,7 +346,7 @@ static void inode_free_rcu(struct rcu_head *head)

static void inode_free_security(struct inode *inode)
{
- struct inode_security_struct *isec = inode->i_security;
+ struct inode_security_struct *isec = selinux_inode(inode);
struct superblock_security_struct *sbsec = inode->i_sb->s_security;

/*
@@ -1500,7 +1500,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;
@@ -1800,7 +1800,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);
@@ -3028,7 +3028,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;
@@ -3128,7 +3128,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;
@@ -4148,7 +4148,7 @@ static int selinux_task_kill(struct task_struct *p, struct 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);
@@ -6527,7 +6527,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;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index cad8b765f6dd..ea1687e737ad 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -170,4 +170,10 @@ static inline struct file_security_struct *selinux_file(const struct file *file)
return file->f_security;
}

+static inline struct inode_security_struct *selinux_inode(
+ const struct inode *inode)
+{
+ return inode->i_security;
+}
+
#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;
--
2.17.1



2018-09-22 00:21:23

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 19/19] LSM: Blob sharing support for S.A.R.A and LandLock

Two proposed security modules require the ability to
share security blobs with existing "major" security modules.
These modules, S.A.R.A and LandLock, provide significantly
different services than SELinux, Smack or AppArmor. Using
either in conjunction with the existing modules is quite
reasonable. S.A.R.A requires access to the cred, inode and
task blobs, while LandLock uses the cred, file, inode and
ipc blobs.

The use of the cred, file, inode, ipc and task blobs has been
abstracted in preceding patches in the series. This
patch teaches the affected security modules how to access
the part of the blob set aside for their use in the case
where blobs are shared. The configuration option
CONFIG_SECURITY_STACKING identifies systems where the
blobs may be shared.

The mechanism for selecting which security modules are
active has been changed to allow non-conflicting "major"
security modules to be used together. At this time the
TOMOYO module can safely be used with any of the others.
The two new modules would be non-conflicting as well.

Signed-off-by: Casey Schaufler <[email protected]>
---
Documentation/admin-guide/LSM/index.rst | 14 +++--
include/linux/lsm_hooks.h | 2 +-
security/Kconfig | 81 +++++++++++++++++++++++++
security/apparmor/include/cred.h | 8 +++
security/apparmor/include/file.h | 9 ++-
security/apparmor/include/lib.h | 4 ++
security/apparmor/lsm.c | 8 ++-
security/security.c | 30 ++++++++-
security/selinux/hooks.c | 3 +-
security/selinux/include/objsec.h | 12 ++++
security/smack/smack.h | 13 ++++
security/smack/smack_lsm.c | 3 +-
security/tomoyo/common.h | 5 ++
security/tomoyo/tomoyo.c | 3 +-
14 files changed, 182 insertions(+), 13 deletions(-)

diff --git a/Documentation/admin-guide/LSM/index.rst b/Documentation/admin-guide/LSM/index.rst
index 9842e21afd4a..d3d8af174042 100644
--- a/Documentation/admin-guide/LSM/index.rst
+++ b/Documentation/admin-guide/LSM/index.rst
@@ -17,10 +17,16 @@ MAC extensions, other extensions can be built using the LSM to provide
specific changes to system operation when these tweaks are not available
in the core functionality of Linux itself.

-The Linux capabilities modules will always be included. This may be
-followed by any number of "minor" modules and at most one "major" module.
-For more details on capabilities, see ``capabilities(7)`` in the Linux
-man-pages project.
+The Linux capabilities modules will always be included. For more details
+on capabilities, see ``capabilities(7)`` in the Linux man-pages project.
+
+Security modules that do not use the security data blobs maintained
+by the LSM infrastructure are considered "minor" modules. These may be
+included at compile time and stacked explicitly. Security modules that
+use the LSM maintained security blobs are considered "major" modules.
+These may only be stacked if the CONFIG_LSM_STACKED configuration
+option is used. If this is chosen all of the security modules selected
+will be used.

A list of the active security modules can be found by reading
``/sys/kernel/security/lsm``. This is a comma separated list, and
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index f6dbde28833a..7e8b32fdf576 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2082,7 +2082,7 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
#define __lsm_ro_after_init __ro_after_init
#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */

-extern int __init security_module_enable(const char *module);
+extern bool __init security_module_enable(const char *lsm, const bool stacked);
extern void __init capability_add_hooks(void);
#ifdef CONFIG_SECURITY_YAMA
extern void __init yama_add_hooks(void);
diff --git a/security/Kconfig b/security/Kconfig
index 22f7664c4977..ed48025ae9e0 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -36,6 +36,28 @@ config SECURITY_WRITABLE_HOOKS
bool
default n

+config SECURITY_STACKING
+ bool "Security module stacking"
+ depends on SECURITY
+ help
+ Allows multiple major security modules to be stacked.
+ Modules are invoked in the order registered with a
+ "bail on fail" policy, in which the infrastructure
+ will stop processing once a denial is detected. Not
+ all modules can be stacked. SELinux, Smack and AppArmor are
+ known to be incompatible. User space components may
+ have trouble identifying the security module providing
+ data in some cases.
+
+ If you select this option you will have to select which
+ of the stackable modules you wish to be active. The
+ "Default security module" will be ignored. The boot line
+ "security=" option can be used to specify that one of
+ the modules identifed for stacking should be used instead
+ of the entire stack.
+
+ If you are unsure how to answer this question, answer N.
+
config SECURITY_LSM_DEBUG
bool "Enable debugging of the LSM infrastructure"
depends on SECURITY
@@ -250,6 +272,9 @@ source security/yama/Kconfig

source security/integrity/Kconfig

+menu "Security Module Selection"
+ visible if !SECURITY_STACKING
+
choice
prompt "Default security module"
default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
@@ -289,3 +314,59 @@ config DEFAULT_SECURITY

endmenu

+menu "Security Module Stack"
+ visible if SECURITY_STACKING
+
+choice
+ prompt "Stacked 'extreme' security module"
+ default SECURITY_SELINUX_STACKED if SECURITY_SELINUX
+ default SECURITY_SMACK_STACKED if SECURITY_SMACK
+ default SECURITY_APPARMOR_STACKED if SECURITY_APPARMOR
+
+ help
+ Enable an extreme security module. These modules cannot
+ be used at the same time.
+
+ config SECURITY_SELINUX_STACKED
+ bool "SELinux" if SECURITY_SELINUX=y
+ help
+ This option instructs the system to use the SELinux checks.
+ At this time the Smack security module is incompatible with this
+ module.
+ At this time the AppArmor security module is incompatible with this
+ module.
+
+ config SECURITY_SMACK_STACKED
+ bool "Simplified Mandatory Access Control" if SECURITY_SMACK=y
+ help
+ This option instructs the system to use the Smack checks.
+ At this time the SELinux security module is incompatible with this
+ module.
+ At this time the AppArmor security module is incompatible with this
+ module.
+
+ config SECURITY_APPARMOR_STACKED
+ bool "AppArmor" if SECURITY_APPARMOR=y
+ help
+ This option instructs the system to use the AppArmor checks.
+ At this time the SELinux security module is incompatible with this
+ module.
+ At this time the Smack security module is incompatible with this
+ module.
+
+endchoice
+
+config SECURITY_TOMOYO_STACKED
+ bool "TOMOYO support is enabled by default"
+ depends on SECURITY_TOMOYO && SECURITY_STACKING
+ default n
+ help
+ This option instructs the system to use the TOMOYO checks.
+ If not selected the module will not be invoked.
+ Stacked security modules may interact in unexpected ways.
+
+ If you are unsure how to answer this question, answer N.
+
+endmenu
+
+endmenu
diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h
index a90eae76d7c1..be7575adf6f0 100644
--- a/security/apparmor/include/cred.h
+++ b/security/apparmor/include/cred.h
@@ -25,7 +25,11 @@

static inline struct aa_label *cred_label(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+#else
struct aa_label **blob = cred->security;
+#endif

AA_BUG(!blob);
return *blob;
@@ -34,7 +38,11 @@ static inline struct aa_label *cred_label(const struct cred *cred)
static inline void set_cred_label(const struct cred *cred,
struct aa_label *label)
{
+#ifdef CONFIG_SECURITY_STACKING
+ struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+#else
struct aa_label **blob = cred->security;
+#endif

AA_BUG(!blob);
*blob = label;
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index 4c2c8ac8842f..aeb757471cc0 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -32,7 +32,14 @@ struct path;
AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
AA_EXEC_MMAP | AA_MAY_LINK)

-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+static inline struct aa_file_ctx *file_ctx(struct file *file)
+{
+#ifdef CONFIG_SECURITY_STACKING
+ return file->f_security + apparmor_blob_sizes.lbs_file;
+#else
+ return file->f_security;
+#endif
+}

/* struct aa_file_ctx - the AppArmor context the file was opened in
* @lock: lock to update the ctx
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/lsm.c b/security/apparmor/lsm.c
index c97dc3dbb515..50da984fca54 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1544,7 +1544,9 @@ static int __init apparmor_init(void)
int error;

if (!finish) {
- if (apparmor_enabled && security_module_enable("apparmor"))
+ if (apparmor_enabled &&
+ security_module_enable("apparmor",
+ IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED)))
security_add_blobs(&apparmor_blob_sizes);
else
apparmor_enabled = false;
@@ -1552,7 +1554,9 @@ static int __init apparmor_init(void)
return 0;
}

- if (!apparmor_enabled || !security_module_enable("apparmor")) {
+ if (!apparmor_enabled ||
+ !security_module_enable("apparmor",
+ IS_ENABLED(CONFIG_SECURITY_APPARMOR_STACKED))) {
aa_info_message("AppArmor disabled by boot time parameter");
apparmor_enabled = false;
return 0;
diff --git a/security/security.c b/security/security.c
index a151d728aed2..e7c8506041f1 100644
--- a/security/security.c
+++ b/security/security.c
@@ -37,6 +37,7 @@

/* Maximum number of letters for an LSM name string */
#define SECURITY_NAME_MAX 10
+#define MODULE_STACK "(stacking)"

struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
@@ -49,7 +50,11 @@ static struct lsm_blob_sizes blob_sizes;

/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
+#ifdef CONFIG_SECURITY_STACKING
+ MODULE_STACK;
+#else
CONFIG_DEFAULT_SECURITY;
+#endif

static void __init do_security_initcalls(void)
{
@@ -173,6 +178,7 @@ static int lsm_append(char *new, char **result)
/**
* security_module_enable - Load given security module on boot ?
* @module: the name of the module
+ * @stacked: indicates that the module wants to be stacked
*
* Each LSM must pass this method before registering its own operations
* to avoid security registration races. This method may also be used
@@ -188,9 +194,29 @@ static int lsm_append(char *new, char **result)
*
* Otherwise, return false.
*/
-int __init security_module_enable(const char *module)
+bool __init security_module_enable(const char *lsm, const bool stacked)
{
- return !strcmp(module, chosen_lsm);
+#ifdef CONFIG_SECURITY_STACKING
+ /*
+ * Module defined on the command line security=XXXX
+ */
+ if (strcmp(chosen_lsm, MODULE_STACK)) {
+ if (!strcmp(lsm, chosen_lsm)) {
+ pr_info("Command line sets the %s security module.\n",
+ lsm);
+ return true;
+ }
+ return false;
+ }
+ /*
+ * Module configured as stacked.
+ */
+ return stacked;
+#else
+ if (strcmp(lsm, chosen_lsm) == 0)
+ return true;
+ return false;
+#endif
}

/**
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 3c53a3ba480e..44337d2349d9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -6981,7 +6981,8 @@ static __init int selinux_init(void)
{
static int finish;

- if (!security_module_enable("selinux")) {
+ if (!security_module_enable("selinux",
+ IS_ENABLED(CONFIG_SECURITY_SELINUX_STACKED))) {
selinux_enabled = 0;
return 0;
}
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 5bf9f280e9b2..ee4471213909 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -160,18 +160,30 @@ struct bpf_security_struct {
extern struct lsm_blob_sizes selinux_blob_sizes;
static inline struct task_security_struct *selinux_cred(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return cred->security + selinux_blob_sizes.lbs_cred;
+#else
return cred->security;
+#endif
}

static inline struct file_security_struct *selinux_file(const struct file *file)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return file->f_security + selinux_blob_sizes.lbs_file;
+#else
return file->f_security;
+#endif
}

static inline struct inode_security_struct *selinux_inode(
const struct inode *inode)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return inode->i_security + selinux_blob_sizes.lbs_inode;
+#else
return inode->i_security;
+#endif
}

static inline struct msg_security_struct *selinux_msg_msg(
diff --git a/security/smack/smack.h b/security/smack/smack.h
index dffa0ba8fd49..59d0bc994304 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -337,6 +337,7 @@ extern struct smack_known *smack_syslog_label;
extern struct smack_known *smack_unconfined;
#endif
extern int smack_ptrace_rule;
+extern struct lsm_blob_sizes smack_blob_sizes;

extern struct smack_known smack_known_floor;
extern struct smack_known smack_known_hat;
@@ -359,17 +360,29 @@ extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];

static inline struct task_smack *smack_cred(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return cred->security + smack_blob_sizes.lbs_cred;
+#else
return cred->security;
+#endif
}

static inline struct smack_known **smack_file(const struct file *file)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return file->f_security + smack_blob_sizes.lbs_file;
+#else
return file->f_security;
+#endif
}

static inline struct inode_smack *smack_inode(const struct inode *inode)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return inode->i_security + smack_blob_sizes.lbs_inode;
+#else
return inode->i_security;
+#endif
}

static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 8f3b809d7c26..784300406b97 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -4734,7 +4734,8 @@ static __init int smack_init(void)
struct cred *cred = (struct cred *) current->cred;
struct task_smack *tsp;

- if (!security_module_enable("smack"))
+ if (!security_module_enable("smack",
+ IS_ENABLED(CONFIG_SECURITY_SMACK_STACKED)))
return 0;

if (!finish) {
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 0110bebe86e2..c734f0b63100 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -1087,6 +1087,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+extern struct lsm_blob_sizes tomoyo_blob_sizes;

/********** Inlined functions. **********/

@@ -1206,7 +1207,11 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
*/
static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred)
{
+#ifdef CONFIG_SECURITY_STACKING
+ return cred->security + tomoyo_blob_sizes.lbs_cred;
+#else
return cred->security;
+#endif
}

/**
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index bb84e6ec3886..fa121ad8534a 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -564,7 +564,8 @@ static int __init tomoyo_init(void)
struct cred *cred = (struct cred *) current_cred();
struct tomoyo_domain_info **blob;

- if (!security_module_enable("tomoyo")) {
+ if (!security_module_enable("tomoyo",
+ IS_ENABLED(CONFIG_SECURITY_TOMOYO_STACKED))) {
tomoyo_enabled = false;
return 0;
}
--
2.17.1



2018-09-22 00:21:36

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 18/19] LSM: Infrastructure management of the ipc security blob

Move management of the kern_ipc_perm->security and
msg_msg->security blobs out of the individual security
modules and into the security infrastructure. Instead
of allocating the blobs from within the modules the modules
tell the infrastructure how much space is required, and
the space is allocated there.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 2 +
security/security.c | 91 +++++++++++++++++++++++++++++++++--
security/selinux/hooks.c | 98 +++++---------------------------------
security/smack/smack.h | 4 +-
security/smack/smack_lsm.c | 32 ++-----------
5 files changed, 108 insertions(+), 119 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 6057c603b979..f6dbde28833a 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2031,6 +2031,8 @@ struct lsm_blob_sizes {
int lbs_cred;
int lbs_file;
int lbs_inode;
+ int lbs_ipc;
+ int lbs_msg_msg;
int lbs_task;
};

diff --git a/security/security.c b/security/security.c
index 7e11de7eec21..a151d728aed2 100644
--- a/security/security.c
+++ b/security/security.c
@@ -28,6 +28,7 @@
#include <linux/personality.h>
#include <linux/backing-dev.h>
#include <linux/string.h>
+#include <linux/msg.h>
#include <net/flow.h>

#include <trace/events/initcall.h>
@@ -117,6 +118,8 @@ int __init security_init(void)
pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
pr_info("LSM: file blob size = %d\n", blob_sizes.lbs_file);
pr_info("LSM: inode blob size = %d\n", blob_sizes.lbs_inode);
+ pr_info("LSM: ipc blob size = %d\n", blob_sizes.lbs_ipc);
+ pr_info("LSM: msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
pr_info("LSM: task blob size = %d\n", blob_sizes.lbs_task);
#endif

@@ -302,6 +305,8 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
blob_sizes.lbs_inode = sizeof(struct rcu_head);
lsm_set_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_set_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_set_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
lsm_set_size(&needed->lbs_task, &blob_sizes.lbs_task);
}

@@ -387,6 +392,48 @@ int lsm_task_alloc(struct task_struct *task)
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.
+ */
+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.
+ */
+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
@@ -1468,22 +1515,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)
@@ -1510,12 +1575,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)
@@ -1535,12 +1609,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)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e6cb5fce5437..3c53a3ba480e 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5832,51 +5832,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)
{
@@ -5898,11 +5869,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)
{
@@ -5911,11 +5877,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;
@@ -5923,16 +5886,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)
@@ -6062,11 +6016,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;
@@ -6074,16 +6025,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)
@@ -6159,11 +6101,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;
@@ -6171,16 +6110,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)
@@ -6813,6 +6743,8 @@ struct lsm_blob_sizes selinux_blob_sizes = {
.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 = {
@@ -6923,24 +6855,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),
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 52cea142fcf6..dffa0ba8fd49 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -374,12 +374,12 @@ static inline struct inode_smack *smack_inode(const struct inode *inode)

static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg)
{
- return (struct smack_known **)&msg->security;
+ return msg->security;
}

static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
{
- return (struct smack_known **)&ipc->security;
+ return ipc->security;
}

/*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 4afc8899f83f..8f3b809d7c26 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2880,23 +2880,12 @@ 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
@@ -2924,17 +2913,6 @@ static int smack_ipc_alloc_security(struct kern_ipc_perm *isp)
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
@@ -4576,6 +4554,8 @@ struct lsm_blob_sizes smack_blob_sizes = {
.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 = {
@@ -4647,23 +4627,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),
--
2.17.1



2018-09-22 00:22:02

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 16/19] SELinux: Abstract use of ipc security blobs

Don't use the ipc->security pointer directly.
Don't use the msg_msg->security pointer directly.
Provide helper functions that provides the security blob pointers.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/selinux/hooks.c | 18 +++++++++---------
security/selinux/include/objsec.h | 13 +++++++++++++
2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 389e51ef48a5..e6cb5fce5437 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5884,7 +5884,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;
@@ -5941,7 +5941,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;
@@ -5990,8 +5990,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
@@ -6038,8 +6038,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;
@@ -6092,7 +6092,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;
@@ -6189,7 +6189,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;
@@ -6275,7 +6275,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;
}

diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 591adb374d69..5bf9f280e9b2 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -26,6 +26,7 @@
#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"
@@ -173,4 +174,16 @@ static inline struct inode_security_struct *selinux_inode(
return inode->i_security;
}

+static inline struct msg_security_struct *selinux_msg_msg(
+ const struct msg_msg *msg_msg)
+{
+ return msg_msg->security;
+}
+
+static inline struct ipc_security_struct *selinux_ipc(
+ const struct kern_ipc_perm *ipc)
+{
+ return ipc->security;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
--
2.17.1



2018-09-22 00:23:48

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 09/19] SELinux: Abstract use of file security blob

Don't use the file->f_security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
security/selinux/hooks.c | 18 +++++++++---------
security/selinux/include/objsec.h | 5 +++++
2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b629cc302088..641a8ce726ff 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -396,7 +396,7 @@ static int file_alloc_security(struct file *file)

static void file_free_security(struct file *file)
{
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
file->f_security = NULL;
kmem_cache_free(file_security_cache, fsec);
}
@@ -1879,7 +1879,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);
@@ -2223,7 +2223,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;
@@ -3535,7 +3535,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();

@@ -3570,7 +3570,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;
@@ -3822,7 +3822,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();
}

@@ -3837,7 +3837,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 */
@@ -3861,7 +3861,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
@@ -4000,7 +4000,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);
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index ad511c3d2eb7..cad8b765f6dd 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -165,4 +165,9 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred)
return cred->security;
}

+static inline struct file_security_struct *selinux_file(const struct file *file)
+{
+ return file->f_security;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
--
2.17.1



2018-09-22 00:23:55

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 09/19] SELinux: Abstract use of file security blob

Don't use the file->f_security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
security/selinux/hooks.c | 18 +++++++++---------
security/selinux/include/objsec.h | 5 +++++
2 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index b629cc302088..641a8ce726ff 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -396,7 +396,7 @@ static int file_alloc_security(struct file *file)

static void file_free_security(struct file *file)
{
- struct file_security_struct *fsec = file->f_security;
+ struct file_security_struct *fsec = selinux_file(file);
file->f_security = NULL;
kmem_cache_free(file_security_cache, fsec);
}
@@ -1879,7 +1879,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);
@@ -2223,7 +2223,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;
@@ -3535,7 +3535,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();

@@ -3570,7 +3570,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;
@@ -3822,7 +3822,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();
}

@@ -3837,7 +3837,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 */
@@ -3861,7 +3861,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
@@ -4000,7 +4000,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);
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index ad511c3d2eb7..cad8b765f6dd 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -165,4 +165,9 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred)
return cred->security;
}

+static inline struct file_security_struct *selinux_file(const struct file *file)
+{
+ return file->f_security;
+}
+
#endif /* _SELINUX_OBJSEC_H_ */
--
2.17.1



2018-09-22 00:25:29

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 13/19] Smack: Abstract use of inode security blob

Don't use the inode->i_security pointer directly.
Provide a helper function that provides the security blob pointer.

Signed-off-by: Casey Schaufler <[email protected]>
Reviewed-by: Kees Cook <[email protected]>
---
security/smack/smack.h | 9 +++++++--
security/smack/smack_lsm.c | 32 ++++++++++++++++----------------
2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/security/smack/smack.h b/security/smack/smack.h
index 62a22ad8ce92..add19b7efc96 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -366,12 +366,17 @@ static inline struct smack_known **smack_file(const struct file *file)
return file->f_security;
}

+static inline struct inode_smack *smack_inode(const struct inode *inode)
+{
+ return inode->i_security;
+}
+
/*
* 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;
}

@@ -380,7 +385,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;
}

diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index d1430341798f..364699ad55b9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -166,7 +166,7 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc)
static int smk_bu_inode(struct inode *inode, int mode, int rc)
{
struct task_smack *tsp = smack_cred(current_cred());
- 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)
@@ -198,7 +198,7 @@ static int smk_bu_file(struct file *file, int mode, int rc)
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)
@@ -228,7 +228,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
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)
@@ -824,7 +824,7 @@ static int smack_set_mnt_opts(struct super_block *sb,
/*
* Initialize the root inode.
*/
- isp = inode->i_security;
+ isp = smack_inode(inode);
if (isp == NULL) {
isp = new_inode_smack(sp->smk_root);
if (isp == NULL)
@@ -912,7 +912,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;

@@ -992,7 +992,7 @@ static void smack_inode_free_rcu(struct rcu_head *head)
*/
static void smack_inode_free_security(struct inode *inode)
{
- struct inode_smack *issp = inode->i_security;
+ struct inode_smack *issp = smack_inode(inode);

/*
* The inode may still be referenced in a path walk and
@@ -1020,7 +1020,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);
@@ -1358,7 +1358,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;
@@ -1439,7 +1439,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
@@ -1714,7 +1714,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;
@@ -2056,7 +2056,7 @@ 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 inode_smack *isp = smack_inode(inode);
struct task_smack *tsp = smack_cred(new);

tsp->smk_forked = isp->smk_inode;
@@ -2256,7 +2256,7 @@ static int smack_task_kill(struct task_struct *p, struct 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;
@@ -2719,7 +2719,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;
@@ -3327,7 +3327,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);
/*
@@ -4559,7 +4559,7 @@ static int smack_inode_copy_up(struct dentry *dentry, struct cred **new)
/*
* 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;
@@ -4596,7 +4596,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();
--
2.17.1



2018-09-22 02:43:57

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 04/19] SELinux: Remove cred security blob poisoning

On Fri, Sep 21, 2018 at 5:17 PM, Casey Schaufler <[email protected]> wrote:
> The SELinux specific credential poisioning only makes sense
> if SELinux is managing the credentials. As the intent of this
> patch set is to move the blob management out of the modules
> and into the infrastructure, the SELinux specific code has
> to go. The poisioning could be introduced into the infrastructure
> at some later date.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees


> ---
> kernel/cred.c | 13 -------------
> security/selinux/hooks.c | 6 ------
> 2 files changed, 19 deletions(-)
>
> diff --git a/kernel/cred.c b/kernel/cred.c
> index ecf03657e71c..fa2061ee4955 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -704,19 +704,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);
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 9d6cdd21acb6..80614ca25a2b 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -3920,12 +3920,6 @@ static void selinux_cred_free(struct cred *cred)
> {
> struct task_security_struct *tsec = selinux_cred(cred);
>
> - /*
> - * 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);
> }
>
> --
> 2.17.1
>
>



--
Kees Cook
Pixel Security

2018-09-22 02:44:39

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 05/19] SELinux: Remove unused selinux_is_enabled

On Fri, Sep 21, 2018 at 5:17 PM, Casey Schaufler <[email protected]> wrote:
> There are no longer users of selinux_is_enabled().
> Remove it. As selinux_is_enabled() is the only reason
> for include/linux/selinux.h remove that as well.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:46:07

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 02/19] Smack: Abstract use of cred security blob

On Fri, Sep 21, 2018 at 5:17 PM, Casey Schaufler <[email protected]> wrote:
> Don't use the cred->security pointer directly.
> Provide a helper function that provides the security blob pointer.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:47:43

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 06/19] AppArmor: Abstract use of cred security blob

On Fri, Sep 21, 2018 at 5:17 PM, Casey Schaufler <[email protected]> wrote:
> Don't use the cred->security pointer directly.
> Provide a helper function that provides the security blob pointer.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:49:15

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 07/19] TOMOYO: Abstract use of cred security blob

On Fri, Sep 21, 2018 at 5:18 PM, Casey Schaufler <[email protected]> wrote:
> Don't use the cred->security pointer directly.
> Provide helper functions that provide the security blob pointer.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:51:07

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 08/19] Infrastructure management of the cred security blob

On Fri, Sep 21, 2018 at 5:18 PM, Casey Schaufler <[email protected]> wrote:
> Move management of the cred security blob out of the
> security modules and into the security infrastructre.
> Instead of allocating and freeing space the security
> modules tell the infrastructure how much space they
> require.
>
> Signed-off-by: Casey Schaufler <[email protected]>

When combined with my series, this gets slightly simpler:
- the double init call and the "finished" stuff goes away
- debugging output is controlled by "lsm.debug" param instead of a CONFIG

Regardless, for the overall logic, calculating the sizes, etc:

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:53:37

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 10/19] Smack: Abstract use of file security blob

On Fri, Sep 21, 2018 at 5:18 PM, Casey Schaufler <[email protected]> wrote:
> Don't use the file->f_security pointer directly.
> Provide a helper function that provides the security blob pointer.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:55:11

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 11/19] LSM: Infrastructure management of the file security

On Fri, Sep 21, 2018 at 5:19 PM, Casey Schaufler <[email protected]> wrote:
> Move management of the file->f_security blob out of the
> individual security modules and into the infrastructure.
> The modules no longer allocate or free the data, instead
> they tell the infrastructure how much space they require.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:56:08

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 14/19] LSM: Infrastructure management of the inode security

On Fri, Sep 21, 2018 at 5:19 PM, Casey Schaufler <[email protected]> wrote:
> Move management of the inode->i_security blob out
> of the individual security modules and into the security
> infrastructure. Instead of allocating the blobs from within
> the modules the modules tell the infrastructure how much
> space is required, and the space is allocated there.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> ---
> include/linux/lsm_hooks.h | 3 ++
> security/security.c | 83 ++++++++++++++++++++++++++++++-
> security/selinux/hooks.c | 32 +-----------
> security/selinux/include/objsec.h | 5 +-
> security/smack/smack_lsm.c | 70 ++++----------------------
> 5 files changed, 98 insertions(+), 95 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 167ffbd4d0c0..416b20c3795b 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -2030,6 +2030,7 @@ struct security_hook_list {
> struct lsm_blob_sizes {
> int lbs_cred;
> int lbs_file;
> + int lbs_inode;
> };
>
> /*
> @@ -2092,9 +2093,11 @@ static inline void loadpin_add_hooks(void) { };
> #endif
>
> extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
> +extern int lsm_inode_alloc(struct inode *inode);
>
> #ifdef CONFIG_SECURITY
> void lsm_early_cred(struct cred *cred);
> +void lsm_early_inode(struct inode *inode);
> #endif
>
> #endif /* ! __LINUX_LSM_HOOKS_H */
> diff --git a/security/security.c b/security/security.c
> index 5430cae73cf6..a8f00fdff4d8 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -41,6 +41,7 @@ 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;
> @@ -101,6 +102,10 @@ int __init security_init(void)
> 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);
> /*
> * The second call to a module specific init function
> * adds hooks to the hook lists and does any other early
> @@ -111,6 +116,7 @@ int __init security_init(void)
> #ifdef CONFIG_SECURITY_LSM_DEBUG
> pr_info("LSM: cred blob size = %d\n", blob_sizes.lbs_cred);
> pr_info("LSM: file blob size = %d\n", blob_sizes.lbs_file);
> + pr_info("LSM: inode blob size = %d\n", blob_sizes.lbs_inode);
> #endif
>
> return 0;
> @@ -288,6 +294,13 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
> {
> lsm_set_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
> lsm_set_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_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
> }
>
> /**
> @@ -311,6 +324,46 @@ int lsm_file_alloc(struct file *file)
> 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_early_inode - during initialization allocate a composite inode blob
> + * @inode: the inode that needs a blob
> + *
> + * Allocate the inode blob for all the modules if it's not already there
> + */
> +void lsm_early_inode(struct inode *inode)
> +{
> + int rc;
> +
> + if (inode == NULL)
> + panic("%s: NULL inode.\n", __func__);
> + if (inode->i_security != NULL)
> + return;
> + rc = lsm_inode_alloc(inode);
> + if (rc)
> + panic("%s: Early inode alloc failed.\n", __func__);
> +}

I'm still advising against using panic(), but I'll leave it up to James.

For everything else here:

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:58:21

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 16/19] SELinux: Abstract use of ipc security blobs

On Fri, Sep 21, 2018 at 5:19 PM, Casey Schaufler <[email protected]> wrote:
> Don't use the ipc->security pointer directly.
> Don't use the msg_msg->security pointer directly.
> Provide helper functions that provides the security blob pointers.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:58:52

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 15/19] LSM: Infrastructure management of the task security

On Fri, Sep 21, 2018 at 5:19 PM, Casey Schaufler <[email protected]> wrote:
> Move management of the task_struct->security blob out
> of the individual security modules and into the security
> infrastructure. Instead of allocating the blobs from within
> the modules the modules tell the infrastructure how much
> space is required, and the space is allocated there.
> The only user of this blob is AppArmor. The AppArmor use
> is abstracted to avoid future conflict.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:58:53

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 17/19] Smack: Abstract use of ipc security blobs

On Fri, Sep 21, 2018 at 5:19 PM, Casey Schaufler <[email protected]> wrote:
> Don't use the ipc->security pointer directly.
> Don't use the msg_msg->security pointer directly.
> Provide helper functions that provides the security blob pointers.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 02:59:34

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 18/19] LSM: Infrastructure management of the ipc security blob

On Fri, Sep 21, 2018 at 5:20 PM, Casey Schaufler <[email protected]> wrote:
> Move management of the kern_ipc_perm->security and
> msg_msg->security blobs out of the individual security
> modules and into the security infrastructure. Instead
> of allocating the blobs from within the modules the modules
> tell the infrastructure how much space is required, and
> the space is allocated there.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

-Kees

--
Kees Cook
Pixel Security

2018-09-22 03:03:24

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On Fri, Sep 21, 2018 at 4:59 PM, Casey Schaufler <[email protected]> wrote:
> 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.

Thanks for the splitting, this really does make it easier to review
(at least for me). I think this looks really good, though obviously
I'd like to refactor it slightly on top of my series. :)

One additional thought I had was about the blobs allocations: some are
separate kmem caches, and some are kmalloc. I'm thinking it might make
sense to use separate kmem caches for two reasons:

- they're going to always be the same size and are regularly
allocated/freed, so it may offer a performance benefit.

- they're explicitly not supposed to be exposed to userspace, so
hardened usercopy would protect them if they were not kmalloc()ed.

I'm excited about getting this landed!

-Kees

--
Kees Cook
Pixel Security

2018-09-22 16:39:20

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 9/21/2018 8:02 PM, Kees Cook wrote:
> On Fri, Sep 21, 2018 at 4:59 PM, Casey Schaufler <[email protected]> wrote:
>> 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.
> Thanks for the splitting, this really does make it easier to review
> (at least for me). I think this looks really good, though obviously
> I'd like to refactor it slightly on top of my series. :)

Whichever goes on top is fine with me. What's one
more patch set merge, after all?

> One additional thought I had was about the blobs allocations: some are
> separate kmem caches, and some are kmalloc. I'm thinking it might make
> sense to use separate kmem caches for two reasons:

I had seriously considered doing that. I can't see any reason
not to. It's something that could be done at any time, and with
all the other things that had to change it just didn't get in.

> - they're going to always be the same size and are regularly
> allocated/freed, so it may offer a performance benefit.
>
> - they're explicitly not supposed to be exposed to userspace, so
> hardened usercopy would protect them if they were not kmalloc()ed.
>
> I'm excited about getting this landed!

Soon. Real soon. I hope. I would very much like for
someone from the SELinux camp to chime in, especially on
the selinux_is_enabled() removal.

On a somewhat related note, I will be out for the first three
weeks of October, returning just in time for the Linux Security
Summit in Edinburgh. My connectivity will be severely limited.
I don't expect to accomplish anything while I'm out.


2018-09-23 02:44:05

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On Sat, Sep 22, 2018 at 9:38 AM, Casey Schaufler <[email protected]> wrote:
> On 9/21/2018 8:02 PM, Kees Cook wrote:
>> On Fri, Sep 21, 2018 at 4:59 PM, Casey Schaufler <[email protected]> wrote:
>>> 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.
>> Thanks for the splitting, this really does make it easier to review
>> (at least for me). I think this looks really good, though obviously
>> I'd like to refactor it slightly on top of my series. :)
>
> Whichever goes on top is fine with me. What's one
> more patch set merge, after all?
>
>> One additional thought I had was about the blobs allocations: some are
>> separate kmem caches, and some are kmalloc. I'm thinking it might make
>> sense to use separate kmem caches for two reasons:
>
> I had seriously considered doing that. I can't see any reason
> not to. It's something that could be done at any time, and with
> all the other things that had to change it just didn't get in.

Yup; that is an easy future change. Not needed now!

>
>> - they're going to always be the same size and are regularly
>> allocated/freed, so it may offer a performance benefit.
>>
>> - they're explicitly not supposed to be exposed to userspace, so
>> hardened usercopy would protect them if they were not kmalloc()ed.
>>
>> I'm excited about getting this landed!
>
> Soon. Real soon. I hope. I would very much like for
> someone from the SELinux camp to chime in, especially on
> the selinux_is_enabled() removal.

Agreed.

> On a somewhat related note, I will be out for the first three
> weeks of October, returning just in time for the Linux Security
> Summit in Edinburgh. My connectivity will be severely limited.
> I don't expect to accomplish anything while I'm out.

If you're okay with it, I can help with changes while you're out -- I
want to try to rebase it on my tree and see how it looks anyway. :)

-Kees

--
Kees Cook
Pixel Security

2018-09-23 16:03:46

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 2018/09/23 11:43, Kees Cook wrote:
>>> I'm excited about getting this landed!
>>
>> Soon. Real soon. I hope. I would very much like for
>> someone from the SELinux camp to chime in, especially on
>> the selinux_is_enabled() removal.
>
> Agreed.
>

This patchset from Casey lands before the patchset from Kees, doesn't it?
OK, a few comments (if I didn't overlook something).

lsm_early_cred()/lsm_early_task() are called from only __init functions.

lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .

lsm_early_inode() should be avoided because it is not appropriate to
call panic() when lsm_early_inode() is called after __init phase.

Since all free hooks are called when one of init hooks failed, each
free hook needs to check whether init hook was called. An example is
inode_free_security() in security/selinux/hooks.c (but not addressed in
this patch).

This patchset might fatally prevent LKM-based LSM modules, for LKM-based
LSMs cannot count on lsm_*_alloc() because size for lsm_*_alloc() cannot
be updated upon loading LKM-based LSMs. If security_file_free() is called
regardless of whether lsm_file_cache is defined, LKM-based LSMs can be
loaded using current behavior (apart from the fact that legitimate
interface for appending to security_hook_heads is currently missing).
How do you plan to handle LKM-based LSMs?

include/linux/lsm_hooks.h | 6 ++----
security/security.c | 31 ++++++-------------------------
security/smack/smack_lsm.c | 8 +++++++-
3 files changed, 15 insertions(+), 30 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7e8b32f..8014614 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2095,13 +2095,11 @@ static inline void __init yama_add_hooks(void) { }
static inline void loadpin_add_hooks(void) { };
#endif

-extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
extern int lsm_inode_alloc(struct inode *inode);

#ifdef CONFIG_SECURITY
-void lsm_early_cred(struct cred *cred);
-void lsm_early_inode(struct inode *inode);
-void lsm_early_task(struct task_struct *task);
+void __init lsm_early_cred(struct cred *cred);
+void __init lsm_early_task(struct task_struct *task);
#endif

#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/security.c b/security/security.c
index e7c85060..341e8df 100644
--- a/security/security.c
+++ b/security/security.c
@@ -267,7 +267,7 @@ int unregister_lsm_notifier(struct notifier_block *nb)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
{
if (blob_sizes.lbs_cred == 0) {
cred->security = NULL;
@@ -286,7 +286,7 @@ int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
*
* Allocate the cred blob for all the modules if it's not already there
*/
-void lsm_early_cred(struct cred *cred)
+void __init lsm_early_cred(struct cred *cred)
{
int rc;

@@ -344,7 +344,7 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-int lsm_file_alloc(struct file *file)
+static int lsm_file_alloc(struct file *file)
{
if (!lsm_file_cache) {
file->f_security = NULL;
@@ -379,25 +379,6 @@ int lsm_inode_alloc(struct inode *inode)
}

/**
- * lsm_early_inode - during initialization allocate a composite inode blob
- * @inode: the inode that needs a blob
- *
- * Allocate the inode blob for all the modules if it's not already there
- */
-void lsm_early_inode(struct inode *inode)
-{
- int rc;
-
- if (inode == NULL)
- panic("%s: NULL inode.\n", __func__);
- if (inode->i_security != NULL)
- return;
- rc = lsm_inode_alloc(inode);
- if (rc)
- panic("%s: Early inode alloc failed.\n", __func__);
-}
-
-/**
* lsm_task_alloc - allocate a composite task blob
* @task: the task that needs a blob
*
@@ -466,7 +447,7 @@ int lsm_msg_msg_alloc(struct msg_msg *mp)
*
* Allocate the task blob for all the modules if it's not already there
*/
-void lsm_early_task(struct task_struct *task)
+void __init lsm_early_task(struct task_struct *task)
{
int rc;

@@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
{
void *blob;

+ call_void_hook(file_free_security, file);
+
if (!lsm_file_cache)
return;

- call_void_hook(file_free_security, file);
-
blob = file->f_security;
file->f_security = NULL;
kmem_cache_free(lsm_file_cache, blob);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 7843004..b0b4045 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -750,6 +750,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.
@@ -818,7 +825,6 @@ static int smack_set_mnt_opts(struct super_block *sb,
/*
* Initialize the root inode.
*/
- lsm_early_inode(inode);
init_inode_smack(inode, sp->smk_root);

if (transmute) {


2018-09-23 17:14:08

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 9/23/2018 8:59 AM, Tetsuo Handa wrote:
> On 2018/09/23 11:43, Kees Cook wrote:
>>>> I'm excited about getting this landed!
>>> Soon. Real soon. I hope. I would very much like for
>>> someone from the SELinux camp to chime in, especially on
>>> the selinux_is_enabled() removal.
>> Agreed.
>>
> This patchset from Casey lands before the patchset from Kees, doesn't it?

That is up for negotiation. We may end up combining them.

> OK, a few comments (if I didn't overlook something).
>
> lsm_early_cred()/lsm_early_task() are called from only __init functions.

True.

> lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .

Also true.

> lsm_early_inode() should be avoided because it is not appropriate to
> call panic() when lsm_early_inode() is called after __init phase.

You're correct. In fact, lsm_early_inode() isn't needed at all
until multiple inode using modules are supported.

> Since all free hooks are called when one of init hooks failed, each
> free hook needs to check whether init hook was called. An example is
> inode_free_security() in security/selinux/hooks.c (but not addressed in
> this patch).

I *think* that selinux_inode_free_security() is safe in this
case because the blob will be zeroed, hence isec->list will
be NULL.

> This patchset might fatally prevent LKM-based LSM modules, for LKM-based
> LSMs cannot count on lsm_*_alloc() because size for lsm_*_alloc() cannot
> be updated upon loading LKM-based LSMs.

LKM based security modules will require dynamically sized blobs.
These can be added to the scheme used here. Each blob would get a
header identifying the modules for which it contains data. When an
LKM is registered if has to declare it's blob space requirements
and gets back the offsets. All alloc operations have to put their
marks in the header. All LKM blob users have to check that the blob
they are looking at has the required data.

module_cred(struct cred *cred) {
return cred->security + module_blob_sizes.lbs_cred;
}

becomes

module_cred(struct cred *cred) {
if (blob_includes(module_id))
return cred->security + module_blob_sizes.lbs_cred;
return NULL;
}

and the calling code needs to accept a NULL return.
Blobs can never get smaller because readjusting the offsets
isn't going to work, so unloading an LKM security module isn't
going to be as complete as you might like. There may be a way
around this if you unload all the LKM modules, but that's a
special case and there may be dragon lurking in the mist.

> If security_file_free() is called
> regardless of whether lsm_file_cache is defined, LKM-based LSMs can be
> loaded using current behavior (apart from the fact that legitimate
> interface for appending to security_hook_heads is currently missing).
> How do you plan to handle LKM-based LSMs?

My position all along has been that I don't plan to handle LKM
based LSMs, but that I won't do anything to prevent someone else
from adding them later. I believe that I've done that. Several
designs, including a separate list for dynamically loaded modules
have been proposed. I think some of those would work.

> include/linux/lsm_hooks.h | 6 ++----
> security/security.c | 31 ++++++-------------------------
> security/smack/smack_lsm.c | 8 +++++++-
> 3 files changed, 15 insertions(+), 30 deletions(-)
>
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index 7e8b32f..8014614 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -2095,13 +2095,11 @@ static inline void __init yama_add_hooks(void) { }
> static inline void loadpin_add_hooks(void) { };
> #endif
>
> -extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
> extern int lsm_inode_alloc(struct inode *inode);
>
> #ifdef CONFIG_SECURITY
> -void lsm_early_cred(struct cred *cred);
> -void lsm_early_inode(struct inode *inode);
> -void lsm_early_task(struct task_struct *task);
> +void __init lsm_early_cred(struct cred *cred);
> +void __init lsm_early_task(struct task_struct *task);
> #endif
>
> #endif /* ! __LINUX_LSM_HOOKS_H */
> diff --git a/security/security.c b/security/security.c
> index e7c85060..341e8df 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -267,7 +267,7 @@ int unregister_lsm_notifier(struct notifier_block *nb)
> *
> * Returns 0, or -ENOMEM if memory can't be allocated.
> */
> -int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
> +static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
> {
> if (blob_sizes.lbs_cred == 0) {
> cred->security = NULL;
> @@ -286,7 +286,7 @@ int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
> *
> * Allocate the cred blob for all the modules if it's not already there
> */
> -void lsm_early_cred(struct cred *cred)
> +void __init lsm_early_cred(struct cred *cred)
> {
> int rc;
>
> @@ -344,7 +344,7 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
> *
> * Returns 0, or -ENOMEM if memory can't be allocated.
> */
> -int lsm_file_alloc(struct file *file)
> +static int lsm_file_alloc(struct file *file)
> {
> if (!lsm_file_cache) {
> file->f_security = NULL;
> @@ -379,25 +379,6 @@ int lsm_inode_alloc(struct inode *inode)
> }
>
> /**
> - * lsm_early_inode - during initialization allocate a composite inode blob
> - * @inode: the inode that needs a blob
> - *
> - * Allocate the inode blob for all the modules if it's not already there
> - */
> -void lsm_early_inode(struct inode *inode)
> -{
> - int rc;
> -
> - if (inode == NULL)
> - panic("%s: NULL inode.\n", __func__);
> - if (inode->i_security != NULL)
> - return;
> - rc = lsm_inode_alloc(inode);
> - if (rc)
> - panic("%s: Early inode alloc failed.\n", __func__);
> -}
> -
> -/**
> * lsm_task_alloc - allocate a composite task blob
> * @task: the task that needs a blob
> *
> @@ -466,7 +447,7 @@ int lsm_msg_msg_alloc(struct msg_msg *mp)
> *
> * Allocate the task blob for all the modules if it's not already there
> */
> -void lsm_early_task(struct task_struct *task)
> +void __init lsm_early_task(struct task_struct *task)
> {
> int rc;
>
> @@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
> {
> void *blob;
>
> + call_void_hook(file_free_security, file);
> +
> if (!lsm_file_cache)
> return;
>
> - call_void_hook(file_free_security, file);
> -

Why does this make sense? If the lsm_file_cache isn't
initialized you can't have allocated any file blobs,
no module can have initialized a file blob, hence there
can be nothing for the module to do.

> blob = file->f_security;
> file->f_security = NULL;
> kmem_cache_free(lsm_file_cache, blob);
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 7843004..b0b4045 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -750,6 +750,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.
> @@ -818,7 +825,6 @@ static int smack_set_mnt_opts(struct super_block *sb,
> /*
> * Initialize the root inode.
> */
> - lsm_early_inode(inode);
> init_inode_smack(inode, sp->smk_root);
>
> if (transmute) {


2018-09-24 01:56:27

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 2018/09/24 2:09, Casey Schaufler wrote:
>> Since all free hooks are called when one of init hooks failed, each
>> free hook needs to check whether init hook was called. An example is
>> inode_free_security() in security/selinux/hooks.c (but not addressed in
>> this patch).
>
> I *think* that selinux_inode_free_security() is safe in this
> case because the blob will be zeroed, hence isec->list will
> be NULL.
>

OK.

>> This patchset might fatally prevent LKM-based LSM modules, for LKM-based
>> LSMs cannot count on lsm_*_alloc() because size for lsm_*_alloc() cannot
>> be updated upon loading LKM-based LSMs.
>
> LKM based security modules will require dynamically sized blobs.
> These can be added to the scheme used here. Each blob would get a
> header identifying the modules for which it contains data. When an
> LKM is registered if has to declare it's blob space requirements
> and gets back the offsets. All alloc operations have to put their
> marks in the header. All LKM blob users have to check that the blob
> they are looking at has the required data.
>
> module_cred(struct cred *cred) {
> return cred->security + module_blob_sizes.lbs_cred;
> }
>
> becomes
>
> module_cred(struct cred *cred) {
> if (blob_includes(module_id))
> return cred->security + module_blob_sizes.lbs_cred;
> return NULL;
> }
>
> and the calling code needs to accept a NULL return.

Not all of LKM-based LSMs use security blobs. And some of LKM-based LSMs
might use security blobs for only a few objects. For example, AKARI uses
inode security blob for remembering whether source address/port of an
accept()ed socket was already checked, only during accept() operation and
first socket operation on the accept()ed socket. Thus, there is no need
to waste memory by assigning blobs for all inode objects.

> Blobs can never get smaller because readjusting the offsets
> isn't going to work, so unloading an LKM security module isn't
> going to be as complete as you might like. There may be a way
> around this if you unload all the LKM modules, but that's a
> special case and there may be dragon lurking in the mist.

If LKM-based LSMs who want to use security blobs have to check for
NULL return, they might choose "not using infrastructure managed
security blobs" and "using locally hashed blobs associated with
object's address" (like AKARI does).

>
>> If security_file_free() is called
>> regardless of whether lsm_file_cache is defined, LKM-based LSMs can be
>> loaded using current behavior (apart from the fact that legitimate
>> interface for appending to security_hook_heads is currently missing).
>> How do you plan to handle LKM-based LSMs?
>
> My position all along has been that I don't plan to handle LKM
> based LSMs, but that I won't do anything to prevent someone else
> from adding them later. I believe that I've done that. Several
> designs, including a separate list for dynamically loaded modules
> have been proposed. I think some of those would work.

Though AKARI is not using security_file_free(), some of LKM-based LSMs
might want to use it. If file_free_security hook is called unconditionally,
such LKM-based LSMs can be registered/unregistered, without worrying about
inability to shrink sizes for blobs.

>> @@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
>> {
>> void *blob;
>>
>> + call_void_hook(file_free_security, file);
>> +
>> if (!lsm_file_cache)
>> return;
>>
>> - call_void_hook(file_free_security, file);
>> -
>
> Why does this make sense? If the lsm_file_cache isn't
> initialized you can't have allocated any file blobs,
> no module can have initialized a file blob, hence there
> can be nothing for the module to do.
>

For modules (not limited to LKM-based LSMs) which want to use
file blobs for only a few objects and avoid wasting memory by
allocating file blobs to all file objects.

Infrastructure based blob management fits well for LSM modules
which want to assign blobs to all objects (like SELinux). But
forcing infrastructure based blob management can become a huge
waste of memory for LSM modules which want to assign blobs to
only a few objects. Unconditionally calling file_free_security
hook (as with other hooks) preserves a room for allowing the
latter type of LSM modules without using infrastructure based
blob management.


2018-09-24 15:07:12

by Stephen Smalley

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 09/23/2018 01:09 PM, Casey Schaufler wrote:
> On 9/23/2018 8:59 AM, Tetsuo Handa wrote:
>> On 2018/09/23 11:43, Kees Cook wrote:
>>>>> I'm excited about getting this landed!
>>>> Soon. Real soon. I hope. I would very much like for
>>>> someone from the SELinux camp to chime in, especially on
>>>> the selinux_is_enabled() removal.
>>> Agreed.
>>>
>> This patchset from Casey lands before the patchset from Kees, doesn't it?
>
> That is up for negotiation. We may end up combining them.
>
>> OK, a few comments (if I didn't overlook something).
>>
>> lsm_early_cred()/lsm_early_task() are called from only __init functions.
>
> True.
>
>> lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .
>
> Also true.
>
>> lsm_early_inode() should be avoided because it is not appropriate to
>> call panic() when lsm_early_inode() is called after __init phase.
>
> You're correct. In fact, lsm_early_inode() isn't needed at all
> until multiple inode using modules are supported.
>
>> Since all free hooks are called when one of init hooks failed, each
>> free hook needs to check whether init hook was called. An example is
>> inode_free_security() in security/selinux/hooks.c (but not addressed in
>> this patch).
>
> I *think* that selinux_inode_free_security() is safe in this
> case because the blob will be zeroed, hence isec->list will
> be NULL.

That's not safe - look more closely at what list_empty_careful() tests,
and then think about what happens when list_del_init() gets called on
that isec->list. selinux_inode_free_security() presumes that
selinux_inode_alloc_security() has been called already. If you are
breaking that assumption, you have to fix it.

Is there a reason you can't make inode_alloc_security() return void
since you moved the allocation to the framework? Unfortunate that
inode_init_security name is already in use for another purpose since
essentially you have reduced these hooks to initialization only.

>
>> This patchset might fatally prevent LKM-based LSM modules, for LKM-based
>> LSMs cannot count on lsm_*_alloc() because size for lsm_*_alloc() cannot
>> be updated upon loading LKM-based LSMs.
>
> LKM based security modules will require dynamically sized blobs.
> These can be added to the scheme used here. Each blob would get a
> header identifying the modules for which it contains data. When an
> LKM is registered if has to declare it's blob space requirements
> and gets back the offsets. All alloc operations have to put their
> marks in the header. All LKM blob users have to check that the blob
> they are looking at has the required data.
>
> module_cred(struct cred *cred) {
> return cred->security + module_blob_sizes.lbs_cred;
> }
>
> becomes
>
> module_cred(struct cred *cred) {
> if (blob_includes(module_id))
> return cred->security + module_blob_sizes.lbs_cred;
> return NULL;
> }
>
> and the calling code needs to accept a NULL return.
> Blobs can never get smaller because readjusting the offsets
> isn't going to work, so unloading an LKM security module isn't
> going to be as complete as you might like. There may be a way
> around this if you unload all the LKM modules, but that's a
> special case and there may be dragon lurking in the mist.
>
>> If security_file_free() is called
>> regardless of whether lsm_file_cache is defined, LKM-based LSMs can be
>> loaded using current behavior (apart from the fact that legitimate
>> interface for appending to security_hook_heads is currently missing).
>> How do you plan to handle LKM-based LSMs?
>
> My position all along has been that I don't plan to handle LKM
> based LSMs, but that I won't do anything to prevent someone else
> from adding them later. I believe that I've done that. Several
> designs, including a separate list for dynamically loaded modules
> have been proposed. I think some of those would work.
>
>> include/linux/lsm_hooks.h | 6 ++----
>> security/security.c | 31 ++++++-------------------------
>> security/smack/smack_lsm.c | 8 +++++++-
>> 3 files changed, 15 insertions(+), 30 deletions(-)
>>
>> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
>> index 7e8b32f..8014614 100644
>> --- a/include/linux/lsm_hooks.h
>> +++ b/include/linux/lsm_hooks.h
>> @@ -2095,13 +2095,11 @@ static inline void __init yama_add_hooks(void) { }
>> static inline void loadpin_add_hooks(void) { };
>> #endif
>>
>> -extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
>> extern int lsm_inode_alloc(struct inode *inode);
>>
>> #ifdef CONFIG_SECURITY
>> -void lsm_early_cred(struct cred *cred);
>> -void lsm_early_inode(struct inode *inode);
>> -void lsm_early_task(struct task_struct *task);
>> +void __init lsm_early_cred(struct cred *cred);
>> +void __init lsm_early_task(struct task_struct *task);
>> #endif
>>
>> #endif /* ! __LINUX_LSM_HOOKS_H */
>> diff --git a/security/security.c b/security/security.c
>> index e7c85060..341e8df 100644
>> --- a/security/security.c
>> +++ b/security/security.c
>> @@ -267,7 +267,7 @@ int unregister_lsm_notifier(struct notifier_block *nb)
>> *
>> * Returns 0, or -ENOMEM if memory can't be allocated.
>> */
>> -int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
>> +static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
>> {
>> if (blob_sizes.lbs_cred == 0) {
>> cred->security = NULL;
>> @@ -286,7 +286,7 @@ int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
>> *
>> * Allocate the cred blob for all the modules if it's not already there
>> */
>> -void lsm_early_cred(struct cred *cred)
>> +void __init lsm_early_cred(struct cred *cred)
>> {
>> int rc;
>>
>> @@ -344,7 +344,7 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
>> *
>> * Returns 0, or -ENOMEM if memory can't be allocated.
>> */
>> -int lsm_file_alloc(struct file *file)
>> +static int lsm_file_alloc(struct file *file)
>> {
>> if (!lsm_file_cache) {
>> file->f_security = NULL;
>> @@ -379,25 +379,6 @@ int lsm_inode_alloc(struct inode *inode)
>> }
>>
>> /**
>> - * lsm_early_inode - during initialization allocate a composite inode blob
>> - * @inode: the inode that needs a blob
>> - *
>> - * Allocate the inode blob for all the modules if it's not already there
>> - */
>> -void lsm_early_inode(struct inode *inode)
>> -{
>> - int rc;
>> -
>> - if (inode == NULL)
>> - panic("%s: NULL inode.\n", __func__);
>> - if (inode->i_security != NULL)
>> - return;
>> - rc = lsm_inode_alloc(inode);
>> - if (rc)
>> - panic("%s: Early inode alloc failed.\n", __func__);
>> -}
>> -
>> -/**
>> * lsm_task_alloc - allocate a composite task blob
>> * @task: the task that needs a blob
>> *
>> @@ -466,7 +447,7 @@ int lsm_msg_msg_alloc(struct msg_msg *mp)
>> *
>> * Allocate the task blob for all the modules if it's not already there
>> */
>> -void lsm_early_task(struct task_struct *task)
>> +void __init lsm_early_task(struct task_struct *task)
>> {
>> int rc;
>>
>> @@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
>> {
>> void *blob;
>>
>> + call_void_hook(file_free_security, file);
>> +
>> if (!lsm_file_cache)
>> return;
>>
>> - call_void_hook(file_free_security, file);
>> -
>
> Why does this make sense? If the lsm_file_cache isn't
> initialized you can't have allocated any file blobs,
> no module can have initialized a file blob, hence there
> can be nothing for the module to do.
>
>> blob = file->f_security;
>> file->f_security = NULL;
>> kmem_cache_free(lsm_file_cache, blob);
>> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
>> index 7843004..b0b4045 100644
>> --- a/security/smack/smack_lsm.c
>> +++ b/security/smack/smack_lsm.c
>> @@ -750,6 +750,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.
>> @@ -818,7 +825,6 @@ static int smack_set_mnt_opts(struct super_block *sb,
>> /*
>> * Initialize the root inode.
>> */
>> - lsm_early_inode(inode);
>> init_inode_smack(inode, sp->smk_root);
>>
>> if (transmute) {
>


2018-09-24 16:18:03

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 9/24/2018 8:01 AM, Stephen Smalley wrote:
> On 09/23/2018 01:09 PM, Casey Schaufler wrote:
>> On 9/23/2018 8:59 AM, Tetsuo Handa wrote:
>>> On 2018/09/23 11:43, Kees Cook wrote:
>>>>>> I'm excited about getting this landed!
>>>>> Soon. Real soon. I hope. I would very much like for
>>>>> someone from the SELinux camp to chime in, especially on
>>>>> the selinux_is_enabled() removal.
>>>> Agreed.
>>>>
>>> This patchset from Casey lands before the patchset from Kees, doesn't it?
>>
>> That is up for negotiation. We may end up combining them.
>>
>>> OK, a few comments (if I didn't overlook something).
>>>
>>>    lsm_early_cred()/lsm_early_task() are called from only __init functions.
>>
>> True.
>>
>>>    lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .
>>
>> Also true.
>>
>>>    lsm_early_inode() should be avoided because it is not appropriate to
>>>    call panic() when lsm_early_inode() is called after __init phase.
>>
>> You're correct. In fact, lsm_early_inode() isn't needed at all
>> until multiple inode using modules are supported.
>>
>>>    Since all free hooks are called when one of init hooks failed, each
>>>    free hook needs to check whether init hook was called. An example is
>>>    inode_free_security() in security/selinux/hooks.c (but not addressed in
>>>    this patch).
>>
>> I *think* that selinux_inode_free_security() is safe in this
>> case because the blob will be zeroed, hence isec->list will
>> be NULL.
>
> That's not safe - look more closely at what list_empty_careful() tests, and then think about what happens when list_del_init() gets called on that isec->list.  selinux_inode_free_security() presumes that selinux_inode_alloc_security() has been called already.  If you are breaking that assumption, you have to fix it.

Yup. I misread the macro my first time around. Easy fix.

> Is there a reason you can't make inode_alloc_security() return void since you moved the allocation to the framework?

No reason with any of the existing modules, But I could see someone
doing unnatural things during allocation that might result in a
failure.

> Unfortunate that inode_init_security name is already in use for another purpose since essentially you have reduced these hooks to initialization only.

I considered that but decided that it makes more sense for the module hook names
to match the infrastructure name. Having security_inode_alloc() call
selinux_inode_setup_security() starts to get confusing.



2018-09-24 17:18:00

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 9/23/2018 6:53 PM, Tetsuo Handa wrote:
> On 2018/09/24 2:09, Casey Schaufler wrote:
>>> Since all free hooks are called when one of init hooks failed, each
>>> free hook needs to check whether init hook was called. An example is
>>> inode_free_security() in security/selinux/hooks.c (but not addressed in
>>> this patch).
>> I *think* that selinux_inode_free_security() is safe in this
>> case because the blob will be zeroed, hence isec->list will
>> be NULL.
>>
> OK.
>
>>> This patchset might fatally prevent LKM-based LSM modules, for LKM-based
>>> LSMs cannot count on lsm_*_alloc() because size for lsm_*_alloc() cannot
>>> be updated upon loading LKM-based LSMs.
>> LKM based security modules will require dynamically sized blobs.
>> These can be added to the scheme used here. Each blob would get a
>> header identifying the modules for which it contains data. When an
>> LKM is registered if has to declare it's blob space requirements
>> and gets back the offsets. All alloc operations have to put their
>> marks in the header. All LKM blob users have to check that the blob
>> they are looking at has the required data.
>>
>> module_cred(struct cred *cred) {
>> return cred->security + module_blob_sizes.lbs_cred;
>> }
>>
>> becomes
>>
>> module_cred(struct cred *cred) {
>> if (blob_includes(module_id))
>> return cred->security + module_blob_sizes.lbs_cred;
>> return NULL;
>> }
>>
>> and the calling code needs to accept a NULL return.
> Not all of LKM-based LSMs use security blobs. And some of LKM-based LSMs
> might use security blobs for only a few objects. For example, AKARI uses
> inode security blob for remembering whether source address/port of an
> accept()ed socket was already checked, only during accept() operation and
> first socket operation on the accept()ed socket. Thus, there is no need
> to waste memory by assigning blobs for all inode objects.

The first question is why use an inode blob? Shouldn't you
be using a socket blob for this socket based information?

If you only want information part of the time you can declare
a pointer sized blob and manage what hangs off that as you will.
I personally think that the added complexity of conditional
blob management is more pain than it's worth, but if you want
a really big blob, but only on occasion, I could see doing it.

>> Blobs can never get smaller because readjusting the offsets
>> isn't going to work, so unloading an LKM security module isn't
>> going to be as complete as you might like. There may be a way
>> around this if you unload all the LKM modules, but that's a
>> special case and there may be dragon lurking in the mist.
> If LKM-based LSMs who want to use security blobs have to check for
> NULL return, they might choose "not using infrastructure managed
> security blobs" and "using locally hashed blobs associated with
> object's address" (like AKARI does).

I can't see how a check for NULL could possibly be a bigger
hassle than doing your own locally hashed blobs.

>
>>> If security_file_free() is called
>>> regardless of whether lsm_file_cache is defined, LKM-based LSMs can be
>>> loaded using current behavior (apart from the fact that legitimate
>>> interface for appending to security_hook_heads is currently missing).
>>> How do you plan to handle LKM-based LSMs?
>> My position all along has been that I don't plan to handle LKM
>> based LSMs, but that I won't do anything to prevent someone else
>> from adding them later. I believe that I've done that. Several
>> designs, including a separate list for dynamically loaded modules
>> have been proposed. I think some of those would work.
> Though AKARI is not using security_file_free(), some of LKM-based LSMs
> might want to use it. If file_free_security hook is called unconditionally,
> such LKM-based LSMs can be registered/unregistered, without worrying about
> inability to shrink sizes for blobs.

The infrastructure wouldn't call unregistered hooks, so any module
that allocates additional memory attached to a blob is going to have
to deal with freeing that when it unregisters. Aside from that unregistration
should be a (not so) small matter of locking.

>
>>> @@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
>>> {
>>> void *blob;
>>>
>>> + call_void_hook(file_free_security, file);
>>> +
>>> if (!lsm_file_cache)
>>> return;
>>>
>>> - call_void_hook(file_free_security, file);
>>> -
>> Why does this make sense? If the lsm_file_cache isn't
>> initialized you can't have allocated any file blobs,
>> no module can have initialized a file blob, hence there
>> can be nothing for the module to do.
>>
> For modules (not limited to LKM-based LSMs) which want to use
> file blobs for only a few objects and avoid wasting memory by
> allocating file blobs to all file objects.
>
> Infrastructure based blob management fits well for LSM modules
> which want to assign blobs to all objects (like SELinux). But
> forcing infrastructure based blob management can become a huge
> waste of memory for LSM modules which want to assign blobs to
> only a few objects. Unconditionally calling file_free_security
> hook (as with other hooks) preserves a room for allowing the
> latter type of LSM modules without using infrastructure based
> blob management.

There is a hypothetical issue here, but that would require abuse
of the infrastructure. Having a file_free_security hook that doesn't
free a security blob allocated by file_alloc_security may coincidentaly
be useful, but that's not the intent of the hook.


2018-09-24 17:23:40

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 2018/09/25 1:15, Casey Schaufler wrote:
>>>>    Since all free hooks are called when one of init hooks failed, each
>>>>    free hook needs to check whether init hook was called. An example is
>>>>    inode_free_security() in security/selinux/hooks.c (but not addressed in
>>>>    this patch).
>>>
>>> I *think* that selinux_inode_free_security() is safe in this
>>> case because the blob will be zeroed, hence isec->list will
>>> be NULL.
>>
>> That's not safe - look more closely at what list_empty_careful() tests, and then think about what happens when list_del_init() gets called on that isec->list.  selinux_inode_free_security() presumes that selinux_inode_alloc_security() has been called already.  If you are breaking that assumption, you have to fix it.
>
> Yup. I misread the macro my first time around. Easy fix.

Oh, I didn't notice that it is doing !list_empty_careful() than list_empty_careful().
Unsafe indeed. But easy to fix.

>
>> Is there a reason you can't make inode_alloc_security() return void since you moved the allocation to the framework?
>
> No reason with any of the existing modules, But I could see someone
> doing unnatural things during allocation that might result in a
> failure.

Currently upstreamed LSM modules and AKARI would be OK. But I can't guarantee it
for future / not-yet-upstreamed LSM modules.

2018-09-24 17:54:43

by Tetsuo Handa

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 2018/09/25 2:16, Casey Schaufler wrote:
>> Not all of LKM-based LSMs use security blobs. And some of LKM-based LSMs
>> might use security blobs for only a few objects. For example, AKARI uses
>> inode security blob for remembering whether source address/port of an
>> accept()ed socket was already checked, only during accept() operation and
>> first socket operation on the accept()ed socket. Thus, there is no need
>> to waste memory by assigning blobs for all inode objects.
>
> The first question is why use an inode blob? Shouldn't you
> be using a socket blob for this socket based information?

Indeed. AKARI can as well use security_sk_free() using address of
"struct sock" as a key.

>
> If you only want information part of the time you can declare
> a pointer sized blob and manage what hangs off that as you will.
> I personally think that the added complexity of conditional
> blob management is more pain than it's worth, but if you want
> a really big blob, but only on occasion, I could see doing it.

LKM based LSMs are too late for updating blob_sizes.* fields.
Even if they could, they after all have to somehow check whether
corresponding init hook was called. That's checking for NULL.

>>
>>>> @@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
>>>> {
>>>> void *blob;
>>>>
>>>> + call_void_hook(file_free_security, file);
>>>> +
>>>> if (!lsm_file_cache)
>>>> return;
>>>>
>>>> - call_void_hook(file_free_security, file);
>>>> -
>>> Why does this make sense? If the lsm_file_cache isn't
>>> initialized you can't have allocated any file blobs,
>>> no module can have initialized a file blob, hence there
>>> can be nothing for the module to do.
>>>
>> For modules (not limited to LKM-based LSMs) which want to use
>> file blobs for only a few objects and avoid wasting memory by
>> allocating file blobs to all file objects.
>>
>> Infrastructure based blob management fits well for LSM modules
>> which want to assign blobs to all objects (like SELinux). But
>> forcing infrastructure based blob management can become a huge
>> waste of memory for LSM modules which want to assign blobs to
>> only a few objects. Unconditionally calling file_free_security
>> hook (as with other hooks) preserves a room for allowing the
>> latter type of LSM modules without using infrastructure based
>> blob management.
>
> There is a hypothetical issue here, but that would require abuse
> of the infrastructure. Having a file_free_security hook that doesn't
> free a security blob allocated by file_alloc_security may coincidentaly
> be useful, but that's not the intent of the hook.
>

The free hook might be used for freeing resources which were not allocated
by alloc hook. Yama is using task_free hook without task_alloc hook.
Someone might want to use file_free hook without file_alloc hook.


2018-09-24 20:36:18

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On 9/24/2018 10:53 AM, Tetsuo Handa wrote:
> On 2018/09/25 2:16, Casey Schaufler wrote:
>>> Not all of LKM-based LSMs use security blobs. And some of LKM-based LSMs
>>> might use security blobs for only a few objects. For example, AKARI uses
>>> inode security blob for remembering whether source address/port of an
>>> accept()ed socket was already checked, only during accept() operation and
>>> first socket operation on the accept()ed socket. Thus, there is no need
>>> to waste memory by assigning blobs for all inode objects.
>> The first question is why use an inode blob? Shouldn't you
>> be using a socket blob for this socket based information?
> Indeed. AKARI can as well use security_sk_free() using address of
> "struct sock" as a key.
>
>> If you only want information part of the time you can declare
>> a pointer sized blob and manage what hangs off that as you will.
>> I personally think that the added complexity of conditional
>> blob management is more pain than it's worth, but if you want
>> a really big blob, but only on occasion, I could see doing it.
> LKM based LSMs are too late for updating blob_sizes.* fields.

That is true with the code in this patch set. As I mentioned,
changing the blob handling to include a header with real use
information would be required.

> Even if they could, they after all have to somehow check whether
> corresponding init hook was called. That's checking for NULL.

Right.

>>>>> @@ -1202,11 +1183,11 @@ void security_file_free(struct file *file)
>>>>> {
>>>>> void *blob;
>>>>>
>>>>> + call_void_hook(file_free_security, file);
>>>>> +
>>>>> if (!lsm_file_cache)
>>>>> return;
>>>>>
>>>>> - call_void_hook(file_free_security, file);
>>>>> -
>>>> Why does this make sense? If the lsm_file_cache isn't
>>>> initialized you can't have allocated any file blobs,
>>>> no module can have initialized a file blob, hence there
>>>> can be nothing for the module to do.
>>>>
>>> For modules (not limited to LKM-based LSMs) which want to use
>>> file blobs for only a few objects and avoid wasting memory by
>>> allocating file blobs to all file objects.
>>>
>>> Infrastructure based blob management fits well for LSM modules
>>> which want to assign blobs to all objects (like SELinux). But
>>> forcing infrastructure based blob management can become a huge
>>> waste of memory for LSM modules which want to assign blobs to
>>> only a few objects. Unconditionally calling file_free_security
>>> hook (as with other hooks) preserves a room for allowing the
>>> latter type of LSM modules without using infrastructure based
>>> blob management.
>> There is a hypothetical issue here, but that would require abuse
>> of the infrastructure. Having a file_free_security hook that doesn't
>> free a security blob allocated by file_alloc_security may coincidentaly
>> be useful, but that's not the intent of the hook.
>>
> The free hook might be used for freeing resources which were not allocated
> by alloc hook. Yama is using task_free hook without task_alloc hook.
> Someone might want to use file_free hook without file_alloc hook.

OK, you're correct. Checking for an initialized kmem_cache isn't appropriate.


2018-09-26 21:57:44

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH v4 20/19] LSM: Correct file blob free empty blob check

Instead of checking if the kmem_cache for file blobs
has been initialized check if the blob is NULL. This
allows non-blob using modules to do other kinds of
clean up in the security_file_free hooks.

Signed-off-by: Casey Schaufler <[email protected]>
---
security/security.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/security/security.c b/security/security.c
index e7c8506041f1..76f7dc49b63c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1202,14 +1202,13 @@ void security_file_free(struct file *file)
{
void *blob;

- if (!lsm_file_cache)
- return;
-
call_void_hook(file_free_security, file);

blob = file->f_security;
- file->f_security = NULL;
- kmem_cache_free(lsm_file_cache, blob);
+ 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)
--
2.17.1



2018-09-26 21:58:07

by Casey Schaufler

[permalink] [raw]
Subject: [PATCH 21/19] LSM: Cleanup and fixes from Tetsuo Handa

lsm_early_cred()/lsm_early_task() are called from only __init functions.

lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .

lsm_early_inode() should be avoided because it is not appropriate to
call panic() when lsm_early_inode() is called after __init phase.

Since all free hooks are called when one of init hooks failed, each
free hook needs to check whether init hook was called.

The original changes are from Tetsuo Handa. I have made minor
changes in some places, but this is mostly his code.

Signed-off-by: Casey Schaufler <[email protected]>
---
include/linux/lsm_hooks.h | 6 ++----
security/security.c | 27 ++++-----------------------
security/selinux/hooks.c | 5 ++++-
security/selinux/include/objsec.h | 2 ++
security/smack/smack_lsm.c | 8 +++++++-
5 files changed, 19 insertions(+), 29 deletions(-)

diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7e8b32fdf576..80146147531f 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -2095,13 +2095,11 @@ void __init loadpin_add_hooks(void);
static inline void loadpin_add_hooks(void) { };
#endif

-extern int lsm_cred_alloc(struct cred *cred, gfp_t gfp);
extern int lsm_inode_alloc(struct inode *inode);

#ifdef CONFIG_SECURITY
-void lsm_early_cred(struct cred *cred);
-void lsm_early_inode(struct inode *inode);
-void lsm_early_task(struct task_struct *task);
+void __init lsm_early_cred(struct cred *cred);
+void __init lsm_early_task(struct task_struct *task);
#endif

#endif /* ! __LINUX_LSM_HOOKS_H */
diff --git a/security/security.c b/security/security.c
index 76f7dc49b63c..d986045dd4c0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -267,7 +267,7 @@ EXPORT_SYMBOL(unregister_lsm_notifier);
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
{
if (blob_sizes.lbs_cred == 0) {
cred->security = NULL;
@@ -286,7 +286,7 @@ int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
*
* Allocate the cred blob for all the modules if it's not already there
*/
-void lsm_early_cred(struct cred *cred)
+void __init lsm_early_cred(struct cred *cred)
{
int rc;

@@ -344,7 +344,7 @@ void __init security_add_blobs(struct lsm_blob_sizes *needed)
*
* Returns 0, or -ENOMEM if memory can't be allocated.
*/
-int lsm_file_alloc(struct file *file)
+static int lsm_file_alloc(struct file *file)
{
if (!lsm_file_cache) {
file->f_security = NULL;
@@ -378,25 +378,6 @@ int lsm_inode_alloc(struct inode *inode)
return 0;
}

-/**
- * lsm_early_inode - during initialization allocate a composite inode blob
- * @inode: the inode that needs a blob
- *
- * Allocate the inode blob for all the modules if it's not already there
- */
-void lsm_early_inode(struct inode *inode)
-{
- int rc;
-
- if (inode == NULL)
- panic("%s: NULL inode.\n", __func__);
- if (inode->i_security != NULL)
- return;
- rc = lsm_inode_alloc(inode);
- if (rc)
- panic("%s: Early inode alloc failed.\n", __func__);
-}
-
/**
* lsm_task_alloc - allocate a composite task blob
* @task: the task that needs a blob
@@ -466,7 +447,7 @@ int lsm_msg_msg_alloc(struct msg_msg *mp)
*
* Allocate the task blob for all the modules if it's not already there
*/
-void lsm_early_task(struct task_struct *task)
+void __init lsm_early_task(struct task_struct *task)
{
int rc;

diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 44337d2349d9..e54b7dbac775 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -332,8 +332,11 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
static void inode_free_security(struct inode *inode)
{
struct inode_security_struct *isec = selinux_inode(inode);
- struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+ 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
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index ee4471213909..8231ae02560e 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -180,6 +180,8 @@ static inline struct inode_security_struct *selinux_inode(
const struct inode *inode)
{
#ifdef CONFIG_SECURITY_STACKING
+ if (unlikely(!inode->i_security))
+ return NULL;
return inode->i_security + selinux_blob_sizes.lbs_inode;
#else
return inode->i_security;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 784300406b97..b0b40454174b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -750,6 +750,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.
@@ -818,7 +825,6 @@ static int smack_set_mnt_opts(struct super_block *sb,
/*
* Initialize the root inode.
*/
- lsm_early_inode(inode);
init_inode_smack(inode, sp->smk_root);

if (transmute) {
--
2.17.1



2018-09-27 22:15:51

by James Morris

[permalink] [raw]
Subject: Re: [PATCH v4 04/19] SELinux: Remove cred security blob poisoning

On Fri, 21 Sep 2018, Casey Schaufler wrote:

> The SELinux specific credential poisioning only makes sense
> if SELinux is managing the credentials. As the intent of this
> patch set is to move the blob management out of the modules
> and into the infrastructure, the SELinux specific code has
> to go. The poisioning could be introduced into the infrastructure
> at some later date.

If it's useful, it should be incorporated into core LSM, otherwise that's
a regression for SELinux.


--
James Morris
<[email protected]>


2018-09-27 22:32:48

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 04/19] SELinux: Remove cred security blob poisoning

On 9/27/2018 3:13 PM, James Morris wrote:
> On Fri, 21 Sep 2018, Casey Schaufler wrote:
>
>> The SELinux specific credential poisioning only makes sense
>> if SELinux is managing the credentials. As the intent of this
>> patch set is to move the blob management out of the modules
>> and into the infrastructure, the SELinux specific code has
>> to go. The poisioning could be introduced into the infrastructure
>> at some later date.
> If it's useful, it should be incorporated into core LSM, otherwise that's
> a regression for SELinux

When I discussed this code with David Howells he indicated
that it was primarily used for debugging the original shared
credential implementation and that is was not especially
valuable any longer. If someone thinks it is valuable we
should consider doing it in the infrastructure for all the
blobs, not just the credential.


2018-10-01 17:59:43

by James Morris

[permalink] [raw]
Subject: Re: [PATCH v4 00/19] LSM: Module stacking for SARA and Landlock

On Sun, 23 Sep 2018, Casey Schaufler wrote:

> > How do you plan to handle LKM-based LSMs?
>
> My position all along has been that I don't plan to handle LKM
> based LSMs, but that I won't do anything to prevent someone else
> from adding them later. I believe that I've done that. Several
> designs, including a separate list for dynamically loaded modules
> have been proposed. I think some of those would work.

Dynamically loadable LSMs are a bad idea, per several previous
discussions. As a general design concept, kernel security mechanisms
should be invoked during boot, so we can reason about the overall state of
the system at a given point.

In any case, we do not need to take dynamic LSMs into account at this
stage. We don't build infrastructure for non-existent features.





2018-10-01 20:35:11

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH v4 20/19] LSM: Correct file blob free empty blob check

On Wed, Sep 26, 2018 at 2:57 PM, Casey Schaufler <[email protected]> wrote:
> Instead of checking if the kmem_cache for file blobs
> has been initialized check if the blob is NULL. This
> allows non-blob using modules to do other kinds of
> clean up in the security_file_free hooks.
>
> Signed-off-by: Casey Schaufler <[email protected]>

Reviewed-by: Kees Cook <[email protected]>

This looks like it should get folded into "LSM: Infrastructure
management of the file security".

-Kees


> ---
> security/security.c | 9 ++++-----
> 1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/security/security.c b/security/security.c
> index e7c8506041f1..76f7dc49b63c 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -1202,14 +1202,13 @@ void security_file_free(struct file *file)
> {
> void *blob;
>
> - if (!lsm_file_cache)
> - return;
> -
> call_void_hook(file_free_security, file);
>
> blob = file->f_security;
> - file->f_security = NULL;
> - kmem_cache_free(lsm_file_cache, blob);
> + 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)
> --
> 2.17.1
>
>



--
Kees Cook
Pixel Security

2018-10-01 21:49:40

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH 21/19] LSM: Cleanup and fixes from Tetsuo Handa

On Wed, Sep 26, 2018 at 2:57 PM, Casey Schaufler <[email protected]> wrote:
> lsm_early_cred()/lsm_early_task() are called from only __init functions.
>
> lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .
>
> lsm_early_inode() should be avoided because it is not appropriate to
> call panic() when lsm_early_inode() is called after __init phase.
>
> Since all free hooks are called when one of init hooks failed, each
> free hook needs to check whether init hook was called.
>
> The original changes are from Tetsuo Handa. I have made minor
> changes in some places, but this is mostly his code.
>
> Signed-off-by: Casey Schaufler <[email protected]>
> ---
> include/linux/lsm_hooks.h | 6 ++----
> security/security.c | 27 ++++-----------------------
> security/selinux/hooks.c | 5 ++++-
> security/selinux/include/objsec.h | 2 ++
> security/smack/smack_lsm.c | 8 +++++++-
> 5 files changed, 19 insertions(+), 29 deletions(-)

I've split this across the various commits they touch:

Infrastructure management of the cred security blob
LSM: Infrastructure management of the file security
LSM: Infrastructure management of the inode security
LSM: Infrastructure management of the task security
LSM: Blob sharing support for S.A.R.A and LandLock

Based on these changes, I've uploaded the "v4.1", or "Casey is on
vacation", tree here:
https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=lsm/blob-sharing-v4.1

I'm going to work on a merged series for the "arbitrary ordering" and
"blob-sharing" trees next...

-Kees

--
Kees Cook
Pixel Security

2018-10-03 18:14:03

by James Morris

[permalink] [raw]
Subject: Re: [PATCH v4 14/19] LSM: Infrastructure management of the inode security

On Fri, 21 Sep 2018, Kees Cook wrote:

> On Fri, Sep 21, 2018 at 5:19 PM, Casey Schaufler <[email protected]> wrote:

> > + * lsm_early_inode - during initialization allocate a composite inode blob
> > + * @inode: the inode that needs a blob
> > + *
> > + * Allocate the inode blob for all the modules if it's not already there
> > + */
> > +void lsm_early_inode(struct inode *inode)
> > +{
> > + int rc;
> > +
> > + if (inode == NULL)
> > + panic("%s: NULL inode.\n", __func__);
> > + if (inode->i_security != NULL)
> > + return;
> > + rc = lsm_inode_alloc(inode);
> > + if (rc)
> > + panic("%s: Early inode alloc failed.\n", __func__);
> > +}
>
> I'm still advising against using panic(), but I'll leave it up to James.
>

Calling panic() is not appropriate here. Perhaps if it was during
boot-time initialization of LSM infrastructure, but not on the fly.

Use a WARN_ONCE then propagate the error back and fail the operation.


--
James Morris
<[email protected]>


2018-10-04 04:49:51

by Casey Schaufler

[permalink] [raw]
Subject: Re: [PATCH v4 14/19] LSM: Infrastructure management of the inode security

On 10/3/2018 11:13 AM, James Morris wrote:
> On Fri, 21 Sep 2018, Kees Cook wrote:
>
>> On Fri, Sep 21, 2018 at 5:19 PM, Casey Schaufler <[email protected]> wrote:
>>> + * lsm_early_inode - during initialization allocate a composite inode blob
>>> + * @inode: the inode that needs a blob
>>> + *
>>> + * Allocate the inode blob for all the modules if it's not already there
>>> + */
>>> +void lsm_early_inode(struct inode *inode)
>>> +{
>>> + int rc;
>>> +
>>> + if (inode == NULL)
>>> + panic("%s: NULL inode.\n", __func__);
>>> + if (inode->i_security != NULL)
>>> + return;
>>> + rc = lsm_inode_alloc(inode);
>>> + if (rc)
>>> + panic("%s: Early inode alloc failed.\n", __func__);
>>> +}
>> I'm still advising against using panic(), but I'll leave it up to James.
>>
> Calling panic() is not appropriate here. Perhaps if it was during
> boot-time initialization of LSM infrastructure, but not on the fly.

Tetsuo's patch makes this an __init function. It's only for doing
init time stuff like root inode initialization during start-up.
If it fails the caller is going to have to panic. This came straight
out of the SELinux system initialization code. I could go back to
having each LSM do it's own panic, but that seems silly.

>
> Use a WARN_ONCE then propagate the error back and fail the operation.
>
>


2018-10-12 20:09:58

by Kees Cook

[permalink] [raw]
Subject: Re: [PATCH 21/19] LSM: Cleanup and fixes from Tetsuo Handa

On Mon, Oct 1, 2018 at 2:48 PM, Kees Cook <[email protected]> wrote:
> On Wed, Sep 26, 2018 at 2:57 PM, Casey Schaufler <[email protected]> wrote:
>> lsm_early_cred()/lsm_early_task() are called from only __init functions.
>>
>> lsm_cred_alloc()/lsm_file_alloc() are called from only security/security.c .
>>
>> lsm_early_inode() should be avoided because it is not appropriate to
>> call panic() when lsm_early_inode() is called after __init phase.
>>
>> Since all free hooks are called when one of init hooks failed, each
>> free hook needs to check whether init hook was called.
>>
>> The original changes are from Tetsuo Handa. I have made minor
>> changes in some places, but this is mostly his code.
>>
>> Signed-off-by: Casey Schaufler <[email protected]>
>> ---
>> include/linux/lsm_hooks.h | 6 ++----
>> security/security.c | 27 ++++-----------------------
>> security/selinux/hooks.c | 5 ++++-
>> security/selinux/include/objsec.h | 2 ++
>> security/smack/smack_lsm.c | 8 +++++++-
>> 5 files changed, 19 insertions(+), 29 deletions(-)
>
> I've split this across the various commits they touch:
>
> Infrastructure management of the cred security blob
> LSM: Infrastructure management of the file security
> LSM: Infrastructure management of the inode security
> LSM: Infrastructure management of the task security
> LSM: Blob sharing support for S.A.R.A and LandLock
>
> Based on these changes, I've uploaded the "v4.1", or "Casey is on
> vacation", tree here:
> https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=lsm/blob-sharing-v4.1
>
> I'm going to work on a merged series for the "arbitrary ordering" and
> "blob-sharing" trees next...

Here is my v6 (v5 plus small fix I noticed) with my refactoring of
Casey's blob-sharing series on top:

https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=lsm/ordering-v6-blob-sharing

procfs: add smack subdir to attrs
Smack: Abstract use of cred security blob
SELinux: Abstract use of cred security blob
SELinux: Remove cred security blob poisoning
SELinux: Remove unused selinux_is_enabled
AppArmor: Abstract use of cred security blob
TOMOYO: Abstract use of cred security blob
Infrastructure management of the cred security blob
SELinux: Abstract use of file security blob
Smack: Abstract use of file security blob
LSM: Infrastructure management of the file security
SELinux: Abstract use of inode security blob
Smack: Abstract use of inode security blob
LSM: Infrastructure management of the inode security
LSM: Infrastructure management of the task security
SELinux: Abstract use of ipc security blobs
Smack: Abstract use of ipc security blobs
LSM: Infrastructure management of the ipc security blob
TOMOYO: Update LSM flags to no longer be exclusive

Notably, the last patch from Casey's series is entirely removed.
Additionally all the per-LSM initialization changes were removed since
the blob size calculations now stay internal to security.c, done
during the "prepare" phase.

-Kees

--
Kees Cook
Pixel Security