summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/apparmorfs.c2
-rw-r--r--security/apparmor/audit.c2
-rw-r--r--security/apparmor/lsm.c17
-rw-r--r--security/apparmor/path.c66
-rw-r--r--security/capability.c13
-rw-r--r--security/device_cgroup.c7
-rw-r--r--security/inode.c193
-rw-r--r--security/integrity/Kconfig14
-rw-r--r--security/integrity/Makefile1
-rw-r--r--security/integrity/digsig.c48
-rw-r--r--security/integrity/evm/evm.h12
-rw-r--r--security/integrity/evm/evm_crypto.c81
-rw-r--r--security/integrity/evm/evm_main.c94
-rw-r--r--security/integrity/ima/ima_api.c4
-rw-r--r--security/integrity/ima/ima_queue.c17
-rw-r--r--security/integrity/integrity.h21
-rw-r--r--security/keys/encrypted-keys/Makefile8
-rw-r--r--security/keys/encrypted-keys/encrypted.c2
-rw-r--r--security/keys/encrypted-keys/encrypted.h3
-rw-r--r--security/keys/key.c3
-rw-r--r--security/keys/user_defined.c3
-rw-r--r--security/lsm_audit.c7
-rw-r--r--security/security.c19
-rw-r--r--security/selinux/hooks.c21
-rw-r--r--security/selinux/netnode.c2
-rw-r--r--security/selinux/netport.c4
-rw-r--r--security/selinux/selinuxfs.c14
-rw-r--r--security/selinux/ss/conditional.c2
-rw-r--r--security/smack/smack_lsm.c4
-rw-r--r--security/smack/smackfs.c115
-rw-r--r--security/tomoyo/.gitignore2
-rw-r--r--security/tomoyo/audit.c4
-rw-r--r--security/tomoyo/common.h4
-rw-r--r--security/tomoyo/realpath.c22
-rw-r--r--security/tomoyo/securityfs_if.c2
-rw-r--r--security/tomoyo/tomoyo.c15
36 files changed, 473 insertions, 375 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 69ddb47787b..e39df6d4377 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -165,7 +165,7 @@ static void __init aafs_remove(const char *name)
*
* Used aafs_remove to remove entries created with this fn.
*/
-static int __init aafs_create(const char *name, int mask,
+static int __init aafs_create(const char *name, umode_t mask,
const struct file_operations *fops)
{
struct dentry *dentry;
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c
index 96502b22b26..f3fafedd798 100644
--- a/security/apparmor/audit.c
+++ b/security/apparmor/audit.c
@@ -133,7 +133,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
struct aa_profile *profile = sa->aad.profile;
pid_t pid;
rcu_read_lock();
- pid = tsk->real_parent->pid;
+ pid = rcu_dereference(tsk->real_parent)->pid;
rcu_read_unlock();
audit_log_format(ab, " parent=%d", pid);
if (profile->ns != root_ns) {
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 37832026e58..d7f06f8b283 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -262,7 +262,7 @@ static int apparmor_path_unlink(struct path *dir, struct dentry *dentry)
}
static int apparmor_path_mkdir(struct path *dir, struct dentry *dentry,
- int mode)
+ umode_t mode)
{
return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
S_IFDIR);
@@ -274,7 +274,7 @@ static int apparmor_path_rmdir(struct path *dir, struct dentry *dentry)
}
static int apparmor_path_mknod(struct path *dir, struct dentry *dentry,
- int mode, unsigned int dev)
+ umode_t mode, unsigned int dev)
{
return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode);
}
@@ -344,13 +344,12 @@ static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry,
return error;
}
-static int apparmor_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
- mode_t mode)
+static int apparmor_path_chmod(struct path *path, umode_t mode)
{
- if (!mediated_filesystem(dentry->d_inode))
+ if (!mediated_filesystem(path->dentry->d_inode))
return 0;
- return common_perm_mnt_dentry(OP_CHMOD, mnt, dentry, AA_MAY_CHMOD);
+ return common_perm_mnt_dentry(OP_CHMOD, path->mnt, path->dentry, AA_MAY_CHMOD);
}
static int apparmor_path_chown(struct path *path, uid_t uid, gid_t gid)
@@ -671,7 +670,7 @@ static struct security_operations apparmor_ops = {
static int param_set_aabool(const char *val, const struct kernel_param *kp);
static int param_get_aabool(char *buffer, const struct kernel_param *kp);
-#define param_check_aabool(name, p) __param_check(name, p, int)
+#define param_check_aabool param_check_bool
static struct kernel_param_ops param_ops_aabool = {
.set = param_set_aabool,
.get = param_get_aabool
@@ -679,7 +678,7 @@ static struct kernel_param_ops param_ops_aabool = {
static int param_set_aauint(const char *val, const struct kernel_param *kp);
static int param_get_aauint(char *buffer, const struct kernel_param *kp);
-#define param_check_aauint(name, p) __param_check(name, p, int)
+#define param_check_aauint param_check_uint
static struct kernel_param_ops param_ops_aauint = {
.set = param_set_aauint,
.get = param_get_aauint
@@ -687,7 +686,7 @@ static struct kernel_param_ops param_ops_aauint = {
static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
-#define param_check_aalockpolicy(name, p) __param_check(name, p, int)
+#define param_check_aalockpolicy param_check_bool
static struct kernel_param_ops param_ops_aalockpolicy = {
.set = param_set_aalockpolicy,
.get = param_get_aalockpolicy
diff --git a/security/apparmor/path.c b/security/apparmor/path.c
index 36cc0cc39e7..9d070a7c3ff 100644
--- a/security/apparmor/path.c
+++ b/security/apparmor/path.c
@@ -13,7 +13,6 @@
*/
#include <linux/magic.h>
-#include <linux/mnt_namespace.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/nsproxy.h>
@@ -57,23 +56,44 @@ static int prepend(char **buffer, int buflen, const char *str, int namelen)
static int d_namespace_path(struct path *path, char *buf, int buflen,
char **name, int flags)
{
- struct path root, tmp;
char *res;
- int connected, error = 0;
+ int error = 0;
+ int connected = 1;
+
+ if (path->mnt->mnt_flags & MNT_INTERNAL) {
+ /* it's not mounted anywhere */
+ res = dentry_path(path->dentry, buf, buflen);
+ *name = res;
+ if (IS_ERR(res)) {
+ *name = buf;
+ return PTR_ERR(res);
+ }
+ if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
+ strncmp(*name, "/sys/", 5) == 0) {
+ /* TODO: convert over to using a per namespace
+ * control instead of hard coded /proc
+ */
+ return prepend(name, *name - buf, "/proc", 5);
+ }
+ return 0;
+ }
- /* Get the root we want to resolve too, released below */
+ /* resolve paths relative to chroot?*/
if (flags & PATH_CHROOT_REL) {
- /* resolve paths relative to chroot */
+ struct path root;
get_fs_root(current->fs, &root);
- } else {
- /* resolve paths relative to namespace */
- root.mnt = current->nsproxy->mnt_ns->root;
- root.dentry = root.mnt->mnt_root;
- path_get(&root);
+ res = __d_path(path, &root, buf, buflen);
+ if (res && !IS_ERR(res)) {
+ /* everything's fine */
+ *name = res;
+ path_put(&root);
+ goto ok;
+ }
+ path_put(&root);
+ connected = 0;
}
- tmp = root;
- res = __d_path(path, &tmp, buf, buflen);
+ res = d_absolute_path(path, buf, buflen);
*name = res;
/* handle error conditions - and still allow a partial path to
@@ -84,7 +104,10 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
*name = buf;
goto out;
}
+ if (!our_mnt(path->mnt))
+ connected = 0;
+ok:
/* Handle two cases:
* 1. A deleted dentry && profile is not allowing mediation of deleted
* 2. On some filesystems, newly allocated dentries appear to the
@@ -97,10 +120,7 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
goto out;
}
- /* Determine if the path is connected to the expected root */
- connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt;
-
- /* If the path is not connected,
+ /* If the path is not connected to the expected root,
* check if it is a sysctl and handle specially else remove any
* leading / that __d_path may have returned.
* Unless
@@ -112,17 +132,9 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
* namespace root.
*/
if (!connected) {
- /* is the disconnect path a sysctl? */
- if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC &&
- strncmp(*name, "/sys/", 5) == 0) {
- /* TODO: convert over to using a per namespace
- * control instead of hard coded /proc
- */
- error = prepend(name, *name - buf, "/proc", 5);
- } else if (!(flags & PATH_CONNECT_PATH) &&
+ if (!(flags & PATH_CONNECT_PATH) &&
!(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
- (tmp.mnt == current->nsproxy->mnt_ns->root &&
- tmp.dentry == tmp.mnt->mnt_root))) {
+ our_mnt(path->mnt))) {
/* disconnected path, don't return pathname starting
* with '/'
*/
@@ -133,8 +145,6 @@ static int d_namespace_path(struct path *path, char *buf, int buflen,
}
out:
- path_put(&root);
-
return error;
}
diff --git a/security/capability.c b/security/capability.c
index 2984ea4f776..3b5883b7179 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -125,7 +125,7 @@ static int cap_inode_init_security(struct inode *inode, struct inode *dir,
}
static int cap_inode_create(struct inode *inode, struct dentry *dentry,
- int mask)
+ umode_t mask)
{
return 0;
}
@@ -148,7 +148,7 @@ static int cap_inode_symlink(struct inode *inode, struct dentry *dentry,
}
static int cap_inode_mkdir(struct inode *inode, struct dentry *dentry,
- int mask)
+ umode_t mask)
{
return 0;
}
@@ -159,7 +159,7 @@ static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry)
}
static int cap_inode_mknod(struct inode *inode, struct dentry *dentry,
- int mode, dev_t dev)
+ umode_t mode, dev_t dev)
{
return 0;
}
@@ -235,13 +235,13 @@ static void cap_inode_getsecid(const struct inode *inode, u32 *secid)
}
#ifdef CONFIG_SECURITY_PATH
-static int cap_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+static int cap_path_mknod(struct path *dir, struct dentry *dentry, umode_t mode,
unsigned int dev)
{
return 0;
}
-static int cap_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
+static int cap_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode)
{
return 0;
}
@@ -279,8 +279,7 @@ static int cap_path_truncate(struct path *path)
return 0;
}
-static int cap_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
- mode_t mode)
+static int cap_path_chmod(struct path *path, umode_t mode)
{
return 0;
}
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
index 4450fbeec41..8b5b5d8612c 100644
--- a/security/device_cgroup.c
+++ b/security/device_cgroup.c
@@ -62,11 +62,12 @@ static inline struct dev_cgroup *task_devcgroup(struct task_struct *task)
struct cgroup_subsys devices_subsys;
static int devcgroup_can_attach(struct cgroup_subsys *ss,
- struct cgroup *new_cgroup, struct task_struct *task)
+ struct cgroup *new_cgrp, struct cgroup_taskset *set)
{
- if (current != task && !capable(CAP_SYS_ADMIN))
- return -EPERM;
+ struct task_struct *task = cgroup_taskset_first(set);
+ if (current != task && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
return 0;
}
diff --git a/security/inode.c b/security/inode.c
index c4df2fbebe6..43ce6e19015 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -25,100 +25,6 @@
static struct vfsmount *mount;
static int mount_count;
-/*
- * TODO:
- * I think I can get rid of these default_file_ops, but not quite sure...
- */
-static ssize_t default_read_file(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- return 0;
-}
-
-static ssize_t default_write_file(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- return count;
-}
-
-static int default_open(struct inode *inode, struct file *file)
-{
- if (inode->i_private)
- file->private_data = inode->i_private;
-
- return 0;
-}
-
-static const struct file_operations default_file_ops = {
- .read = default_read_file,
- .write = default_write_file,
- .open = default_open,
- .llseek = noop_llseek,
-};
-
-static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)
-{
- struct inode *inode = new_inode(sb);
-
- if (inode) {
- inode->i_ino = get_next_ino();
- inode->i_mode = mode;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- switch (mode & S_IFMT) {
- default:
- init_special_inode(inode, mode, dev);
- break;
- case S_IFREG:
- inode->i_fop = &default_file_ops;
- break;
- case S_IFDIR:
- inode->i_op = &simple_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
-
- /* directory inodes start off with i_nlink == 2 (for "." entry) */
- inc_nlink(inode);
- break;
- }
- }
- return inode;
-}
-
-/* SMP-safe */
-static int mknod(struct inode *dir, struct dentry *dentry,
- int mode, dev_t dev)
-{
- struct inode *inode;
- int error = -ENOMEM;
-
- if (dentry->d_inode)
- return -EEXIST;
-
- inode = get_inode(dir->i_sb, mode, dev);
- if (inode) {
- d_instantiate(dentry, inode);
- dget(dentry);
- error = 0;
- }
- return error;
-}
-
-static int mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
- int res;
-
- mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
- res = mknod(dir, dentry, mode, 0);
- if (!res)
- inc_nlink(dir);
- return res;
-}
-
-static int create(struct inode *dir, struct dentry *dentry, int mode)
-{
- mode = (mode & S_IALLUGO) | S_IFREG;
- return mknod(dir, dentry, mode, 0);
-}
-
static inline int positive(struct dentry *dentry)
{
return dentry->d_inode && !d_unhashed(dentry);
@@ -145,38 +51,6 @@ static struct file_system_type fs_type = {
.kill_sb = kill_litter_super,
};
-static int create_by_name(const char *name, mode_t mode,
- struct dentry *parent,
- struct dentry **dentry)
-{
- int error = 0;
-
- *dentry = NULL;
-
- /* If the parent is not specified, we create it in the root.
- * We need the root dentry to do this, which is in the super
- * block. A pointer to that is in the struct vfsmount that we
- * have around.
- */
- if (!parent)
- parent = mount->mnt_sb->s_root;
-
- mutex_lock(&parent->d_inode->i_mutex);
- *dentry = lookup_one_len(name, parent, strlen(name));
- if (!IS_ERR(*dentry)) {
- if ((mode & S_IFMT) == S_IFDIR)
- error = mkdir(parent->d_inode, *dentry, mode);
- else
- error = create(parent->d_inode, *dentry, mode);
- if (error)
- dput(*dentry);
- } else
- error = PTR_ERR(*dentry);
- mutex_unlock(&parent->d_inode->i_mutex);
-
- return error;
-}
-
/**
* securityfs_create_file - create a file in the securityfs filesystem
*
@@ -205,35 +79,70 @@ static int create_by_name(const char *name, mode_t mode,
* If securityfs is not enabled in the kernel, the value %-ENODEV is
* returned.
*/
-struct dentry *securityfs_create_file(const char *name, mode_t mode,
+struct dentry *securityfs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops)
{
- struct dentry *dentry = NULL;
+ struct dentry *dentry;
+ int is_dir = S_ISDIR(mode);
+ struct inode *dir, *inode;
int error;
+ if (!is_dir) {
+ BUG_ON(!fops);
+ mode = (mode & S_IALLUGO) | S_IFREG;
+ }
+
pr_debug("securityfs: creating file '%s'\n",name);
error = simple_pin_fs(&fs_type, &mount, &mount_count);
- if (error) {
- dentry = ERR_PTR(error);
- goto exit;
+ if (error)
+ return ERR_PTR(error);
+
+ if (!parent)
+ parent = mount->mnt_root;
+
+ dir = parent->d_inode;
+
+ mutex_lock(&dir->i_mutex);
+ dentry = lookup_one_len(name, parent, strlen(name));
+ if (IS_ERR(dentry))
+ goto out;
+
+ if (dentry->d_inode) {
+ error = -EEXIST;
+ goto out1;
}
- error = create_by_name(name, mode, parent, &dentry);
- if (error) {
- dentry = ERR_PTR(error);
- simple_release_fs(&mount, &mount_count);
- goto exit;
+ inode = new_inode(dir->i_sb);
+ if (!inode) {
+ error = -ENOMEM;
+ goto out1;
}
- if (dentry->d_inode) {
- if (fops)
- dentry->d_inode->i_fop = fops;
- if (data)
- dentry->d_inode->i_private = data;
+ inode->i_ino = get_next_ino();
+ inode->i_mode = mode;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_private = data;
+ if (is_dir) {
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ inc_nlink(inode);
+ inc_nlink(dir);
+ } else {
+ inode->i_fop = fops;
}
-exit:
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ mutex_unlock(&dir->i_mutex);
+ return dentry;
+
+out1:
+ dput(dentry);
+ dentry = ERR_PTR(error);
+out:
+ mutex_unlock(&dir->i_mutex);
+ simple_release_fs(&mount, &mount_count);
return dentry;
}
EXPORT_SYMBOL_GPL(securityfs_create_file);
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 4bf00acf793..d384ea92148 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -3,5 +3,19 @@ config INTEGRITY
def_bool y
depends on IMA || EVM
+config INTEGRITY_DIGSIG
+ boolean "Digital signature verification using multiple keyrings"
+ depends on INTEGRITY && KEYS
+ default n
+ select DIGSIG
+ help
+ This option enables digital signature verification support
+ using multiple keyrings. It defines separate keyrings for each
+ of the different use cases - evm, ima, and modules.
+ Different keyrings improves search performance, but also allow
+ to "lock" certain keyring to prevent adding new keys.
+ This is useful for evm and module keyrings, when keys are
+ usually only added from initramfs.
+
source security/integrity/ima/Kconfig
source security/integrity/evm/Kconfig
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index 0ae44aea651..bece0563ee5 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -3,6 +3,7 @@
#
obj-$(CONFIG_INTEGRITY) += integrity.o
+obj-$(CONFIG_INTEGRITY_DIGSIG) += digsig.o
integrity-y := iint.o
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
new file mode 100644
index 00000000000..2dc167d7cde
--- /dev/null
+++ b/security/integrity/digsig.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 Intel Corporation
+ *
+ * Author:
+ * Dmitry Kasatkin <dmitry.kasatkin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/err.h>
+#include <linux/rbtree.h>
+#include <linux/key-type.h>
+#include <linux/digsig.h>
+
+#include "integrity.h"
+
+static struct key *keyring[INTEGRITY_KEYRING_MAX];
+
+static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
+ "_evm",
+ "_module",
+ "_ima",
+};
+
+int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
+ const char *digest, int digestlen)
+{
+ if (id >= INTEGRITY_KEYRING_MAX)
+ return -EINVAL;
+
+ if (!keyring[id]) {
+ keyring[id] =
+ request_key(&key_type_keyring, keyring_name[id], NULL);
+ if (IS_ERR(keyring[id])) {
+ int err = PTR_ERR(keyring[id]);
+ pr_err("no %s keyring: %d\n", keyring_name[id], err);
+ keyring[id] = NULL;
+ return err;
+ }
+ }
+
+ return digsig_verify(keyring[id], sig, siglen, digest, digestlen);
+}
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h
index d320f519743..c885247ebcf 100644
--- a/security/integrity/evm/evm.h
+++ b/security/integrity/evm/evm.h
@@ -12,14 +12,21 @@
* File: evm.h
*
*/
+
+#ifndef __INTEGRITY_EVM_H
+#define __INTEGRITY_EVM_H
+
#include <linux/xattr.h>
#include <linux/security.h>
+
#include "../integrity.h"
extern int evm_initialized;
extern char *evm_hmac;
+extern char *evm_hash;
extern struct crypto_shash *hmac_tfm;
+extern struct crypto_shash *hash_tfm;
/* List of EVM protected security xattrs */
extern char *evm_config_xattrnames[];
@@ -32,7 +39,12 @@ extern int evm_update_evmxattr(struct dentry *dentry,
extern int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char *digest);
+extern int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
+ const char *req_xattr_value,
+ size_t req_xattr_value_len, char *digest);
extern int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
char *hmac_val);
extern int evm_init_secfs(void);
extern void evm_cleanup_secfs(void);
+
+#endif
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 5dd5b140242..49a464f5595 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -26,36 +26,59 @@ static unsigned char evmkey[MAX_KEY_SIZE];
static int evmkey_len = MAX_KEY_SIZE;
struct crypto_shash *hmac_tfm;
+struct crypto_shash *hash_tfm;
-static struct shash_desc *init_desc(void)
+static DEFINE_MUTEX(mutex);
+
+static struct shash_desc *init_desc(char type)
{
- int rc;
+ long rc;
+ char *algo;
+ struct crypto_shash **tfm;
struct shash_desc *desc;
- if (hmac_tfm == NULL) {
- hmac_tfm = crypto_alloc_shash(evm_hmac, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(hmac_tfm)) {
- pr_err("Can not allocate %s (reason: %ld)\n",
- evm_hmac, PTR_ERR(hmac_tfm));
- rc = PTR_ERR(hmac_tfm);
- hmac_tfm = NULL;
+ if (type == EVM_XATTR_HMAC) {
+ tfm = &hmac_tfm;
+ algo = evm_hmac;
+ } else {
+ tfm = &hash_tfm;
+ algo = evm_hash;
+ }
+
+ if (*tfm == NULL) {
+ mutex_lock(&mutex);
+ if (*tfm)
+ goto out;
+ *tfm = crypto_alloc_shash(algo, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(*tfm)) {
+ rc = PTR_ERR(*tfm);
+ pr_err("Can not allocate %s (reason: %ld)\n", algo, rc);
+ *tfm = NULL;
+ mutex_unlock(&mutex);
return ERR_PTR(rc);
}
+ if (type == EVM_XATTR_HMAC) {
+ rc = crypto_shash_setkey(*tfm, evmkey, evmkey_len);
+ if (rc) {
+ crypto_free_shash(*tfm);
+ *tfm = NULL;
+ mutex_unlock(&mutex);
+ return ERR_PTR(rc);
+ }
+ }
+out:
+ mutex_unlock(&mutex);
}
- desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(hmac_tfm),
+ desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
GFP_KERNEL);
if (!desc)
return ERR_PTR(-ENOMEM);
- desc->tfm = hmac_tfm;
+ desc->tfm = *tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- rc = crypto_shash_setkey(hmac_tfm, evmkey, evmkey_len);
- if (rc)
- goto out;
rc = crypto_shash_init(desc);
-out:
if (rc) {
kfree(desc);
return ERR_PTR(rc);
@@ -97,9 +120,11 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,
* the hmac using the requested xattr value. Don't alloc/free memory for
* each xattr, but attempt to re-use the previously allocated memory.
*/
-int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
- const char *req_xattr_value, size_t req_xattr_value_len,
- char *digest)
+static int evm_calc_hmac_or_hash(struct dentry *dentry,
+ const char *req_xattr_name,
+ const char *req_xattr_value,
+ size_t req_xattr_value_len,
+ char type, char *digest)
{
struct inode *inode = dentry->d_inode;
struct shash_desc *desc;
@@ -111,7 +136,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
if (!inode->i_op || !inode->i_op->getxattr)
return -EOPNOTSUPP;
- desc = init_desc();
+ desc = init_desc(type);
if (IS_ERR(desc))
return PTR_ERR(desc);
@@ -145,6 +170,22 @@ out:
return error;
}
+int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,
+ const char *req_xattr_value, size_t req_xattr_value_len,
+ char *digest)
+{
+ return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
+ req_xattr_value_len, EVM_XATTR_HMAC, digest);
+}
+
+int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
+ const char *req_xattr_value, size_t req_xattr_value_len,
+ char *digest)
+{
+ return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value,
+ req_xattr_value_len, IMA_XATTR_DIGEST, digest);
+}
+
/*
* Calculate the hmac and update security.evm xattr
*
@@ -175,7 +216,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
{
struct shash_desc *desc;
- desc = init_desc();
+ desc = init_desc(EVM_XATTR_HMAC);
if (IS_ERR(desc)) {
printk(KERN_INFO "init_desc failed\n");
return PTR_ERR(desc);
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index 92d3d99a9f7..8901501425f 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -25,6 +25,7 @@
int evm_initialized;
char *evm_hmac = "hmac(sha1)";
+char *evm_hash = "sha1";
char *evm_config_xattrnames[] = {
#ifdef CONFIG_SECURITY_SELINUX
@@ -46,6 +47,29 @@ static int __init evm_set_fixmode(char *str)
}
__setup("evm=", evm_set_fixmode);
+static int evm_find_protected_xattrs(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ char **xattr;
+ int error;
+ int count = 0;
+
+ if (!inode->i_op || !inode->i_op->getxattr)
+ return -EOPNOTSUPP;
+
+ for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
+ error = inode->i_op->getxattr(dentry, *xattr, NULL, 0);
+ if (error < 0) {
+ if (error == -ENODATA)
+ continue;
+ return error;
+ }
+ count++;
+ }
+
+ return count;
+}
+
/*
* evm_verify_hmac - calculate and compare the HMAC with the EVM xattr
*
@@ -65,32 +89,72 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
size_t xattr_value_len,
struct integrity_iint_cache *iint)
{
- struct evm_ima_xattr_data xattr_data;
+ struct evm_ima_xattr_data *xattr_data = NULL;
+ struct evm_ima_xattr_data calc;
enum integrity_status evm_status = INTEGRITY_PASS;
- int rc;
+ int rc, xattr_len;
if (iint && iint->evm_status == INTEGRITY_PASS)
return iint->evm_status;
/* if status is not PASS, try to check again - against -ENOMEM */
- rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
- xattr_value_len, xattr_data.digest);
- if (rc < 0) {
- evm_status = (rc == -ENODATA)
- ? INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
+ /* first need to know the sig type */
+ rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0,
+ GFP_NOFS);
+ if (rc <= 0) {
+ if (rc == 0)
+ evm_status = INTEGRITY_FAIL; /* empty */
+ else if (rc == -ENODATA) {
+ rc = evm_find_protected_xattrs(dentry);
+ if (rc > 0)
+ evm_status = INTEGRITY_NOLABEL;
+ else if (rc == 0)
+ evm_status = INTEGRITY_NOXATTRS; /* new file */
+ }
goto out;
}
- xattr_data.type = EVM_XATTR_HMAC;
- rc = vfs_xattr_cmp(dentry, XATTR_NAME_EVM, (u8 *)&xattr_data,
- sizeof xattr_data, GFP_NOFS);
- if (rc < 0)
- evm_status = (rc == -ENODATA)
- ? INTEGRITY_NOLABEL : INTEGRITY_FAIL;
+ xattr_len = rc - 1;
+
+ /* check value type */
+ switch (xattr_data->type) {
+ case EVM_XATTR_HMAC:
+ rc = evm_calc_hmac(dentry, xattr_name, xattr_value,
+ xattr_value_len, calc.digest);
+ if (rc)
+ break;
+ rc = memcmp(xattr_data->digest, calc.digest,
+ sizeof(calc.digest));
+ if (rc)
+ rc = -EINVAL;
+ break;
+ case EVM_IMA_XATTR_DIGSIG:
+ rc = evm_calc_hash(dentry, xattr_name, xattr_value,
+ xattr_value_len, calc.digest);
+ if (rc)
+ break;
+ rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,
+ xattr_data->digest, xattr_len,
+ calc.digest, sizeof(calc.digest));
+ if (!rc) {
+ /* we probably want to replace rsa with hmac here */
+ evm_update_evmxattr(dentry, xattr_name, xattr_value,
+ xattr_value_len);
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ if (rc)
+ evm_status = (rc == -ENODATA) ?
+ INTEGRITY_NOXATTRS : INTEGRITY_FAIL;
out:
if (iint)
iint->evm_status = evm_status;
+ kfree(xattr_data);
return evm_status;
}
@@ -354,6 +418,8 @@ static int __init init_evm(void)
printk(KERN_INFO "EVM: Error registering secfs\n");
goto err;
}
+
+ return 0;
err:
return error;
}
@@ -363,6 +429,8 @@ static void __exit cleanup_evm(void)
evm_cleanup_secfs();
if (hmac_tfm)
crypto_free_shash(hmac_tfm);
+ if (hash_tfm)
+ crypto_free_shash(hash_tfm);
}
/*
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 0d50df04ccc..88a2788b981 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -178,8 +178,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX);
result = ima_store_template(entry, violation, inode);
- if (!result)
+ if (!result || result == -EEXIST)
iint->flags |= IMA_MEASURED;
- else
+ if (result < 0)
kfree(entry);
}
diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c
index 8e28f04a5e2..55a6271bce7 100644
--- a/security/integrity/ima/ima_queue.c
+++ b/security/integrity/ima/ima_queue.c
@@ -23,6 +23,8 @@
#include <linux/slab.h>
#include "ima.h"
+#define AUDIT_CAUSE_LEN_MAX 32
+
LIST_HEAD(ima_measurements); /* list of all measurements */
/* key: inode (before secure-hashing a file) */
@@ -94,7 +96,8 @@ static int ima_pcr_extend(const u8 *hash)
result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash);
if (result != 0)
- pr_err("IMA: Error Communicating to TPM chip\n");
+ pr_err("IMA: Error Communicating to TPM chip, result: %d\n",
+ result);
return result;
}
@@ -106,14 +109,16 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
{
u8 digest[IMA_DIGEST_SIZE];
const char *audit_cause = "hash_added";
+ char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX];
int audit_info = 1;
- int result = 0;
+ int result = 0, tpmresult = 0;
mutex_lock(&ima_extend_list_mutex);
if (!violation) {
memcpy(digest, entry->digest, sizeof digest);
if (ima_lookup_digest_entry(digest)) {
audit_cause = "hash_exists";
+ result = -EEXIST;
goto out;
}
}
@@ -128,9 +133,11 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation,
if (violation) /* invalidate pcr */
memset(digest, 0xff, sizeof digest);
- result = ima_pcr_extend(digest);
- if (result != 0) {
- audit_cause = "TPM error";
+ tpmresult = ima_pcr_extend(digest);
+ if (tpmresult != 0) {
+ snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)",
+ tpmresult);
+ audit_cause = tpm_audit_cause;
audit_info = 0;
}
out:
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 3143a3c3986..4da6ba81d15 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -46,5 +46,26 @@ struct integrity_iint_cache {
struct integrity_iint_cache *integrity_iint_insert(struct inode *inode);
struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
+#define INTEGRITY_KEYRING_EVM 0
+#define INTEGRITY_KEYRING_MODULE 1
+#define INTEGRITY_KEYRING_IMA 2
+#define INTEGRITY_KEYRING_MAX 3
+
+#ifdef CONFIG_INTEGRITY_DIGSIG
+
+int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
+ const char *digest, int digestlen);
+
+#else
+
+static inline int integrity_digsig_verify(const unsigned int id,
+ const char *sig, int siglen,
+ const char *digest, int digestlen)
+{
+ return -EOPNOTSUPP;
+}
+
+#endif /* CONFIG_INTEGRITY_DIGSIG */
+
/* set during initialization */
extern int iint_initialized;
diff --git a/security/keys/encrypted-keys/Makefile b/security/keys/encrypted-keys/Makefile
index 6bc7a86d102..d6f8433250a 100644
--- a/security/keys/encrypted-keys/Makefile
+++ b/security/keys/encrypted-keys/Makefile
@@ -2,5 +2,9 @@
# Makefile for encrypted keys
#
-obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted.o ecryptfs_format.o
-obj-$(CONFIG_TRUSTED_KEYS) += masterkey_trusted.o
+obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys.o
+
+encrypted-keys-y := encrypted.o ecryptfs_format.o
+masterkey-$(CONFIG_TRUSTED_KEYS) := masterkey_trusted.o
+masterkey-$(CONFIG_TRUSTED_KEYS)-$(CONFIG_ENCRYPTED_KEYS) := masterkey_trusted.o
+encrypted-keys-y += $(masterkey-y) $(masterkey-m-m)
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index dcc843cb0f8..41144f71d61 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -444,7 +444,7 @@ static struct key *request_master_key(struct encrypted_key_payload *epayload,
goto out;
if (IS_ERR(mkey)) {
- int ret = PTR_ERR(epayload);
+ int ret = PTR_ERR(mkey);
if (ret == -ENOTSUPP)
pr_info("encrypted_key: key %s not supported",
diff --git a/security/keys/encrypted-keys/encrypted.h b/security/keys/encrypted-keys/encrypted.h
index b6ade894525..8136a2d44c6 100644
--- a/security/keys/encrypted-keys/encrypted.h
+++ b/security/keys/encrypted-keys/encrypted.h
@@ -2,7 +2,8 @@
#define __ENCRYPTED_KEY_H
#define ENCRYPTED_DEBUG 0
-#ifdef CONFIG_TRUSTED_KEYS
+#if defined(CONFIG_TRUSTED_KEYS) || \
+ (defined(CONFIG_TRUSTED_KEYS_MODULE) && defined(CONFIG_ENCRYPTED_KEYS_MODULE))
extern struct key *request_trusted_key(const char *trusted_desc,
u8 **master_key, size_t *master_keylen);
#else
diff --git a/security/keys/key.c b/security/keys/key.c
index 4414abddcb5..4f64c7267af 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -291,6 +291,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
atomic_set(&key->usage, 1);
init_rwsem(&key->sem);
+ lockdep_set_class(&key->sem, &type->lock_class);
key->type = type;
key->user = user;
key->quotalen = quotalen;
@@ -946,6 +947,8 @@ int register_key_type(struct key_type *ktype)
struct key_type *p;
int ret;
+ memset(&ktype->lock_class, 0, sizeof(ktype->lock_class));
+
ret = -EEXIST;
down_write(&key_types_sem);
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 5b366d7af3c..69ff52c08e9 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -102,7 +102,8 @@ int user_update(struct key *key, const void *data, size_t datalen)
key->expiry = 0;
}
- kfree_rcu(zap, rcu);
+ if (zap)
+ kfree_rcu(zap, rcu);
error:
return ret;
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 893af8a2fa1..7bd6f138236 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -114,19 +114,20 @@ int ipv6_skb_to_auditdata(struct sk_buff *skb,
int offset, ret = 0;
struct ipv6hdr *ip6;
u8 nexthdr;
+ __be16 frag_off;
ip6 = ipv6_hdr(skb);
if (ip6 == NULL)
return -EINVAL;
- ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
- ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+ ad->u.net.v6info.saddr = ip6->saddr;
+ ad->u.net.v6info.daddr = ip6->daddr;
ret = 0;
/* IPv6 can have several extension header before the Transport header
* skip them */
offset = skb_network_offset(skb);
offset += sizeof(*ip6);
nexthdr = ip6->nexthdr;
- offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
+ offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
if (offset < 0)
return 0;
if (proto)
diff --git a/security/security.c b/security/security.c
index 0c6cc69c8f8..214502c772a 100644
--- a/security/security.c
+++ b/security/security.c
@@ -381,14 +381,14 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir,
void **value, size_t *len)
{
if (unlikely(IS_PRIVATE(inode)))
- return 0;
+ return -EOPNOTSUPP;
return security_ops->inode_init_security(inode, dir, qstr, name, value,
len);
}
EXPORT_SYMBOL(security_old_inode_init_security);
#ifdef CONFIG_SECURITY_PATH
-int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
+int security_path_mknod(struct path *dir, struct dentry *dentry, umode_t mode,
unsigned int dev)
{
if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
@@ -397,7 +397,7 @@ int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
}
EXPORT_SYMBOL(security_path_mknod);
-int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode)
+int security_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
return 0;
@@ -454,12 +454,11 @@ int security_path_truncate(struct path *path)
return security_ops->path_truncate(path);
}
-int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
- mode_t mode)
+int security_path_chmod(struct path *path, umode_t mode)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
return 0;
- return security_ops->path_chmod(dentry, mnt, mode);
+ return security_ops->path_chmod(path, mode);
}
int security_path_chown(struct path *path, uid_t uid, gid_t gid)
@@ -475,7 +474,7 @@ int security_path_chroot(struct path *path)
}
#endif
-int security_inode_create(struct inode *dir, struct dentry *dentry, int mode)
+int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
@@ -506,7 +505,7 @@ int security_inode_symlink(struct inode *dir, struct dentry *dentry,
return security_ops->inode_symlink(dir, dentry, old_name);
}
-int security_inode_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
@@ -521,7 +520,7 @@ int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
return security_ops->inode_rmdir(dir, dentry);
}
-int security_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 1126c10a5e8..7cd4c3affac 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1090,7 +1090,7 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_NETLINK_ROUTE_SOCKET;
case NETLINK_FIREWALL:
return SECCLASS_NETLINK_FIREWALL_SOCKET;
- case NETLINK_INET_DIAG:
+ case NETLINK_SOCK_DIAG:
return SECCLASS_NETLINK_TCPDIAG_SOCKET;
case NETLINK_NFLOG:
return SECCLASS_NETLINK_NFLOG_SOCKET;
@@ -1740,7 +1740,7 @@ static inline u32 file_mask_to_av(int mode, int mask)
{
u32 av = 0;
- if ((mode & S_IFMT) != S_IFDIR) {
+ if (!S_ISDIR(mode)) {
if (mask & MAY_EXEC)
av |= FILE__EXECUTE;
if (mask & MAY_READ)
@@ -2507,7 +2507,7 @@ static int selinux_mount(char *dev_name,
const struct cred *cred = current_cred();
if (flags & MS_REMOUNT)
- return superblock_has_perm(cred, path->mnt->mnt_sb,
+ return superblock_has_perm(cred, path->dentry->d_sb,
FILESYSTEM__REMOUNT, NULL);
else
return path_has_perm(cred, path, FILE__MOUNTON);
@@ -2598,7 +2598,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
return 0;
}
-static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
return may_create(dir, dentry, SECCLASS_FILE);
}
@@ -2618,7 +2618,7 @@ static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const
return may_create(dir, dentry, SECCLASS_LNK_FILE);
}
-static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
+static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
{
return may_create(dir, dentry, SECCLASS_DIR);
}
@@ -2628,7 +2628,7 @@ static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
return may_link(dir, dentry, MAY_RMDIR);
}
-static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
return may_create(dir, dentry, inode_mode_to_security_class(mode));
}
@@ -3561,19 +3561,20 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb,
u8 nexthdr;
int ret = -EINVAL, offset;
struct ipv6hdr _ipv6h, *ip6;
+ __be16 frag_off;
offset = skb_network_offset(skb);
ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
if (ip6 == NULL)
goto out;
- ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
- ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
+ ad->u.net.v6info.saddr = ip6->saddr;
+ ad->u.net.v6info.daddr = ip6->daddr;
ret = 0;
nexthdr = ip6->nexthdr;
offset += sizeof(_ipv6h);
- offset = ipv6_skip_exthdr(skb, offset, &nexthdr);
+ offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
if (offset < 0)
goto out;
@@ -3871,7 +3872,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
if (family == PF_INET)
ad.u.net.v4info.saddr = addr4->sin_addr.s_addr;
else
- ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr);
+ ad.u.net.v6info.saddr = addr6->sin6_addr;
err = avc_has_perm(sksec->sid, sid,
sksec->sclass, node_perm, &ad);
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 3bf46abaa68..86365857c08 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -220,7 +220,7 @@ static int sel_netnode_sid_slow(void *addr, u16 family, u32 *sid)
case PF_INET6:
ret = security_node_sid(PF_INET6,
addr, sizeof(struct in6_addr), sid);
- ipv6_addr_copy(&new->nsec.addr.ipv6, addr);
+ new->nsec.addr.ipv6 = *(struct in6_addr *)addr;
break;
default:
BUG();
diff --git a/security/selinux/netport.c b/security/selinux/netport.c
index 0b62bd11246..7b9eb1faf68 100644
--- a/security/selinux/netport.c
+++ b/security/selinux/netport.c
@@ -123,7 +123,9 @@ static void sel_netport_insert(struct sel_netport *port)
if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) {
struct sel_netport *tail;
tail = list_entry(
- rcu_dereference(sel_netport_hash[idx].list.prev),
+ rcu_dereference_protected(
+ sel_netport_hash[idx].list.prev,
+ lockdep_is_held(&sel_netport_lock)),
struct sel_netport, list);
list_del_rcu(&tail->list);
kfree_rcu(tail, rcu);
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index f46658722c7..48a7d0014b4 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -749,14 +749,6 @@ out:
return length;
}
-static inline int hexcode_to_int(int code) {
- if (code == '\0' || !isxdigit(code))
- return -1;
- if (isdigit(code))
- return code - '0';
- return tolower(code) - 'a' + 10;
-}
-
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
char *scon = NULL, *tcon = NULL;
@@ -808,9 +800,11 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (c1 == '+')
c1 = ' ';
else if (c1 == '%') {
- if ((c1 = hexcode_to_int(*r++)) < 0)
+ c1 = hex_to_bin(*r++);
+ if (c1 < 0)
goto out;
- if ((c2 = hexcode_to_int(*r++)) < 0)
+ c2 = hex_to_bin(*r++);
+ if (c2 < 0)
goto out;
c1 = (c1 << 4) | c2;
}
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 2ec904177fe..377d148e715 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -175,7 +175,7 @@ void cond_policydb_destroy(struct policydb *p)
int cond_init_bool_indexes(struct policydb *p)
{
kfree(p->bool_val_to_struct);
- p->bool_val_to_struct = (struct cond_bool_datum **)
+ p->bool_val_to_struct =
kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum *), GFP_KERNEL);
if (!p->bool_val_to_struct)
return -ENOMEM;
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 7db62b48eb4..e8af5b0ba80 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -406,7 +406,7 @@ static int smack_sb_statfs(struct dentry *dentry)
static int smack_sb_mount(char *dev_name, struct path *path,
char *type, unsigned long flags, void *data)
{
- struct superblock_smack *sbp = path->mnt->mnt_sb->s_security;
+ struct superblock_smack *sbp = path->dentry->d_sb->s_security;
struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
@@ -435,7 +435,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, path);
- sbp = mnt->mnt_sb->s_security;
+ sbp = path.dentry->d_sb->s_security;
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
}
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 6aceef518a4..5c32f36ff70 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -102,9 +102,6 @@ static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT;
const char *smack_cipso_option = SMACK_CIPSO_OPTION;
-
-#define SEQ_READ_FINISHED ((loff_t)-1)
-
/*
* Values for parsing cipso rules
* SMK_DIGITLEN: Length of a digit field in a rule.
@@ -357,10 +354,12 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf,
rc = count;
/*
+ * If this is "load" as opposed to "load-self" and a new rule
+ * it needs to get added for reporting.
* smk_set_access returns true if there was already a rule
* for the subject/object pair, and false if it was new.
*/
- if (!smk_set_access(rule, rule_list, rule_lock)) {
+ if (load && !smk_set_access(rule, rule_list, rule_lock)) {
smlp = kzalloc(sizeof(*smlp), GFP_KERNEL);
if (smlp != NULL) {
smlp->smk_rule = rule;
@@ -377,12 +376,12 @@ out:
return rc;
}
-
/*
- * Seq_file read operations for /smack/load
+ * Core logic for smackfs seq list operations.
*/
-static void *load_seq_start(struct seq_file *s, loff_t *pos)
+static void *smk_seq_start(struct seq_file *s, loff_t *pos,
+ struct list_head *head)
{
struct list_head *list;
@@ -390,7 +389,7 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
* This is 0 the first time through.
*/
if (s->index == 0)
- s->private = &smack_rule_list;
+ s->private = head;
if (s->private == NULL)
return NULL;
@@ -404,11 +403,12 @@ static void *load_seq_start(struct seq_file *s, loff_t *pos)
return list;
}
-static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos,
+ struct list_head *head)
{
struct list_head *list = v;
- if (list_is_last(list, &smack_rule_list)) {
+ if (list_is_last(list, head)) {
s->private = NULL;
return NULL;
}
@@ -416,6 +416,25 @@ static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
return list->next;
}
+static void smk_seq_stop(struct seq_file *s, void *v)
+{
+ /* No-op */
+}
+
+/*
+ * Seq_file read operations for /smack/load
+ */
+
+static void *load_seq_start(struct seq_file *s, loff_t *pos)
+{
+ return smk_seq_start(s, pos, &smack_rule_list);
+}
+
+static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ return smk_seq_next(s, v, pos, &smack_rule_list);
+}
+
static int load_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
@@ -446,16 +465,11 @@ static int load_seq_show(struct seq_file *s, void *v)
return 0;
}
-static void load_seq_stop(struct seq_file *s, void *v)
-{
- /* No-op */
-}
-
static const struct seq_operations load_seq_ops = {
.start = load_seq_start,
.next = load_seq_next,
.show = load_seq_show,
- .stop = load_seq_stop,
+ .stop = smk_seq_stop,
};
/**
@@ -574,28 +588,12 @@ static void smk_unlbl_ambient(char *oldambient)
static void *cipso_seq_start(struct seq_file *s, loff_t *pos)
{
- if (*pos == SEQ_READ_FINISHED)
- return NULL;
- if (list_empty(&smack_known_list))
- return NULL;
-
- return smack_known_list.next;
+ return smk_seq_start(s, pos, &smack_known_list);
}
static void *cipso_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
- struct list_head *list = v;
-
- /*
- * labels with no associated cipso value wont be printed
- * in cipso_seq_show
- */
- if (list_is_last(list, &smack_known_list)) {
- *pos = SEQ_READ_FINISHED;
- return NULL;
- }
-
- return list->next;
+ return smk_seq_next(s, v, pos, &smack_known_list);
}
/*
@@ -634,16 +632,11 @@ static int cipso_seq_show(struct seq_file *s, void *v)
return 0;
}
-static void cipso_seq_stop(struct seq_file *s, void *v)
-{
- /* No-op */
-}
-
static const struct seq_operations cipso_seq_ops = {
.start = cipso_seq_start,
- .stop = cipso_seq_stop,
.next = cipso_seq_next,
.show = cipso_seq_show,
+ .stop = smk_seq_stop,
};
/**
@@ -788,23 +781,12 @@ static const struct file_operations smk_cipso_ops = {
static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos)
{
- if (*pos == SEQ_READ_FINISHED)
- return NULL;
- if (list_empty(&smk_netlbladdr_list))
- return NULL;
- return smk_netlbladdr_list.next;
+ return smk_seq_start(s, pos, &smk_netlbladdr_list);
}
static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
- struct list_head *list = v;
-
- if (list_is_last(list, &smk_netlbladdr_list)) {
- *pos = SEQ_READ_FINISHED;
- return NULL;
- }
-
- return list->next;
+ return smk_seq_next(s, v, pos, &smk_netlbladdr_list);
}
#define BEBITS (sizeof(__be32) * 8)
@@ -828,16 +810,11 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
return 0;
}
-static void netlbladdr_seq_stop(struct seq_file *s, void *v)
-{
- /* No-op */
-}
-
static const struct seq_operations netlbladdr_seq_ops = {
.start = netlbladdr_seq_start,
- .stop = netlbladdr_seq_stop,
.next = netlbladdr_seq_next,
.show = netlbladdr_seq_show,
+ .stop = smk_seq_stop,
};
/**
@@ -1405,23 +1382,14 @@ static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
{
struct task_smack *tsp = current_security();
- if (*pos == SEQ_READ_FINISHED)
- return NULL;
- if (list_empty(&tsp->smk_rules))
- return NULL;
- return tsp->smk_rules.next;
+ 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 list_head *list = v;
- if (list_is_last(list, &tsp->smk_rules)) {
- *pos = SEQ_READ_FINISHED;
- return NULL;
- }
- return list->next;
+ return smk_seq_next(s, v, pos, &tsp->smk_rules);
}
static int load_self_seq_show(struct seq_file *s, void *v)
@@ -1453,16 +1421,11 @@ static int load_self_seq_show(struct seq_file *s, void *v)
return 0;
}
-static void load_self_seq_stop(struct seq_file *s, void *v)
-{
- /* No-op */
-}
-
static const struct seq_operations load_self_seq_ops = {
.start = load_self_seq_start,
.next = load_self_seq_next,
.show = load_self_seq_show,
- .stop = load_self_seq_stop,
+ .stop = smk_seq_stop,
};
diff --git a/security/tomoyo/.gitignore b/security/tomoyo/.gitignore
new file mode 100644
index 00000000000..5caf1a6f590
--- /dev/null
+++ b/security/tomoyo/.gitignore
@@ -0,0 +1,2 @@
+builtin-policy.h
+policy/
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c
index 075c3a6d164..5ca47ea3049 100644
--- a/security/tomoyo/audit.c
+++ b/security/tomoyo/audit.c
@@ -112,7 +112,7 @@ out:
*
* Returns file type string.
*/
-static inline const char *tomoyo_filetype(const mode_t mode)
+static inline const char *tomoyo_filetype(const umode_t mode)
{
switch (mode & S_IFMT) {
case S_IFREG:
@@ -180,7 +180,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
for (i = 0; i < TOMOYO_MAX_PATH_STAT; i++) {
struct tomoyo_mini_stat *stat;
unsigned int dev;
- mode_t mode;
+ umode_t mode;
if (!obj->stat_valid[i])
continue;
stat = &obj->stat[i];
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index ed311d7a8ce..9512222d558 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -564,7 +564,7 @@ struct tomoyo_mini_stat {
uid_t uid;
gid_t gid;
ino_t ino;
- mode_t mode;
+ umode_t mode;
dev_t dev;
dev_t rdev;
};
@@ -1122,7 +1122,7 @@ static inline pid_t tomoyo_sys_getppid(void)
{
pid_t pid;
rcu_read_lock();
- pid = task_tgid_vnr(current->real_parent);
+ pid = task_tgid_vnr(rcu_dereference(current->real_parent));
rcu_read_unlock();
return pid;
}
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index 738bbdf8d4c..80a09c37cac 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -4,15 +4,8 @@
* Copyright (C) 2005-2011 NTT DATA CORPORATION
*/
-#include <linux/types.h>
-#include <linux/mount.h>
-#include <linux/mnt_namespace.h>
-#include <linux/fs_struct.h>
-#include <linux/magic.h>
-#include <linux/slab.h>
-#include <net/sock.h>
#include "common.h"
-#include "../../fs/internal.h"
+#include <linux/magic.h>
/**
* tomoyo_encode2 - Encode binary string to ascii string.
@@ -101,9 +94,8 @@ static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
{
char *pos = ERR_PTR(-ENOMEM);
if (buflen >= 256) {
- struct path ns_root = { };
/* go to whatever namespace root we are under */
- pos = __d_path(path, &ns_root, buffer, buflen - 1);
+ pos = d_absolute_path(path, buffer, buflen - 1);
if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
struct inode *inode = path->dentry->d_inode;
if (inode && S_ISDIR(inode->i_mode)) {
@@ -294,8 +286,16 @@ char *tomoyo_realpath_from_path(struct path *path)
pos = tomoyo_get_local_path(path->dentry, buf,
buf_len - 1);
/* Get absolute name for the rest. */
- else
+ else {
pos = tomoyo_get_absolute_path(path, buf, buf_len - 1);
+ /*
+ * Fall back to local name if absolute name is not
+ * available.
+ */
+ if (pos == ERR_PTR(-EINVAL))
+ pos = tomoyo_get_local_path(path->dentry, buf,
+ buf_len - 1);
+ }
encode:
if (IS_ERR(pos))
continue;
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 2672ac4f3be..482b2a5f48f 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -224,7 +224,7 @@ static const struct file_operations tomoyo_operations = {
*
* Returns nothing.
*/
-static void __init tomoyo_create_entry(const char *name, const mode_t mode,
+static void __init tomoyo_create_entry(const char *name, const umode_t mode,
struct dentry *parent, const u8 key)
{
securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 4b327b69174..620d37c159a 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -186,7 +186,7 @@ static int tomoyo_path_unlink(struct path *parent, struct dentry *dentry)
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
- int mode)
+ umode_t mode)
{
struct path path = { parent->mnt, dentry };
return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
@@ -234,7 +234,7 @@ static int tomoyo_path_symlink(struct path *parent, struct dentry *dentry,
* Returns 0 on success, negative value otherwise.
*/
static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
- int mode, unsigned int dev)
+ umode_t mode, unsigned int dev)
{
struct path path = { parent->mnt, dentry };
int type = TOMOYO_TYPE_CREATE;
@@ -353,17 +353,14 @@ static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
/**
* tomoyo_path_chmod - Target for security_path_chmod().
*
- * @dentry: Pointer to "struct dentry".
- * @mnt: Pointer to "struct vfsmount".
- * @mode: DAC permission mode.
+ * @path: Pointer to "struct path".
+ * @mode: DAC permission mode.
*
* Returns 0 on success, negative value otherwise.
*/
-static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
- mode_t mode)
+static int tomoyo_path_chmod(struct path *path, umode_t mode)
{
- struct path path = { mnt, dentry };
- return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, &path,
+ return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, path,
mode & S_IALLUGO);
}