summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/Kconfig1
-rw-r--r--security/Makefile2
-rw-r--r--security/apparmor/apparmorfs.c2
-rw-r--r--security/apparmor/domain.c12
-rw-r--r--security/apparmor/file.c6
-rw-r--r--security/apparmor/lsm.c155
-rw-r--r--security/capability.c1164
-rw-r--r--security/commoncap.c47
-rw-r--r--security/inode.c18
-rw-r--r--security/integrity/digsig.c2
-rw-r--r--security/integrity/evm/evm_crypto.c4
-rw-r--r--security/integrity/evm/evm_main.c34
-rw-r--r--security/integrity/iint.c3
-rw-r--r--security/integrity/ima/ima.h29
-rw-r--r--security/integrity/ima/ima_api.c20
-rw-r--r--security/integrity/ima/ima_appraise.c16
-rw-r--r--security/integrity/ima/ima_fs.c4
-rw-r--r--security/integrity/ima/ima_init.c13
-rw-r--r--security/integrity/ima/ima_main.c5
-rw-r--r--security/integrity/ima/ima_policy.c124
-rw-r--r--security/integrity/ima/ima_template_lib.c74
-rw-r--r--security/integrity/ima/ima_template_lib.h22
-rw-r--r--security/integrity/integrity.h2
-rw-r--r--security/keys/compat.c29
-rw-r--r--security/keys/internal.h5
-rw-r--r--security/keys/keyctl.c78
-rw-r--r--security/lsm_audit.c19
-rw-r--r--security/security.c1015
-rw-r--r--security/selinux/avc.c24
-rw-r--r--security/selinux/hooks.c668
-rw-r--r--security/selinux/include/avc.h9
-rw-r--r--security/selinux/include/classmap.h44
-rw-r--r--security/selinux/include/security.h1
-rw-r--r--security/selinux/nlmsgtab.c13
-rw-r--r--security/selinux/selinuxfs.c2
-rw-r--r--security/selinux/ss/avtab.c72
-rw-r--r--security/selinux/ss/avtab.h8
-rw-r--r--security/selinux/ss/mls.c10
-rw-r--r--security/selinux/ss/services.c6
-rw-r--r--security/selinux/xfrm.c3
-rw-r--r--security/smack/smack.h35
-rw-r--r--security/smack/smack_access.c111
-rw-r--r--security/smack/smack_lsm.c557
-rw-r--r--security/smack/smack_netfilter.c8
-rw-r--r--security/smack/smackfs.c378
-rw-r--r--security/tomoyo/.gitignore2
-rw-r--r--security/tomoyo/Kconfig1
-rw-r--r--security/tomoyo/Makefile55
-rw-r--r--security/tomoyo/common.h4
-rw-r--r--security/tomoyo/condition.c2
-rw-r--r--security/tomoyo/file.c4
-rw-r--r--security/tomoyo/policy/exception_policy.conf.default2
-rw-r--r--security/tomoyo/realpath.c16
-rw-r--r--security/tomoyo/tomoyo.c77
-rw-r--r--security/tomoyo/util.c13
-rw-r--r--security/yama/Kconfig2
-rw-r--r--security/yama/yama_lsm.c73
57 files changed, 2314 insertions, 2791 deletions
diff --git a/security/Kconfig b/security/Kconfig
index beb86b500adf..bf4ec46474b6 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -21,6 +21,7 @@ config SECURITY_DMESG_RESTRICT
config SECURITY
bool "Enable different security models"
depends on SYSFS
+ depends on MULTIUSER
help
This allows you to choose different security modules to be
configured into your kernel.
diff --git a/security/Makefile b/security/Makefile
index 05f1c934d74b..c9bfbc84ff50 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -14,7 +14,7 @@ obj-y += commoncap.o
obj-$(CONFIG_MMU) += min_addr.o
# Object file lists
-obj-$(CONFIG_SECURITY) += security.o capability.o
+obj-$(CONFIG_SECURITY) += security.o
obj-$(CONFIG_SECURITYFS) += inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/
obj-$(CONFIG_SECURITY_SMACK) += smack/
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 7db9954f1af2..ad4fa49ad1db 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -365,7 +365,7 @@ void __aa_fs_profile_rmdir(struct aa_profile *profile)
if (!profile->dents[i])
continue;
- r = profile->dents[i]->d_inode->i_private;
+ r = d_inode(profile->dents[i])->i_private;
securityfs_remove(profile->dents[i]);
aa_put_replacedby(r);
profile->dents[i] = NULL;
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c
index d97cba3e3849..dc0027b28b04 100644
--- a/security/apparmor/domain.c
+++ b/security/apparmor/domain.c
@@ -347,9 +347,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
file_inode(bprm->file)->i_mode
};
const char *name = NULL, *target = NULL, *info = NULL;
- int error = cap_bprm_set_creds(bprm);
- if (error)
- return error;
+ int error = 0;
if (bprm->cred_prepared)
return 0;
@@ -531,15 +529,13 @@ cleanup:
*/
int apparmor_bprm_secureexec(struct linux_binprm *bprm)
{
- int ret = cap_bprm_secureexec(bprm);
-
/* the decision to use secure exec is computed in set_creds
* and stored in bprm->unsafe.
*/
- if (!ret && (bprm->unsafe & AA_SECURE_X_NEEDED))
- ret = 1;
+ if (bprm->unsafe & AA_SECURE_X_NEEDED)
+ return 1;
- return ret;
+ return 0;
}
/**
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index fdaa50cb1876..913f377a038a 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -259,7 +259,7 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
*/
static inline bool is_deleted(struct dentry *dentry)
{
- if (d_unlinked(dentry) && dentry->d_inode->i_nlink == 0)
+ if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0)
return 1;
return 0;
}
@@ -351,8 +351,8 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
struct path link = { new_dir->mnt, new_dentry };
struct path target = { new_dir->mnt, old_dentry };
struct path_cond cond = {
- old_dentry->d_inode->i_uid,
- old_dentry->d_inode->i_mode
+ d_backing_inode(old_dentry)->i_uid,
+ d_backing_inode(old_dentry)->i_mode
};
char *buffer = NULL, *buffer2 = NULL;
const char *lname, *tname = NULL, *info = NULL;
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 107db88b1d5f..5696874e8062 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -12,7 +12,7 @@
* License.
*/
-#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
#include <linux/mman.h>
@@ -96,19 +96,11 @@ static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
static int apparmor_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- int error = cap_ptrace_access_check(child, mode);
- if (error)
- return error;
-
return aa_ptrace(current, child, mode);
}
static int apparmor_ptrace_traceme(struct task_struct *parent)
{
- int error = cap_ptrace_traceme(parent);
- if (error)
- return error;
-
return aa_ptrace(parent, current, PTRACE_MODE_ATTACH);
}
@@ -123,10 +115,10 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
cred = __task_cred(target);
profile = aa_cred_profile(cred);
- *effective = cred->cap_effective;
- *inheritable = cred->cap_inheritable;
- *permitted = cred->cap_permitted;
-
+ /*
+ * cap_capget is stacked ahead of this and will
+ * initialize effective and permitted.
+ */
if (!unconfined(profile) && !COMPLAIN_MODE(profile)) {
*effective = cap_intersect(*effective, profile->caps.allow);
*permitted = cap_intersect(*permitted, profile->caps.allow);
@@ -140,13 +132,11 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit)
{
struct aa_profile *profile;
- /* cap_capable returns 0 on success, else -EPERM */
- int error = cap_capable(cred, ns, cap, audit);
- if (!error) {
- profile = aa_cred_profile(cred);
- if (!unconfined(profile))
- error = aa_capable(profile, cap, audit);
- }
+ int error = 0;
+
+ profile = aa_cred_profile(cred);
+ if (!unconfined(profile))
+ error = aa_capable(profile, cap, audit);
return error;
}
@@ -204,8 +194,8 @@ static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
struct dentry *dentry, u32 mask)
{
struct path path = { mnt, dentry };
- struct path_cond cond = { dentry->d_inode->i_uid,
- dentry->d_inode->i_mode
+ struct path_cond cond = { d_backing_inode(dentry)->i_uid,
+ d_backing_inode(dentry)->i_mode
};
return common_perm(op, &path, mask, &cond);
@@ -223,7 +213,7 @@ static int common_perm_mnt_dentry(int op, struct vfsmount *mnt,
static int common_perm_rm(int op, struct path *dir,
struct dentry *dentry, u32 mask)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
struct path_cond cond = { };
if (!inode || !dir->mnt || !mediated_filesystem(dentry))
@@ -281,8 +271,8 @@ static int apparmor_path_mknod(struct path *dir, struct dentry *dentry,
static int apparmor_path_truncate(struct path *path)
{
- struct path_cond cond = { path->dentry->d_inode->i_uid,
- path->dentry->d_inode->i_mode
+ struct path_cond cond = { d_backing_inode(path->dentry)->i_uid,
+ d_backing_inode(path->dentry)->i_mode
};
if (!path->mnt || !mediated_filesystem(path->dentry))
@@ -327,8 +317,8 @@ static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry,
if (!unconfined(profile)) {
struct path old_path = { old_dir->mnt, old_dentry };
struct path new_path = { new_dir->mnt, new_dentry };
- struct path_cond cond = { old_dentry->d_inode->i_uid,
- old_dentry->d_inode->i_mode
+ struct path_cond cond = { d_backing_inode(old_dentry)->i_uid,
+ d_backing_inode(old_dentry)->i_mode
};
error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0,
@@ -354,8 +344,8 @@ static int apparmor_path_chmod(struct path *path, umode_t mode)
static int apparmor_path_chown(struct path *path, kuid_t uid, kgid_t gid)
{
- struct path_cond cond = { path->dentry->d_inode->i_uid,
- path->dentry->d_inode->i_mode
+ struct path_cond cond = { d_backing_inode(path->dentry)->i_uid,
+ d_backing_inode(path->dentry)->i_mode
};
if (!mediated_filesystem(path->dentry))
@@ -364,12 +354,12 @@ static int apparmor_path_chown(struct path *path, kuid_t uid, kgid_t gid)
return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond);
}
-static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+static int apparmor_inode_getattr(const struct path *path)
{
- if (!mediated_filesystem(dentry))
+ if (!mediated_filesystem(path->dentry))
return 0;
- return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry,
+ return common_perm_mnt_dentry(OP_GETATTR, path->mnt, path->dentry,
AA_MAY_META_READ);
}
@@ -615,49 +605,46 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
-static struct security_operations apparmor_ops = {
- .name = "apparmor",
-
- .ptrace_access_check = apparmor_ptrace_access_check,
- .ptrace_traceme = apparmor_ptrace_traceme,
- .capget = apparmor_capget,
- .capable = apparmor_capable,
-
- .path_link = apparmor_path_link,
- .path_unlink = apparmor_path_unlink,
- .path_symlink = apparmor_path_symlink,
- .path_mkdir = apparmor_path_mkdir,
- .path_rmdir = apparmor_path_rmdir,
- .path_mknod = apparmor_path_mknod,
- .path_rename = apparmor_path_rename,
- .path_chmod = apparmor_path_chmod,
- .path_chown = apparmor_path_chown,
- .path_truncate = apparmor_path_truncate,
- .inode_getattr = apparmor_inode_getattr,
-
- .file_open = apparmor_file_open,
- .file_permission = apparmor_file_permission,
- .file_alloc_security = apparmor_file_alloc_security,
- .file_free_security = apparmor_file_free_security,
- .mmap_file = apparmor_mmap_file,
- .mmap_addr = cap_mmap_addr,
- .file_mprotect = apparmor_file_mprotect,
- .file_lock = apparmor_file_lock,
-
- .getprocattr = apparmor_getprocattr,
- .setprocattr = apparmor_setprocattr,
-
- .cred_alloc_blank = apparmor_cred_alloc_blank,
- .cred_free = apparmor_cred_free,
- .cred_prepare = apparmor_cred_prepare,
- .cred_transfer = apparmor_cred_transfer,
-
- .bprm_set_creds = apparmor_bprm_set_creds,
- .bprm_committing_creds = apparmor_bprm_committing_creds,
- .bprm_committed_creds = apparmor_bprm_committed_creds,
- .bprm_secureexec = apparmor_bprm_secureexec,
-
- .task_setrlimit = apparmor_task_setrlimit,
+static struct security_hook_list apparmor_hooks[] = {
+ LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
+ LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
+ LSM_HOOK_INIT(capget, apparmor_capget),
+ LSM_HOOK_INIT(capable, apparmor_capable),
+
+ LSM_HOOK_INIT(path_link, apparmor_path_link),
+ LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
+ LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
+ LSM_HOOK_INIT(path_mkdir, apparmor_path_mkdir),
+ LSM_HOOK_INIT(path_rmdir, apparmor_path_rmdir),
+ LSM_HOOK_INIT(path_mknod, apparmor_path_mknod),
+ LSM_HOOK_INIT(path_rename, apparmor_path_rename),
+ LSM_HOOK_INIT(path_chmod, apparmor_path_chmod),
+ LSM_HOOK_INIT(path_chown, apparmor_path_chown),
+ LSM_HOOK_INIT(path_truncate, apparmor_path_truncate),
+ LSM_HOOK_INIT(inode_getattr, apparmor_inode_getattr),
+
+ LSM_HOOK_INIT(file_open, apparmor_file_open),
+ LSM_HOOK_INIT(file_permission, apparmor_file_permission),
+ LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security),
+ LSM_HOOK_INIT(file_free_security, apparmor_file_free_security),
+ LSM_HOOK_INIT(mmap_file, apparmor_mmap_file),
+ LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect),
+ LSM_HOOK_INIT(file_lock, apparmor_file_lock),
+
+ LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
+ LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
+
+ LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
+ LSM_HOOK_INIT(cred_free, apparmor_cred_free),
+ LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
+ LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer),
+
+ LSM_HOOK_INIT(bprm_set_creds, apparmor_bprm_set_creds),
+ LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds),
+ LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds),
+ LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec),
+
+ LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
};
/*
@@ -898,7 +885,7 @@ static int __init apparmor_init(void)
{
int error;
- if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) {
+ if (!apparmor_enabled || !security_module_enable("apparmor")) {
aa_info_message("AppArmor disabled by boot time parameter");
apparmor_enabled = 0;
return 0;
@@ -913,17 +900,10 @@ static int __init apparmor_init(void)
error = set_init_cxt();
if (error) {
AA_ERROR("Failed to set context on init task\n");
- goto register_security_out;
- }
-
- error = register_security(&apparmor_ops);
- if (error) {
- struct cred *cred = (struct cred *)current->real_cred;
- aa_free_task_context(cred_cxt(cred));
- cred_cxt(cred) = NULL;
- AA_ERROR("Unable to register AppArmor\n");
- goto register_security_out;
+ aa_free_root_ns();
+ goto alloc_out;
}
+ security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks));
/* Report that AppArmor successfully initialized */
apparmor_initialized = 1;
@@ -936,9 +916,6 @@ static int __init apparmor_init(void)
return error;
-register_security_out:
- aa_free_root_ns();
-
alloc_out:
aa_destroy_aafs();
diff --git a/security/capability.c b/security/capability.c
deleted file mode 100644
index 070dd46f62f4..000000000000
--- a/security/capability.c
+++ /dev/null
@@ -1,1164 +0,0 @@
-/*
- * Capabilities Linux Security Module
- *
- * This is the default security module in case no other module is loaded.
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/security.h>
-
-static int cap_binder_set_context_mgr(struct task_struct *mgr)
-{
- return 0;
-}
-
-static int cap_binder_transaction(struct task_struct *from,
- struct task_struct *to)
-{
- return 0;
-}
-
-static int cap_binder_transfer_binder(struct task_struct *from,
- struct task_struct *to)
-{
- return 0;
-}
-
-static int cap_binder_transfer_file(struct task_struct *from,
- struct task_struct *to, struct file *file)
-{
- return 0;
-}
-
-static int cap_syslog(int type)
-{
- return 0;
-}
-
-static int cap_quotactl(int cmds, int type, int id, struct super_block *sb)
-{
- return 0;
-}
-
-static int cap_quota_on(struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_bprm_check_security(struct linux_binprm *bprm)
-{
- return 0;
-}
-
-static void cap_bprm_committing_creds(struct linux_binprm *bprm)
-{
-}
-
-static void cap_bprm_committed_creds(struct linux_binprm *bprm)
-{
-}
-
-static int cap_sb_alloc_security(struct super_block *sb)
-{
- return 0;
-}
-
-static void cap_sb_free_security(struct super_block *sb)
-{
-}
-
-static int cap_sb_copy_data(char *orig, char *copy)
-{
- return 0;
-}
-
-static int cap_sb_remount(struct super_block *sb, void *data)
-{
- return 0;
-}
-
-static int cap_sb_kern_mount(struct super_block *sb, int flags, void *data)
-{
- return 0;
-}
-
-static int cap_sb_show_options(struct seq_file *m, struct super_block *sb)
-{
- return 0;
-}
-
-static int cap_sb_statfs(struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_sb_mount(const char *dev_name, struct path *path,
- const char *type, unsigned long flags, void *data)
-{
- return 0;
-}
-
-static int cap_sb_umount(struct vfsmount *mnt, int flags)
-{
- return 0;
-}
-
-static int cap_sb_pivotroot(struct path *old_path, struct path *new_path)
-{
- return 0;
-}
-
-static int cap_sb_set_mnt_opts(struct super_block *sb,
- struct security_mnt_opts *opts,
- unsigned long kern_flags,
- unsigned long *set_kern_flags)
-
-{
- if (unlikely(opts->num_mnt_opts))
- return -EOPNOTSUPP;
- return 0;
-}
-
-static int cap_sb_clone_mnt_opts(const struct super_block *oldsb,
- struct super_block *newsb)
-{
- return 0;
-}
-
-static int cap_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
-{
- return 0;
-}
-
-static int cap_dentry_init_security(struct dentry *dentry, int mode,
- struct qstr *name, void **ctx,
- u32 *ctxlen)
-{
- return -EOPNOTSUPP;
-}
-
-static int cap_inode_alloc_security(struct inode *inode)
-{
- return 0;
-}
-
-static void cap_inode_free_security(struct inode *inode)
-{
-}
-
-static int cap_inode_init_security(struct inode *inode, struct inode *dir,
- const struct qstr *qstr, const char **name,
- void **value, size_t *len)
-{
- return -EOPNOTSUPP;
-}
-
-static int cap_inode_create(struct inode *inode, struct dentry *dentry,
- umode_t mask)
-{
- return 0;
-}
-
-static int cap_inode_link(struct dentry *old_dentry, struct inode *inode,
- struct dentry *new_dentry)
-{
- return 0;
-}
-
-static int cap_inode_unlink(struct inode *inode, struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_inode_symlink(struct inode *inode, struct dentry *dentry,
- const char *name)
-{
- return 0;
-}
-
-static int cap_inode_mkdir(struct inode *inode, struct dentry *dentry,
- umode_t mask)
-{
- return 0;
-}
-
-static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_inode_mknod(struct inode *inode, struct dentry *dentry,
- umode_t mode, dev_t dev)
-{
- return 0;
-}
-
-static int cap_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
- struct inode *new_inode, struct dentry *new_dentry)
-{
- return 0;
-}
-
-static int cap_inode_readlink(struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_inode_follow_link(struct dentry *dentry,
- struct nameidata *nameidata)
-{
- return 0;
-}
-
-static int cap_inode_permission(struct inode *inode, int mask)
-{
- return 0;
-}
-
-static int cap_inode_setattr(struct dentry *dentry, struct iattr *iattr)
-{
- return 0;
-}
-
-static int cap_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
-{
- return 0;
-}
-
-static void cap_inode_post_setxattr(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags)
-{
-}
-
-static int cap_inode_getxattr(struct dentry *dentry, const char *name)
-{
- return 0;
-}
-
-static int cap_inode_listxattr(struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_inode_getsecurity(const struct inode *inode, const char *name,
- void **buffer, bool alloc)
-{
- return -EOPNOTSUPP;
-}
-
-static int cap_inode_setsecurity(struct inode *inode, const char *name,
- const void *value, size_t size, int flags)
-{
- return -EOPNOTSUPP;
-}
-
-static int cap_inode_listsecurity(struct inode *inode, char *buffer,
- size_t buffer_size)
-{
- return 0;
-}
-
-static void cap_inode_getsecid(const struct inode *inode, u32 *secid)
-{
- *secid = 0;
-}
-
-#ifdef CONFIG_SECURITY_PATH
-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, umode_t mode)
-{
- return 0;
-}
-
-static int cap_path_rmdir(struct path *dir, struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_path_unlink(struct path *dir, struct dentry *dentry)
-{
- return 0;
-}
-
-static int cap_path_symlink(struct path *dir, struct dentry *dentry,
- const char *old_name)
-{
- return 0;
-}
-
-static int cap_path_link(struct dentry *old_dentry, struct path *new_dir,
- struct dentry *new_dentry)
-{
- return 0;
-}
-
-static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
- struct path *new_path, struct dentry *new_dentry)
-{
- return 0;
-}
-
-static int cap_path_truncate(struct path *path)
-{
- return 0;
-}
-
-static int cap_path_chmod(struct path *path, umode_t mode)
-{
- return 0;
-}
-
-static int cap_path_chown(struct path *path, kuid_t uid, kgid_t gid)
-{
- return 0;
-}
-
-static int cap_path_chroot(struct path *root)
-{
- return 0;
-}
-#endif
-
-static int cap_file_permission(struct file *file, int mask)
-{
- return 0;
-}
-
-static int cap_file_alloc_security(struct file *file)
-{
- return 0;
-}
-
-static void cap_file_free_security(struct file *file)
-{
-}
-
-static int cap_file_ioctl(struct file *file, unsigned int command,
- unsigned long arg)
-{
- return 0;
-}
-
-static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
- unsigned long prot)
-{
- return 0;
-}
-
-static int cap_file_lock(struct file *file, unsigned int cmd)
-{
- return 0;
-}
-
-static int cap_file_fcntl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- return 0;
-}
-
-static void cap_file_set_fowner(struct file *file)
-{
- return;
-}
-
-static int cap_file_send_sigiotask(struct task_struct *tsk,
- struct fown_struct *fown, int sig)
-{
- return 0;
-}
-
-static int cap_file_receive(struct file *file)
-{
- return 0;
-}
-
-static int cap_file_open(struct file *file, const struct cred *cred)
-{
- return 0;
-}
-
-static int cap_task_create(unsigned long clone_flags)
-{
- return 0;
-}
-
-static void cap_task_free(struct task_struct *task)
-{
-}
-
-static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp)
-{
- return 0;
-}
-
-static void cap_cred_free(struct cred *cred)
-{
-}
-
-static int cap_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp)
-{
- return 0;
-}
-
-static void cap_cred_transfer(struct cred *new, const struct cred *old)
-{
-}
-
-static int cap_kernel_act_as(struct cred *new, u32 secid)
-{
- return 0;
-}
-
-static int cap_kernel_create_files_as(struct cred *new, struct inode *inode)
-{
- return 0;
-}
-
-static int cap_kernel_fw_from_file(struct file *file, char *buf, size_t size)
-{
- return 0;
-}
-
-static int cap_kernel_module_request(char *kmod_name)
-{
- return 0;
-}
-
-static int cap_kernel_module_from_file(struct file *file)
-{
- return 0;
-}
-
-static int cap_task_setpgid(struct task_struct *p, pid_t pgid)
-{
- return 0;
-}
-
-static int cap_task_getpgid(struct task_struct *p)
-{
- return 0;
-}
-
-static int cap_task_getsid(struct task_struct *p)
-{
- return 0;
-}
-
-static void cap_task_getsecid(struct task_struct *p, u32 *secid)
-{
- *secid = 0;
-}
-
-static int cap_task_getioprio(struct task_struct *p)
-{
- return 0;
-}
-
-static int cap_task_setrlimit(struct task_struct *p, unsigned int resource,
- struct rlimit *new_rlim)
-{
- return 0;
-}
-
-static int cap_task_getscheduler(struct task_struct *p)
-{
- return 0;
-}
-
-static int cap_task_movememory(struct task_struct *p)
-{
- return 0;
-}
-
-static int cap_task_wait(struct task_struct *p)
-{
- return 0;
-}
-
-static int cap_task_kill(struct task_struct *p, struct siginfo *info,
- int sig, u32 secid)
-{
- return 0;
-}
-
-static void cap_task_to_inode(struct task_struct *p, struct inode *inode)
-{
-}
-
-static int cap_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
-{
- return 0;
-}
-
-static void cap_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
-{
- *secid = 0;
-}
-
-static int cap_msg_msg_alloc_security(struct msg_msg *msg)
-{
- return 0;
-}
-
-static void cap_msg_msg_free_security(struct msg_msg *msg)
-{
-}
-
-static int cap_msg_queue_alloc_security(struct msg_queue *msq)
-{
- return 0;
-}
-
-static void cap_msg_queue_free_security(struct msg_queue *msq)
-{
-}
-
-static int cap_msg_queue_associate(struct msg_queue *msq, int msqflg)
-{
- return 0;
-}
-
-static int cap_msg_queue_msgctl(struct msg_queue *msq, int cmd)
-{
- return 0;
-}
-
-static int cap_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg,
- int msgflg)
-{
- return 0;
-}
-
-static int cap_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
- struct task_struct *target, long type, int mode)
-{
- return 0;
-}
-
-static int cap_shm_alloc_security(struct shmid_kernel *shp)
-{
- return 0;
-}
-
-static void cap_shm_free_security(struct shmid_kernel *shp)
-{
-}
-
-static int cap_shm_associate(struct shmid_kernel *shp, int shmflg)
-{
- return 0;
-}
-
-static int cap_shm_shmctl(struct shmid_kernel *shp, int cmd)
-{
- return 0;
-}
-
-static int cap_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
- int shmflg)
-{
- return 0;
-}
-
-static int cap_sem_alloc_security(struct sem_array *sma)
-{
- return 0;
-}
-
-static void cap_sem_free_security(struct sem_array *sma)
-{
-}
-
-static int cap_sem_associate(struct sem_array *sma, int semflg)
-{
- return 0;
-}
-
-static int cap_sem_semctl(struct sem_array *sma, int cmd)
-{
- return 0;
-}
-
-static int cap_sem_semop(struct sem_array *sma, struct sembuf *sops,
- unsigned nsops, int alter)
-{
- return 0;
-}
-
-#ifdef CONFIG_SECURITY_NETWORK
-static int cap_unix_stream_connect(struct sock *sock, struct sock *other,
- struct sock *newsk)
-{
- return 0;
-}
-
-static int cap_unix_may_send(struct socket *sock, struct socket *other)
-{
- return 0;
-}
-
-static int cap_socket_create(int family, int type, int protocol, int kern)
-{
- return 0;
-}
-
-static int cap_socket_post_create(struct socket *sock, int family, int type,
- int protocol, int kern)
-{
- return 0;
-}
-
-static int cap_socket_bind(struct socket *sock, struct sockaddr *address,
- int addrlen)
-{
- return 0;
-}
-
-static int cap_socket_connect(struct socket *sock, struct sockaddr *address,
- int addrlen)
-{
- return 0;
-}
-
-static int cap_socket_listen(struct socket *sock, int backlog)
-{
- return 0;
-}
-
-static int cap_socket_accept(struct socket *sock, struct socket *newsock)
-{
- return 0;
-}
-
-static int cap_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
-{
- return 0;
-}
-
-static int cap_socket_recvmsg(struct socket *sock, struct msghdr *msg,
- int size, int flags)
-{
- return 0;
-}
-
-static int cap_socket_getsockname(struct socket *sock)
-{
- return 0;
-}
-
-static int cap_socket_getpeername(struct socket *sock)
-{
- return 0;
-}
-
-static int cap_socket_setsockopt(struct socket *sock, int level, int optname)
-{
- return 0;
-}
-
-static int cap_socket_getsockopt(struct socket *sock, int level, int optname)
-{
- return 0;
-}
-
-static int cap_socket_shutdown(struct socket *sock, int how)
-{
- return 0;
-}
-
-static int cap_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
-{
- return 0;
-}
-
-static int cap_socket_getpeersec_stream(struct socket *sock,
- char __user *optval,
- int __user *optlen, unsigned len)
-{
- return -ENOPROTOOPT;
-}
-
-static int cap_socket_getpeersec_dgram(struct socket *sock,
- struct sk_buff *skb, u32 *secid)
-{
- return -ENOPROTOOPT;
-}
-
-static int cap_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
-{
- return 0;
-}
-
-static void cap_sk_free_security(struct sock *sk)
-{
-}
-
-static void cap_sk_clone_security(const struct sock *sk, struct sock *newsk)
-{
-}
-
-static void cap_sk_getsecid(struct sock *sk, u32 *secid)
-{
-}
-
-static void cap_sock_graft(struct sock *sk, struct socket *parent)
-{
-}
-
-static int cap_inet_conn_request(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req)
-{
- return 0;
-}
-
-static void cap_inet_csk_clone(struct sock *newsk,
- const struct request_sock *req)
-{
-}
-
-static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb)
-{
-}
-
-static int cap_secmark_relabel_packet(u32 secid)
-{
- return 0;
-}
-
-static void cap_secmark_refcount_inc(void)
-{
-}
-
-static void cap_secmark_refcount_dec(void)
-{
-}
-
-static void cap_req_classify_flow(const struct request_sock *req,
- struct flowi *fl)
-{
-}
-
-static int cap_tun_dev_alloc_security(void **security)
-{
- return 0;
-}
-
-static void cap_tun_dev_free_security(void *security)
-{
-}
-
-static int cap_tun_dev_create(void)
-{
- return 0;
-}
-
-static int cap_tun_dev_attach_queue(void *security)
-{
- return 0;
-}
-
-static int cap_tun_dev_attach(struct sock *sk, void *security)
-{
- return 0;
-}
-
-static int cap_tun_dev_open(void *security)
-{
- return 0;
-}
-
-static void cap_skb_owned_by(struct sk_buff *skb, struct sock *sk)
-{
-}
-
-#endif /* CONFIG_SECURITY_NETWORK */
-
-#ifdef CONFIG_SECURITY_NETWORK_XFRM
-static int cap_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp,
- struct xfrm_user_sec_ctx *sec_ctx,
- gfp_t gfp)
-{
- return 0;
-}
-
-static int cap_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx,
- struct xfrm_sec_ctx **new_ctxp)
-{
- return 0;
-}
-
-static void cap_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx)
-{
-}
-
-static int cap_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx)
-{
- return 0;
-}
-
-static int cap_xfrm_state_alloc(struct xfrm_state *x,
- struct xfrm_user_sec_ctx *sec_ctx)
-{
- return 0;
-}
-
-static int cap_xfrm_state_alloc_acquire(struct xfrm_state *x,
- struct xfrm_sec_ctx *polsec,
- u32 secid)
-{
- return 0;
-}
-
-static void cap_xfrm_state_free_security(struct xfrm_state *x)
-{
-}
-
-static int cap_xfrm_state_delete_security(struct xfrm_state *x)
-{
- return 0;
-}
-
-static int cap_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 sk_sid, u8 dir)
-{
- return 0;
-}
-
-static int cap_xfrm_state_pol_flow_match(struct xfrm_state *x,
- struct xfrm_policy *xp,
- const struct flowi *fl)
-{
- return 1;
-}
-
-static int cap_xfrm_decode_session(struct sk_buff *skb, u32 *fl, int ckall)
-{
- return 0;
-}
-
-#endif /* CONFIG_SECURITY_NETWORK_XFRM */
-static void cap_d_instantiate(struct dentry *dentry, struct inode *inode)
-{
-}
-
-static int cap_getprocattr(struct task_struct *p, char *name, char **value)
-{
- return -EINVAL;
-}
-
-static int cap_setprocattr(struct task_struct *p, char *name, void *value,
- size_t size)
-{
- return -EINVAL;
-}
-
-static int cap_ismaclabel(const char *name)
-{
- return 0;
-}
-
-static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
-{
- return -EOPNOTSUPP;
-}
-
-static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
-{
- *secid = 0;
- return 0;
-}
-
-static void cap_release_secctx(char *secdata, u32 seclen)
-{
-}
-
-static int cap_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
-{
- return 0;
-}
-
-static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
-{
- return 0;
-}
-
-static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
-{
- return -EOPNOTSUPP;
-}
-#ifdef CONFIG_KEYS
-static int cap_key_alloc(struct key *key, const struct cred *cred,
- unsigned long flags)
-{
- return 0;
-}
-
-static void cap_key_free(struct key *key)
-{
-}
-
-static int cap_key_permission(key_ref_t key_ref, const struct cred *cred,
- unsigned perm)
-{
- return 0;
-}
-
-static int cap_key_getsecurity(struct key *key, char **_buffer)
-{
- *_buffer = NULL;
- return 0;
-}
-
-#endif /* CONFIG_KEYS */
-
-#ifdef CONFIG_AUDIT
-static int cap_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
-{
- return 0;
-}
-
-static int cap_audit_rule_known(struct audit_krule *krule)
-{
- return 0;
-}
-
-static int cap_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
- struct audit_context *actx)
-{
- return 0;
-}
-
-static void cap_audit_rule_free(void *lsmrule)
-{
-}
-#endif /* CONFIG_AUDIT */
-
-#define set_to_cap_if_null(ops, function) \
- do { \
- if (!ops->function) { \
- ops->function = cap_##function; \
- pr_debug("Had to override the " #function \
- " security operation with the default.\n");\
- } \
- } while (0)
-
-void __init security_fixup_ops(struct security_operations *ops)
-{
- set_to_cap_if_null(ops, binder_set_context_mgr);
- set_to_cap_if_null(ops, binder_transaction);
- set_to_cap_if_null(ops, binder_transfer_binder);
- set_to_cap_if_null(ops, binder_transfer_file);
- set_to_cap_if_null(ops, ptrace_access_check);
- set_to_cap_if_null(ops, ptrace_traceme);
- set_to_cap_if_null(ops, capget);
- set_to_cap_if_null(ops, capset);
- set_to_cap_if_null(ops, capable);
- set_to_cap_if_null(ops, quotactl);
- set_to_cap_if_null(ops, quota_on);
- set_to_cap_if_null(ops, syslog);
- set_to_cap_if_null(ops, settime);
- set_to_cap_if_null(ops, vm_enough_memory);
- set_to_cap_if_null(ops, bprm_set_creds);
- set_to_cap_if_null(ops, bprm_committing_creds);
- set_to_cap_if_null(ops, bprm_committed_creds);
- set_to_cap_if_null(ops, bprm_check_security);
- set_to_cap_if_null(ops, bprm_secureexec);
- set_to_cap_if_null(ops, sb_alloc_security);
- set_to_cap_if_null(ops, sb_free_security);
- set_to_cap_if_null(ops, sb_copy_data);
- set_to_cap_if_null(ops, sb_remount);
- set_to_cap_if_null(ops, sb_kern_mount);
- set_to_cap_if_null(ops, sb_show_options);
- set_to_cap_if_null(ops, sb_statfs);
- set_to_cap_if_null(ops, sb_mount);
- set_to_cap_if_null(ops, sb_umount);
- set_to_cap_if_null(ops, sb_pivotroot);
- set_to_cap_if_null(ops, sb_set_mnt_opts);
- set_to_cap_if_null(ops, sb_clone_mnt_opts);
- set_to_cap_if_null(ops, sb_parse_opts_str);
- set_to_cap_if_null(ops, dentry_init_security);
- set_to_cap_if_null(ops, inode_alloc_security);
- set_to_cap_if_null(ops, inode_free_security);
- set_to_cap_if_null(ops, inode_init_security);
- set_to_cap_if_null(ops, inode_create);
- set_to_cap_if_null(ops, inode_link);
- set_to_cap_if_null(ops, inode_unlink);
- set_to_cap_if_null(ops, inode_symlink);
- set_to_cap_if_null(ops, inode_mkdir);
- set_to_cap_if_null(ops, inode_rmdir);
- set_to_cap_if_null(ops, inode_mknod);
- set_to_cap_if_null(ops, inode_rename);
- set_to_cap_if_null(ops, inode_readlink);
- set_to_cap_if_null(ops, inode_follow_link);
- set_to_cap_if_null(ops, inode_permission);
- set_to_cap_if_null(ops, inode_setattr);
- set_to_cap_if_null(ops, inode_getattr);
- set_to_cap_if_null(ops, inode_setxattr);
- set_to_cap_if_null(ops, inode_post_setxattr);
- set_to_cap_if_null(ops, inode_getxattr);
- set_to_cap_if_null(ops, inode_listxattr);
- set_to_cap_if_null(ops, inode_removexattr);
- set_to_cap_if_null(ops, inode_need_killpriv);
- set_to_cap_if_null(ops, inode_killpriv);
- set_to_cap_if_null(ops, inode_getsecurity);
- set_to_cap_if_null(ops, inode_setsecurity);
- set_to_cap_if_null(ops, inode_listsecurity);
- set_to_cap_if_null(ops, inode_getsecid);
-#ifdef CONFIG_SECURITY_PATH
- set_to_cap_if_null(ops, path_mknod);
- set_to_cap_if_null(ops, path_mkdir);
- set_to_cap_if_null(ops, path_rmdir);
- set_to_cap_if_null(ops, path_unlink);
- set_to_cap_if_null(ops, path_symlink);
- set_to_cap_if_null(ops, path_link);
- set_to_cap_if_null(ops, path_rename);
- set_to_cap_if_null(ops, path_truncate);
- set_to_cap_if_null(ops, path_chmod);
- set_to_cap_if_null(ops, path_chown);
- set_to_cap_if_null(ops, path_chroot);
-#endif
- set_to_cap_if_null(ops, file_permission);
- set_to_cap_if_null(ops, file_alloc_security);
- set_to_cap_if_null(ops, file_free_security);
- set_to_cap_if_null(ops, file_ioctl);
- set_to_cap_if_null(ops, mmap_addr);
- set_to_cap_if_null(ops, mmap_file);
- set_to_cap_if_null(ops, file_mprotect);
- set_to_cap_if_null(ops, file_lock);
- set_to_cap_if_null(ops, file_fcntl);
- set_to_cap_if_null(ops, file_set_fowner);
- set_to_cap_if_null(ops, file_send_sigiotask);
- set_to_cap_if_null(ops, file_receive);
- set_to_cap_if_null(ops, file_open);
- set_to_cap_if_null(ops, task_create);
- set_to_cap_if_null(ops, task_free);
- set_to_cap_if_null(ops, cred_alloc_blank);
- set_to_cap_if_null(ops, cred_free);
- set_to_cap_if_null(ops, cred_prepare);
- set_to_cap_if_null(ops, cred_transfer);
- set_to_cap_if_null(ops, kernel_act_as);
- set_to_cap_if_null(ops, kernel_create_files_as);
- set_to_cap_if_null(ops, kernel_fw_from_file);
- set_to_cap_if_null(ops, kernel_module_request);
- set_to_cap_if_null(ops, kernel_module_from_file);
- set_to_cap_if_null(ops, task_fix_setuid);
- set_to_cap_if_null(ops, task_setpgid);
- set_to_cap_if_null(ops, task_getpgid);
- set_to_cap_if_null(ops, task_getsid);
- set_to_cap_if_null(ops, task_getsecid);
- set_to_cap_if_null(ops, task_setnice);
- set_to_cap_if_null(ops, task_setioprio);
- set_to_cap_if_null(ops, task_getioprio);
- set_to_cap_if_null(ops, task_setrlimit);
- set_to_cap_if_null(ops, task_setscheduler);
- set_to_cap_if_null(ops, task_getscheduler);
- set_to_cap_if_null(ops, task_movememory);
- set_to_cap_if_null(ops, task_wait);
- set_to_cap_if_null(ops, task_kill);
- set_to_cap_if_null(ops, task_prctl);
- set_to_cap_if_null(ops, task_to_inode);
- set_to_cap_if_null(ops, ipc_permission);
- set_to_cap_if_null(ops, ipc_getsecid);
- set_to_cap_if_null(ops, msg_msg_alloc_security);
- set_to_cap_if_null(ops, msg_msg_free_security);
- set_to_cap_if_null(ops, msg_queue_alloc_security);
- set_to_cap_if_null(ops, msg_queue_free_security);
- set_to_cap_if_null(ops, msg_queue_associate);
- set_to_cap_if_null(ops, msg_queue_msgctl);
- set_to_cap_if_null(ops, msg_queue_msgsnd);
- set_to_cap_if_null(ops, msg_queue_msgrcv);
- set_to_cap_if_null(ops, shm_alloc_security);
- set_to_cap_if_null(ops, shm_free_security);
- set_to_cap_if_null(ops, shm_associate);
- set_to_cap_if_null(ops, shm_shmctl);
- set_to_cap_if_null(ops, shm_shmat);
- set_to_cap_if_null(ops, sem_alloc_security);
- set_to_cap_if_null(ops, sem_free_security);
- set_to_cap_if_null(ops, sem_associate);
- set_to_cap_if_null(ops, sem_semctl);
- set_to_cap_if_null(ops, sem_semop);
- set_to_cap_if_null(ops, netlink_send);
- set_to_cap_if_null(ops, d_instantiate);
- set_to_cap_if_null(ops, getprocattr);
- set_to_cap_if_null(ops, setprocattr);
- set_to_cap_if_null(ops, ismaclabel);
- set_to_cap_if_null(ops, secid_to_secctx);
- set_to_cap_if_null(ops, secctx_to_secid);
- set_to_cap_if_null(ops, release_secctx);
- set_to_cap_if_null(ops, inode_notifysecctx);
- set_to_cap_if_null(ops, inode_setsecctx);
- set_to_cap_if_null(ops, inode_getsecctx);
-#ifdef CONFIG_SECURITY_NETWORK
- set_to_cap_if_null(ops, unix_stream_connect);
- set_to_cap_if_null(ops, unix_may_send);
- set_to_cap_if_null(ops, socket_create);
- set_to_cap_if_null(ops, socket_post_create);
- set_to_cap_if_null(ops, socket_bind);
- set_to_cap_if_null(ops, socket_connect);
- set_to_cap_if_null(ops, socket_listen);
- set_to_cap_if_null(ops, socket_accept);
- set_to_cap_if_null(ops, socket_sendmsg);
- set_to_cap_if_null(ops, socket_recvmsg);
- set_to_cap_if_null(ops, socket_getsockname);
- set_to_cap_if_null(ops, socket_getpeername);
- set_to_cap_if_null(ops, socket_setsockopt);
- set_to_cap_if_null(ops, socket_getsockopt);
- set_to_cap_if_null(ops, socket_shutdown);
- set_to_cap_if_null(ops, socket_sock_rcv_skb);
- set_to_cap_if_null(ops, socket_getpeersec_stream);
- set_to_cap_if_null(ops, socket_getpeersec_dgram);
- set_to_cap_if_null(ops, sk_alloc_security);
- set_to_cap_if_null(ops, sk_free_security);
- set_to_cap_if_null(ops, sk_clone_security);
- set_to_cap_if_null(ops, sk_getsecid);
- set_to_cap_if_null(ops, sock_graft);
- set_to_cap_if_null(ops, inet_conn_request);
- set_to_cap_if_null(ops, inet_csk_clone);
- set_to_cap_if_null(ops, inet_conn_established);
- set_to_cap_if_null(ops, secmark_relabel_packet);
- set_to_cap_if_null(ops, secmark_refcount_inc);
- set_to_cap_if_null(ops, secmark_refcount_dec);
- set_to_cap_if_null(ops, req_classify_flow);
- set_to_cap_if_null(ops, tun_dev_alloc_security);
- set_to_cap_if_null(ops, tun_dev_free_security);
- set_to_cap_if_null(ops, tun_dev_create);
- set_to_cap_if_null(ops, tun_dev_open);
- set_to_cap_if_null(ops, tun_dev_attach_queue);
- set_to_cap_if_null(ops, tun_dev_attach);
- set_to_cap_if_null(ops, skb_owned_by);
-#endif /* CONFIG_SECURITY_NETWORK */
-#ifdef CONFIG_SECURITY_NETWORK_XFRM
- set_to_cap_if_null(ops, xfrm_policy_alloc_security);
- set_to_cap_if_null(ops, xfrm_policy_clone_security);
- set_to_cap_if_null(ops, xfrm_policy_free_security);
- set_to_cap_if_null(ops, xfrm_policy_delete_security);
- set_to_cap_if_null(ops, xfrm_state_alloc);
- set_to_cap_if_null(ops, xfrm_state_alloc_acquire);
- set_to_cap_if_null(ops, xfrm_state_free_security);
- set_to_cap_if_null(ops, xfrm_state_delete_security);
- set_to_cap_if_null(ops, xfrm_policy_lookup);
- set_to_cap_if_null(ops, xfrm_state_pol_flow_match);
- set_to_cap_if_null(ops, xfrm_decode_session);
-#endif /* CONFIG_SECURITY_NETWORK_XFRM */
-#ifdef CONFIG_KEYS
- set_to_cap_if_null(ops, key_alloc);
- set_to_cap_if_null(ops, key_free);
- set_to_cap_if_null(ops, key_permission);
- set_to_cap_if_null(ops, key_getsecurity);
-#endif /* CONFIG_KEYS */
-#ifdef CONFIG_AUDIT
- set_to_cap_if_null(ops, audit_rule_init);
- set_to_cap_if_null(ops, audit_rule_known);
- set_to_cap_if_null(ops, audit_rule_match);
- set_to_cap_if_null(ops, audit_rule_free);
-#endif
-}
diff --git a/security/commoncap.c b/security/commoncap.c
index f66713bd7450..d103f5a4043d 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/file.h>
#include <linux/mm.h>
#include <linux/mman.h>
@@ -53,11 +53,6 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
}
}
-int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
-{
- return 0;
-}
-
/**
* cap_capable - Determine whether a task has a particular effective capability
* @cred: The credentials to use
@@ -297,7 +292,7 @@ static inline void bprm_clear_caps(struct linux_binprm *bprm)
*/
int cap_inode_need_killpriv(struct dentry *dentry)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
int error;
if (!inode->i_op->getxattr)
@@ -319,7 +314,7 @@ int cap_inode_need_killpriv(struct dentry *dentry)
*/
int cap_inode_killpriv(struct dentry *dentry)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
if (!inode->i_op->removexattr)
return 0;
@@ -375,7 +370,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
*/
int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
__u32 magic_etc;
unsigned tocopy, i;
int size;
@@ -941,7 +936,7 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
* @pages: The size of the mapping
*
* Determine whether the allocation of a new virtual mapping by the current
- * task is permitted, returning 0 if permission is granted, -ve if not.
+ * task is permitted, returning 1 if permission is granted, 0 if not.
*/
int cap_vm_enough_memory(struct mm_struct *mm, long pages)
{
@@ -950,7 +945,7 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
SECURITY_CAP_NOAUDIT) == 0)
cap_sys_admin = 1;
- return __vm_enough_memory(mm, pages, cap_sys_admin);
+ return cap_sys_admin;
}
/*
@@ -981,3 +976,33 @@ int cap_mmap_file(struct file *file, unsigned long reqprot,
{
return 0;
}
+
+#ifdef CONFIG_SECURITY
+
+struct security_hook_list capability_hooks[] = {
+ LSM_HOOK_INIT(capable, cap_capable),
+ LSM_HOOK_INIT(settime, cap_settime),
+ LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check),
+ LSM_HOOK_INIT(ptrace_traceme, cap_ptrace_traceme),
+ LSM_HOOK_INIT(capget, cap_capget),
+ LSM_HOOK_INIT(capset, cap_capset),
+ LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds),
+ LSM_HOOK_INIT(bprm_secureexec, cap_bprm_secureexec),
+ LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv),
+ LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv),
+ LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),
+ LSM_HOOK_INIT(mmap_file, cap_mmap_file),
+ LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid),
+ LSM_HOOK_INIT(task_prctl, cap_task_prctl),
+ LSM_HOOK_INIT(task_setscheduler, cap_task_setscheduler),
+ LSM_HOOK_INIT(task_setioprio, cap_task_setioprio),
+ LSM_HOOK_INIT(task_setnice, cap_task_setnice),
+ LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory),
+};
+
+void __init capability_add_hooks(void)
+{
+ security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks));
+}
+
+#endif /* CONFIG_SECURITY */
diff --git a/security/inode.c b/security/inode.c
index 131a3c49f766..91503b79c5f8 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -27,7 +27,7 @@ static int mount_count;
static inline int positive(struct dentry *dentry)
{
- return dentry->d_inode && !d_unhashed(dentry);
+ return d_really_is_positive(dentry) && !d_unhashed(dentry);
}
static int fill_super(struct super_block *sb, void *data, int silent)
@@ -102,14 +102,14 @@ struct dentry *securityfs_create_file(const char *name, umode_t mode,
if (!parent)
parent = mount->mnt_root;
- dir = parent->d_inode;
+ dir = d_inode(parent);
mutex_lock(&dir->i_mutex);
dentry = lookup_one_len(name, parent, strlen(name));
if (IS_ERR(dentry))
goto out;
- if (dentry->d_inode) {
+ if (d_really_is_positive(dentry)) {
error = -EEXIST;
goto out1;
}
@@ -197,20 +197,20 @@ void securityfs_remove(struct dentry *dentry)
return;
parent = dentry->d_parent;
- if (!parent || !parent->d_inode)
+ if (!parent || d_really_is_negative(parent))
return;
- mutex_lock(&parent->d_inode->i_mutex);
+ mutex_lock(&d_inode(parent)->i_mutex);
if (positive(dentry)) {
- if (dentry->d_inode) {
+ if (d_really_is_positive(dentry)) {
if (d_is_dir(dentry))
- simple_rmdir(parent->d_inode, dentry);
+ simple_rmdir(d_inode(parent), dentry);
else
- simple_unlink(parent->d_inode, dentry);
+ simple_unlink(d_inode(parent), dentry);
dput(dentry);
}
}
- mutex_unlock(&parent->d_inode->i_mutex);
+ mutex_unlock(&d_inode(parent)->i_mutex);
simple_release_fs(&mount, &mount_count);
}
EXPORT_SYMBOL_GPL(securityfs_remove);
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 5e3bd72b299a..36fb6b527829 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -85,7 +85,7 @@ int __init integrity_init_keyring(const unsigned int id)
return err;
}
-int __init integrity_load_x509(const unsigned int id, char *path)
+int __init integrity_load_x509(const unsigned int id, const char *path)
{
key_ref_t key;
char *data;
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 5e9687f02e1b..159ef3ea4130 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -131,7 +131,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
size_t req_xattr_value_len,
char type, char *digest)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
struct shash_desc *desc;
char **xattrname;
size_t xattr_size = 0;
@@ -199,7 +199,7 @@ int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
const char *xattr_value, size_t xattr_value_len)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
struct evm_ima_xattr_data xattr_data;
int rc = 0;
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index f589c9a05da2..1334e02ae8f4 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -72,7 +72,7 @@ static void __init evm_init_config(void)
static int evm_find_protected_xattrs(struct dentry *dentry)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
char **xattr;
int error;
int count = 0;
@@ -165,8 +165,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,
/* Replace RSA with HMAC if not mounted readonly and
* not immutable
*/
- if (!IS_RDONLY(dentry->d_inode) &&
- !IS_IMMUTABLE(dentry->d_inode))
+ if (!IS_RDONLY(d_backing_inode(dentry)) &&
+ !IS_IMMUTABLE(d_backing_inode(dentry)))
evm_update_evmxattr(dentry, xattr_name,
xattr_value,
xattr_value_len);
@@ -235,7 +235,7 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,
return INTEGRITY_UNKNOWN;
if (!iint) {
- iint = integrity_iint_find(dentry->d_inode);
+ iint = integrity_iint_find(d_backing_inode(dentry));
if (!iint)
return INTEGRITY_UNKNOWN;
}
@@ -253,7 +253,7 @@ EXPORT_SYMBOL_GPL(evm_verifyxattr);
*/
static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode)
return 0;
@@ -293,13 +293,24 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,
if (evm_status == INTEGRITY_NOXATTRS) {
struct integrity_iint_cache *iint;
- iint = integrity_iint_find(dentry->d_inode);
+ iint = integrity_iint_find(d_backing_inode(dentry));
if (iint && (iint->flags & IMA_NEW_FILE))
return 0;
+
+ /* exception for pseudo filesystems */
+ if (dentry->d_inode->i_sb->s_magic == TMPFS_MAGIC
+ || dentry->d_inode->i_sb->s_magic == SYSFS_MAGIC)
+ return 0;
+
+ integrity_audit_msg(AUDIT_INTEGRITY_METADATA,
+ dentry->d_inode, dentry->d_name.name,
+ "update_metadata",
+ integrity_status_msg[evm_status],
+ -EPERM, 0);
}
out:
if (evm_status != INTEGRITY_PASS)
- integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
+ integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
integrity_status_msg[evm_status],
-EPERM, 0);
@@ -376,17 +387,16 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,
* @xattr_name: pointer to the affected extended attribute name
*
* Update the HMAC stored in 'security.evm' to reflect removal of the xattr.
+ *
+ * No need to take the i_mutex lock here, as this function is called from
+ * vfs_removexattr() which takes the i_mutex.
*/
void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)
{
- struct inode *inode = dentry->d_inode;
-
if (!evm_initialized || !evm_protected_xattr(xattr_name))
return;
- mutex_lock(&inode->i_mutex);
evm_update_evmxattr(dentry, xattr_name, NULL, 0);
- mutex_unlock(&inode->i_mutex);
}
/**
@@ -404,7 +414,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)
if ((evm_status == INTEGRITY_PASS) ||
(evm_status == INTEGRITY_NOXATTRS))
return 0;
- integrity_audit_msg(AUDIT_INTEGRITY_METADATA, dentry->d_inode,
+ integrity_audit_msg(AUDIT_INTEGRITY_METADATA, d_backing_inode(dentry),
dentry->d_name.name, "appraise_metadata",
integrity_status_msg[evm_status], -EPERM, 0);
return -EPERM;
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index dbb6d141c3db..3d2f5b45c8cb 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -213,6 +213,9 @@ int __init integrity_read_file(const char *path, char **data)
char *buf;
int rc = -EINVAL;
+ if (!path || !*path)
+ return -EINVAL;
+
file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file)) {
rc = PTR_ERR(file);
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 8ee997dff139..e2a60c30df44 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -52,6 +52,16 @@ extern int ima_used_chip;
extern int ima_hash_algo;
extern int ima_appraise;
+/* IMA event related data */
+struct ima_event_data {
+ struct integrity_iint_cache *iint;
+ struct file *file;
+ const unsigned char *filename;
+ struct evm_ima_xattr_data *xattr_value;
+ int xattr_len;
+ const char *violation;
+};
+
/* IMA template field data definition */
struct ima_field_data {
u8 *data;
@@ -61,12 +71,10 @@ struct ima_field_data {
/* IMA template field definition */
struct ima_template_field {
const char field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN];
- int (*field_init) (struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value,
- int xattr_len, struct ima_field_data *field_data);
- void (*field_show) (struct seq_file *m, enum ima_show_type show,
- struct ima_field_data *field_data);
+ int (*field_init)(struct ima_event_data *event_data,
+ struct ima_field_data *field_data);
+ void (*field_show)(struct seq_file *m, enum ima_show_type show,
+ struct ima_field_data *field_data);
};
/* IMA template descriptor definition */
@@ -103,10 +111,11 @@ int ima_calc_field_array_hash(struct ima_field_data *field_data,
struct ima_digest_data *hash);
int __init ima_calc_boot_aggregate(struct ima_digest_data *hash);
void ima_add_violation(struct file *file, const unsigned char *filename,
+ struct integrity_iint_cache *iint,
const char *op, const char *cause);
int ima_init_crypto(void);
void ima_putc(struct seq_file *m, void *data, int datalen);
-void ima_print_digest(struct seq_file *m, u8 *digest, int size);
+void ima_print_digest(struct seq_file *m, u8 *digest, u32 size);
struct ima_template_desc *ima_template_desc_current(void);
int ima_init_template(void);
@@ -140,10 +149,8 @@ void ima_store_measurement(struct integrity_iint_cache *iint, struct file *file,
int xattr_len);
void ima_audit_measurement(struct integrity_iint_cache *iint,
const unsigned char *filename);
-int ima_alloc_init_template(struct integrity_iint_cache *iint,
- struct file *file, const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value,
- int xattr_len, struct ima_template_entry **entry);
+int ima_alloc_init_template(struct ima_event_data *event_data,
+ struct ima_template_entry **entry);
int ima_store_template(struct ima_template_entry *entry, int violation,
struct inode *inode, const unsigned char *filename);
void ima_free_template_entry(struct ima_template_entry *entry);
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index b8a27c5052d4..1d950fbb2aec 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -37,10 +37,8 @@ void ima_free_template_entry(struct ima_template_entry *entry)
/*
* ima_alloc_init_template - create and initialize a new template entry
*/
-int ima_alloc_init_template(struct integrity_iint_cache *iint,
- struct file *file, const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value,
- int xattr_len, struct ima_template_entry **entry)
+int ima_alloc_init_template(struct ima_event_data *event_data,
+ struct ima_template_entry **entry)
{
struct ima_template_desc *template_desc = ima_template_desc_current();
int i, result = 0;
@@ -55,8 +53,7 @@ int ima_alloc_init_template(struct integrity_iint_cache *iint,
struct ima_template_field *field = template_desc->fields[i];
u32 len;
- result = field->field_init(iint, file, filename,
- xattr_value, xattr_len,
+ result = field->field_init(event_data,
&((*entry)->template_data[i]));
if (result != 0)
goto out;
@@ -129,18 +126,20 @@ int ima_store_template(struct ima_template_entry *entry,
* value is invalidated.
*/
void ima_add_violation(struct file *file, const unsigned char *filename,
+ struct integrity_iint_cache *iint,
const char *op, const char *cause)
{
struct ima_template_entry *entry;
struct inode *inode = file_inode(file);
+ struct ima_event_data event_data = {iint, file, filename, NULL, 0,
+ cause};
int violation = 1;
int result;
/* can overflow, only indicator */
atomic_long_inc(&ima_htable.violations);
- result = ima_alloc_init_template(NULL, file, filename,
- NULL, 0, &entry);
+ result = ima_alloc_init_template(&event_data, &entry);
if (result < 0) {
result = -ENOMEM;
goto err_out;
@@ -267,13 +266,14 @@ void ima_store_measurement(struct integrity_iint_cache *iint,
int result = -ENOMEM;
struct inode *inode = file_inode(file);
struct ima_template_entry *entry;
+ struct ima_event_data event_data = {iint, file, filename, xattr_value,
+ xattr_len, NULL};
int violation = 0;
if (iint->flags & IMA_MEASURED)
return;
- result = ima_alloc_init_template(iint, file, filename,
- xattr_value, xattr_len, &entry);
+ result = ima_alloc_init_template(&event_data, &entry);
if (result < 0) {
integrity_audit_msg(AUDIT_INTEGRITY_PCR, inode, filename,
op, audit_cause, result, 0);
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index fffcdb0b31f0..1873b5536f80 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -165,7 +165,7 @@ void ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value, int xattr_len,
int ima_read_xattr(struct dentry *dentry,
struct evm_ima_xattr_data **xattr_value)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
if (!inode->i_op->getxattr)
return 0;
@@ -190,7 +190,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
static const char op[] = "appraise_data";
char *cause = "unknown";
struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0;
@@ -314,7 +314,7 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
*/
void ima_inode_post_setattr(struct dentry *dentry)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
struct integrity_iint_cache *iint;
int must_appraise, rc;
@@ -378,10 +378,14 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name,
result = ima_protect_xattr(dentry, xattr_name, xattr_value,
xattr_value_len);
if (result == 1) {
+ bool digsig;
+
if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST))
return -EINVAL;
- ima_reset_appraise_flags(dentry->d_inode,
- (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0);
+ digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG);
+ if (!digsig && (ima_appraise & IMA_APPRAISE_ENFORCE))
+ return -EPERM;
+ ima_reset_appraise_flags(d_backing_inode(dentry), digsig);
result = 0;
}
return result;
@@ -393,7 +397,7 @@ int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name)
result = ima_protect_xattr(dentry, xattr_name, NULL, 0);
if (result == 1) {
- ima_reset_appraise_flags(dentry->d_inode, 0);
+ ima_reset_appraise_flags(d_backing_inode(dentry), 0);
result = 0;
}
return result;
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c
index 461215e5fd31..816d175da79a 100644
--- a/security/integrity/ima/ima_fs.c
+++ b/security/integrity/ima/ima_fs.c
@@ -190,9 +190,9 @@ static const struct file_operations ima_measurements_ops = {
.release = seq_release,
};
-void ima_print_digest(struct seq_file *m, u8 *digest, int size)
+void ima_print_digest(struct seq_file *m, u8 *digest, u32 size)
{
- int i;
+ u32 i;
for (i = 0; i < size; i++)
seq_printf(m, "%02x", *(digest + i));
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 5e4c29d174ee..e600cadd231c 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -24,12 +24,6 @@
#include <crypto/hash_info.h>
#include "ima.h"
-#ifdef CONFIG_IMA_X509_PATH
-#define IMA_X509_PATH CONFIG_IMA_X509_PATH
-#else
-#define IMA_X509_PATH "/etc/keys/x509_ima.der"
-#endif
-
/* name for boot aggregate entry */
static const char *boot_aggregate_name = "boot_aggregate";
int ima_used_chip;
@@ -55,6 +49,8 @@ static int __init ima_add_boot_aggregate(void)
const char *audit_cause = "ENOMEM";
struct ima_template_entry *entry;
struct integrity_iint_cache tmp_iint, *iint = &tmp_iint;
+ struct ima_event_data event_data = {iint, NULL, boot_aggregate_name,
+ NULL, 0, NULL};
int result = -ENOMEM;
int violation = 0;
struct {
@@ -76,8 +72,7 @@ static int __init ima_add_boot_aggregate(void)
}
}
- result = ima_alloc_init_template(iint, NULL, boot_aggregate_name,
- NULL, 0, &entry);
+ result = ima_alloc_init_template(&event_data, &entry);
if (result < 0) {
audit_cause = "alloc_entry";
goto err_out;
@@ -103,7 +98,7 @@ void __init ima_load_x509(void)
int unset_flags = ima_policy_flag & IMA_APPRAISE;
ima_policy_flag &= ~unset_flags;
- integrity_load_x509(INTEGRITY_KEYRING_IMA, IMA_X509_PATH);
+ integrity_load_x509(INTEGRITY_KEYRING_IMA, CONFIG_IMA_X509_PATH);
ima_policy_flag |= unset_flags;
}
#endif
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index eeee00dce729..c21f09bf8b99 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -106,9 +106,10 @@ static void ima_rdwr_violation_check(struct file *file,
*pathname = ima_d_path(&file->f_path, pathbuf);
if (send_tomtou)
- ima_add_violation(file, *pathname, "invalid_pcr", "ToMToU");
+ ima_add_violation(file, *pathname, iint,
+ "invalid_pcr", "ToMToU");
if (send_writers)
- ima_add_violation(file, *pathname,
+ ima_add_violation(file, *pathname, iint,
"invalid_pcr", "open_writers");
}
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c
index d1eefb9d65fb..3997e206f82d 100644
--- a/security/integrity/ima/ima_policy.c
+++ b/security/integrity/ima/ima_policy.c
@@ -27,6 +27,8 @@
#define IMA_UID 0x0008
#define IMA_FOWNER 0x0010
#define IMA_FSUUID 0x0020
+#define IMA_INMASK 0x0040
+#define IMA_EUID 0x0080
#define UNKNOWN 0
#define MEASURE 0x0001 /* same as IMA_MEASURE */
@@ -42,6 +44,8 @@ enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE,
LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE
};
+enum policy_types { ORIGINAL_TCB = 1, DEFAULT_TCB };
+
struct ima_rule_entry {
struct list_head list;
int action;
@@ -70,7 +74,7 @@ struct ima_rule_entry {
* normal users can easily run the machine out of memory simply building
* and running executables.
*/
-static struct ima_rule_entry default_rules[] = {
+static struct ima_rule_entry dont_measure_rules[] = {
{.action = DONT_MEASURE, .fsmagic = PROC_SUPER_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_MEASURE, .fsmagic = SYSFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_MEASURE, .fsmagic = DEBUGFS_MAGIC, .flags = IMA_FSMAGIC},
@@ -79,12 +83,31 @@ static struct ima_rule_entry default_rules[] = {
{.action = DONT_MEASURE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_MEASURE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_MEASURE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE, .fsmagic = CGROUP_SUPER_MAGIC,
+ .flags = IMA_FSMAGIC},
+ {.action = DONT_MEASURE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC}
+};
+
+static struct ima_rule_entry original_measurement_rules[] = {
{.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC,
.flags = IMA_FUNC | IMA_MASK},
{.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
.flags = IMA_FUNC | IMA_MASK},
- {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ, .uid = GLOBAL_ROOT_UID,
- .flags = IMA_FUNC | IMA_MASK | IMA_UID},
+ {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
+ .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_MASK | IMA_UID},
+ {.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
+ {.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
+};
+
+static struct ima_rule_entry default_measurement_rules[] = {
+ {.action = MEASURE, .func = MMAP_CHECK, .mask = MAY_EXEC,
+ .flags = IMA_FUNC | IMA_MASK},
+ {.action = MEASURE, .func = BPRM_CHECK, .mask = MAY_EXEC,
+ .flags = IMA_FUNC | IMA_MASK},
+ {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
+ .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_EUID},
+ {.action = MEASURE, .func = FILE_CHECK, .mask = MAY_READ,
+ .uid = GLOBAL_ROOT_UID, .flags = IMA_FUNC | IMA_INMASK | IMA_UID},
{.action = MEASURE, .func = MODULE_CHECK, .flags = IMA_FUNC},
{.action = MEASURE, .func = FIRMWARE_CHECK, .flags = IMA_FUNC},
};
@@ -99,6 +122,7 @@ static struct ima_rule_entry default_appraise_rules[] = {
{.action = DONT_APPRAISE, .fsmagic = BINFMTFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_APPRAISE, .fsmagic = SECURITYFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_APPRAISE, .fsmagic = SELINUX_MAGIC, .flags = IMA_FSMAGIC},
+ {.action = DONT_APPRAISE, .fsmagic = NSFS_MAGIC, .flags = IMA_FSMAGIC},
{.action = DONT_APPRAISE, .fsmagic = CGROUP_SUPER_MAGIC, .flags = IMA_FSMAGIC},
#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
{.action = APPRAISE, .fowner = GLOBAL_ROOT_UID, .flags = IMA_FOWNER},
@@ -115,14 +139,29 @@ static struct list_head *ima_rules;
static DEFINE_MUTEX(ima_rules_mutex);
-static bool ima_use_tcb __initdata;
+static int ima_policy __initdata;
static int __init default_measure_policy_setup(char *str)
{
- ima_use_tcb = 1;
+ if (ima_policy)
+ return 1;
+
+ ima_policy = ORIGINAL_TCB;
return 1;
}
__setup("ima_tcb", default_measure_policy_setup);
+static int __init policy_setup(char *str)
+{
+ if (ima_policy)
+ return 1;
+
+ if (strcmp(str, "tcb") == 0)
+ ima_policy = DEFAULT_TCB;
+
+ return 1;
+}
+__setup("ima_policy=", policy_setup);
+
static bool ima_use_appraise_tcb __initdata;
static int __init default_appraise_policy_setup(char *str)
{
@@ -182,6 +221,9 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
if ((rule->flags & IMA_MASK) &&
(rule->mask != mask && func != POST_SETATTR))
return false;
+ if ((rule->flags & IMA_INMASK) &&
+ (!(rule->mask & mask) && func != POST_SETATTR))
+ return false;
if ((rule->flags & IMA_FSMAGIC)
&& rule->fsmagic != inode->i_sb->s_magic)
return false;
@@ -190,6 +232,16 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
return false;
if ((rule->flags & IMA_UID) && !uid_eq(rule->uid, cred->uid))
return false;
+ if (rule->flags & IMA_EUID) {
+ if (has_capability_noaudit(current, CAP_SETUID)) {
+ if (!uid_eq(rule->uid, cred->euid)
+ && !uid_eq(rule->uid, cred->suid)
+ && !uid_eq(rule->uid, cred->uid))
+ return false;
+ } else if (!uid_eq(rule->uid, cred->euid))
+ return false;
+ }
+
if ((rule->flags & IMA_FOWNER) && !uid_eq(rule->fowner, inode->i_uid))
return false;
for (i = 0; i < MAX_LSM_RULES; i++) {
@@ -333,21 +385,31 @@ void __init ima_init_policy(void)
{
int i, measure_entries, appraise_entries;
- /* if !ima_use_tcb set entries = 0 so we load NO default rules */
- measure_entries = ima_use_tcb ? ARRAY_SIZE(default_rules) : 0;
+ /* if !ima_policy set entries = 0 so we load NO default rules */
+ measure_entries = ima_policy ? ARRAY_SIZE(dont_measure_rules) : 0;
appraise_entries = ima_use_appraise_tcb ?
ARRAY_SIZE(default_appraise_rules) : 0;
- for (i = 0; i < measure_entries + appraise_entries; i++) {
- if (i < measure_entries)
- list_add_tail(&default_rules[i].list,
- &ima_default_rules);
- else {
- int j = i - measure_entries;
+ for (i = 0; i < measure_entries; i++)
+ list_add_tail(&dont_measure_rules[i].list, &ima_default_rules);
- list_add_tail(&default_appraise_rules[j].list,
+ switch (ima_policy) {
+ case ORIGINAL_TCB:
+ for (i = 0; i < ARRAY_SIZE(original_measurement_rules); i++)
+ list_add_tail(&original_measurement_rules[i].list,
&ima_default_rules);
- }
+ break;
+ case DEFAULT_TCB:
+ for (i = 0; i < ARRAY_SIZE(default_measurement_rules); i++)
+ list_add_tail(&default_measurement_rules[i].list,
+ &ima_default_rules);
+ default:
+ break;
+ }
+
+ for (i = 0; i < appraise_entries; i++) {
+ list_add_tail(&default_appraise_rules[i].list,
+ &ima_default_rules);
}
ima_rules = &ima_default_rules;
@@ -373,7 +435,8 @@ enum {
Opt_audit,
Opt_obj_user, Opt_obj_role, Opt_obj_type,
Opt_subj_user, Opt_subj_role, Opt_subj_type,
- Opt_func, Opt_mask, Opt_fsmagic, Opt_uid, Opt_fowner,
+ Opt_func, Opt_mask, Opt_fsmagic,
+ Opt_uid, Opt_euid, Opt_fowner,
Opt_appraise_type, Opt_fsuuid, Opt_permit_directio
};
@@ -394,6 +457,7 @@ static match_table_t policy_tokens = {
{Opt_fsmagic, "fsmagic=%s"},
{Opt_fsuuid, "fsuuid=%s"},
{Opt_uid, "uid=%s"},
+ {Opt_euid, "euid=%s"},
{Opt_fowner, "fowner=%s"},
{Opt_appraise_type, "appraise_type=%s"},
{Opt_permit_directio, "permit_directio"},
@@ -435,6 +499,7 @@ static void ima_log_string(struct audit_buffer *ab, char *key, char *value)
static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
{
struct audit_buffer *ab;
+ char *from;
char *p;
int result = 0;
@@ -525,18 +590,23 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
if (entry->mask)
result = -EINVAL;
- if ((strcmp(args[0].from, "MAY_EXEC")) == 0)
+ from = args[0].from;
+ if (*from == '^')
+ from++;
+
+ if ((strcmp(from, "MAY_EXEC")) == 0)
entry->mask = MAY_EXEC;
- else if (strcmp(args[0].from, "MAY_WRITE") == 0)
+ else if (strcmp(from, "MAY_WRITE") == 0)
entry->mask = MAY_WRITE;
- else if (strcmp(args[0].from, "MAY_READ") == 0)
+ else if (strcmp(from, "MAY_READ") == 0)
entry->mask = MAY_READ;
- else if (strcmp(args[0].from, "MAY_APPEND") == 0)
+ else if (strcmp(from, "MAY_APPEND") == 0)
entry->mask = MAY_APPEND;
else
result = -EINVAL;
if (!result)
- entry->flags |= IMA_MASK;
+ entry->flags |= (*args[0].from == '^')
+ ? IMA_INMASK : IMA_MASK;
break;
case Opt_fsmagic:
ima_log_string(ab, "fsmagic", args[0].from);
@@ -566,6 +636,9 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
break;
case Opt_uid:
ima_log_string(ab, "uid", args[0].from);
+ case Opt_euid:
+ if (token == Opt_euid)
+ ima_log_string(ab, "euid", args[0].from);
if (uid_valid(entry->uid)) {
result = -EINVAL;
@@ -574,11 +647,14 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
result = kstrtoul(args[0].from, 10, &lnum);
if (!result) {
- entry->uid = make_kuid(current_user_ns(), (uid_t)lnum);
- if (!uid_valid(entry->uid) || (((uid_t)lnum) != lnum))
+ entry->uid = make_kuid(current_user_ns(),
+ (uid_t) lnum);
+ if (!uid_valid(entry->uid) ||
+ (uid_t)lnum != lnum)
result = -EINVAL;
else
- entry->flags |= IMA_UID;
+ entry->flags |= (token == Opt_uid)
+ ? IMA_UID : IMA_EUID;
}
break;
case Opt_fowner:
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index bcfc36cbde6a..2934e3d377f1 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -70,7 +70,8 @@ static void ima_show_template_data_ascii(struct seq_file *m,
enum data_formats datafmt,
struct ima_field_data *field_data)
{
- u8 *buf_ptr = field_data->data, buflen = field_data->len;
+ u8 *buf_ptr = field_data->data;
+ u32 buflen = field_data->len;
switch (datafmt) {
case DATA_FMT_DIGEST_WITH_ALGO:
@@ -195,9 +196,7 @@ static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
/*
* This function writes the digest of an event (with size limit).
*/
-int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventdigest_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
struct {
@@ -211,25 +210,25 @@ int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file,
memset(&hash, 0, sizeof(hash));
- if (!iint) /* recording a violation. */
+ if (event_data->violation) /* recording a violation. */
goto out;
- if (ima_template_hash_algo_allowed(iint->ima_hash->algo)) {
- cur_digest = iint->ima_hash->digest;
- cur_digestsize = iint->ima_hash->length;
+ if (ima_template_hash_algo_allowed(event_data->iint->ima_hash->algo)) {
+ cur_digest = event_data->iint->ima_hash->digest;
+ cur_digestsize = event_data->iint->ima_hash->length;
goto out;
}
- if (!file) /* missing info to re-calculate the digest */
+ if (!event_data->file) /* missing info to re-calculate the digest */
return -EINVAL;
- inode = file_inode(file);
+ inode = file_inode(event_data->file);
hash.hdr.algo = ima_template_hash_algo_allowed(ima_hash_algo) ?
ima_hash_algo : HASH_ALGO_SHA1;
- result = ima_calc_file_hash(file, &hash.hdr);
+ result = ima_calc_file_hash(event_data->file, &hash.hdr);
if (result) {
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
- filename, "collect_data",
+ event_data->filename, "collect_data",
"failed", result, 0);
return result;
}
@@ -243,48 +242,43 @@ out:
/*
* This function writes the digest of an event (without size limit).
*/
-int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
- struct file *file, const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value,
- int xattr_len, struct ima_field_data *field_data)
+int ima_eventdigest_ng_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data)
{
u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1;
u32 cur_digestsize = 0;
- /* If iint is NULL, we are recording a violation. */
- if (!iint)
+ if (event_data->violation) /* recording a violation. */
goto out;
- cur_digest = iint->ima_hash->digest;
- cur_digestsize = iint->ima_hash->length;
+ cur_digest = event_data->iint->ima_hash->digest;
+ cur_digestsize = event_data->iint->ima_hash->length;
- hash_algo = iint->ima_hash->algo;
+ hash_algo = event_data->iint->ima_hash->algo;
out:
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
hash_algo, field_data);
}
-static int ima_eventname_init_common(struct integrity_iint_cache *iint,
- struct file *file,
- const unsigned char *filename,
+static int ima_eventname_init_common(struct ima_event_data *event_data,
struct ima_field_data *field_data,
bool size_limit)
{
const char *cur_filename = NULL;
u32 cur_filename_len = 0;
- BUG_ON(filename == NULL && file == NULL);
+ BUG_ON(event_data->filename == NULL && event_data->file == NULL);
- if (filename) {
- cur_filename = filename;
- cur_filename_len = strlen(filename);
+ if (event_data->filename) {
+ cur_filename = event_data->filename;
+ cur_filename_len = strlen(event_data->filename);
if (!size_limit || cur_filename_len <= IMA_EVENT_NAME_LEN_MAX)
goto out;
}
- if (file) {
- cur_filename = file->f_path.dentry->d_name.name;
+ if (event_data->file) {
+ cur_filename = event_data->file->f_path.dentry->d_name.name;
cur_filename_len = strlen(cur_filename);
} else
/*
@@ -300,36 +294,30 @@ out:
/*
* This function writes the name of an event (with size limit).
*/
-int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventname_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
- return ima_eventname_init_common(iint, file, filename,
- field_data, true);
+ return ima_eventname_init_common(event_data, field_data, true);
}
/*
* This function writes the name of an event (without size limit).
*/
-int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventname_ng_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
- return ima_eventname_init_common(iint, file, filename,
- field_data, false);
+ return ima_eventname_init_common(event_data, field_data, false);
}
/*
* ima_eventsig_init - include the file signature as part of the template data
*/
-int ima_eventsig_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data)
{
enum data_formats fmt = DATA_FMT_HEX;
+ struct evm_ima_xattr_data *xattr_value = event_data->xattr_value;
+ int xattr_len = event_data->xattr_len;
int rc = 0;
if ((!xattr_value) || (xattr_value->type != EVM_IMA_XATTR_DIGSIG))
diff --git a/security/integrity/ima/ima_template_lib.h b/security/integrity/ima/ima_template_lib.h
index 63f6b52cb1c2..c344530c1d69 100644
--- a/security/integrity/ima/ima_template_lib.h
+++ b/security/integrity/ima/ima_template_lib.h
@@ -26,24 +26,14 @@ void ima_show_template_string(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
struct ima_field_data *field_data);
-int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventdigest_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
-int ima_eventname_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventname_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
-int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
- struct file *file, const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value,
- int xattr_len, struct ima_field_data *field_data);
-int ima_eventname_ng_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventdigest_ng_init(struct ima_event_data *event_data,
+ struct ima_field_data *field_data);
+int ima_eventname_ng_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
-int ima_eventsig_init(struct integrity_iint_cache *iint, struct file *file,
- const unsigned char *filename,
- struct evm_ima_xattr_data *xattr_value, int xattr_len,
+int ima_eventsig_init(struct ima_event_data *event_data,
struct ima_field_data *field_data);
#endif /* __LINUX_IMA_TEMPLATE_LIB_H */
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 0fc9519fefa9..9c6168709d3b 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -135,7 +135,7 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen);
int __init integrity_init_keyring(const unsigned int id);
-int __init integrity_load_x509(const unsigned int id, char *path);
+int __init integrity_load_x509(const unsigned int id, const char *path);
#else
static inline int integrity_digsig_verify(const unsigned int id,
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 347896548ad3..25430a3aa7f7 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -31,30 +31,21 @@ static long compat_keyctl_instantiate_key_iov(
key_serial_t ringid)
{
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+ struct iov_iter from;
long ret;
- if (!_payload_iov || !ioc)
- goto no_payload;
+ if (!_payload_iov)
+ ioc = 0;
- ret = compat_rw_copy_check_uvector(WRITE, _payload_iov, ioc,
- ARRAY_SIZE(iovstack),
- iovstack, &iov);
+ ret = compat_import_iovec(WRITE, _payload_iov, ioc,
+ ARRAY_SIZE(iovstack), &iov,
+ &from);
if (ret < 0)
- goto err;
- if (ret == 0)
- goto no_payload_free;
-
- ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
-err:
- if (iov != iovstack)
- kfree(iov);
- return ret;
+ return ret;
-no_payload_free:
- if (iov != iovstack)
- kfree(iov);
-no_payload:
- return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
+ ret = keyctl_instantiate_key_common(id, &from, ringid);
+ kfree(iov);
+ return ret;
}
/*
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 200e37867336..5105c2c2da75 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -243,9 +243,10 @@ extern long keyctl_instantiate_key_iov(key_serial_t,
unsigned, key_serial_t);
extern long keyctl_invalidate_key(key_serial_t);
+struct iov_iter;
extern long keyctl_instantiate_key_common(key_serial_t,
- const struct iovec *,
- unsigned, size_t, key_serial_t);
+ struct iov_iter *,
+ key_serial_t);
#ifdef CONFIG_PERSISTENT_KEYRINGS
extern long keyctl_get_persistent(uid_t, key_serial_t);
extern unsigned persistent_keyring_expiry;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 4743d71e4aa6..0b9ec78a7a7a 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -998,21 +998,6 @@ static int keyctl_change_reqkey_auth(struct key *key)
}
/*
- * Copy the iovec data from userspace
- */
-static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
- unsigned ioc)
-{
- for (; ioc > 0; ioc--) {
- if (copy_from_user(buffer, iov->iov_base, iov->iov_len) != 0)
- return -EFAULT;
- buffer += iov->iov_len;
- iov++;
- }
- return 0;
-}
-
-/*
* Instantiate a key with the specified payload and link the key into the
* destination keyring if one is given.
*
@@ -1022,20 +1007,21 @@ static long copy_from_user_iovec(void *buffer, const struct iovec *iov,
* If successful, 0 will be returned.
*/
long keyctl_instantiate_key_common(key_serial_t id,
- const struct iovec *payload_iov,
- unsigned ioc,
- size_t plen,
+ struct iov_iter *from,
key_serial_t ringid)
{
const struct cred *cred = current_cred();
struct request_key_auth *rka;
struct key *instkey, *dest_keyring;
+ size_t plen = from ? iov_iter_count(from) : 0;
void *payload;
long ret;
- bool vm = false;
kenter("%d,,%zu,%d", id, plen, ringid);
+ if (!plen)
+ from = NULL;
+
ret = -EINVAL;
if (plen > 1024 * 1024 - 1)
goto error;
@@ -1054,20 +1040,19 @@ long keyctl_instantiate_key_common(key_serial_t id,
/* pull the payload in if one was supplied */
payload = NULL;
- if (payload_iov) {
+ if (from) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
if (!payload) {
if (plen <= PAGE_SIZE)
goto error;
- vm = true;
payload = vmalloc(plen);
if (!payload)
goto error;
}
- ret = copy_from_user_iovec(payload, payload_iov, ioc);
- if (ret < 0)
+ ret = -EFAULT;
+ if (copy_from_iter(payload, plen, from) != plen)
goto error2;
}
@@ -1089,10 +1074,7 @@ long keyctl_instantiate_key_common(key_serial_t id,
keyctl_change_reqkey_auth(NULL);
error2:
- if (!vm)
- kfree(payload);
- else
- vfree(payload);
+ kvfree(payload);
error:
return ret;
}
@@ -1112,15 +1094,19 @@ long keyctl_instantiate_key(key_serial_t id,
key_serial_t ringid)
{
if (_payload && plen) {
- struct iovec iov[1] = {
- [0].iov_base = (void __user *)_payload,
- [0].iov_len = plen
- };
+ struct iovec iov;
+ struct iov_iter from;
+ int ret;
- return keyctl_instantiate_key_common(id, iov, 1, plen, ringid);
+ ret = import_single_range(WRITE, (void __user *)_payload, plen,
+ &iov, &from);
+ if (unlikely(ret))
+ return ret;
+
+ return keyctl_instantiate_key_common(id, &from, ringid);
}
- return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
+ return keyctl_instantiate_key_common(id, NULL, ringid);
}
/*
@@ -1138,29 +1124,19 @@ long keyctl_instantiate_key_iov(key_serial_t id,
key_serial_t ringid)
{
struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+ struct iov_iter from;
long ret;
- if (!_payload_iov || !ioc)
- goto no_payload;
+ if (!_payload_iov)
+ ioc = 0;
- ret = rw_copy_check_uvector(WRITE, _payload_iov, ioc,
- ARRAY_SIZE(iovstack), iovstack, &iov);
+ ret = import_iovec(WRITE, _payload_iov, ioc,
+ ARRAY_SIZE(iovstack), &iov, &from);
if (ret < 0)
- goto err;
- if (ret == 0)
- goto no_payload_free;
-
- ret = keyctl_instantiate_key_common(id, iov, ioc, ret, ringid);
-err:
- if (iov != iovstack)
- kfree(iov);
+ return ret;
+ ret = keyctl_instantiate_key_common(id, &from, ringid);
+ kfree(iov);
return ret;
-
-no_payload_free:
- if (iov != iovstack)
- kfree(iov);
-no_payload:
- return keyctl_instantiate_key_common(id, NULL, 0, 0, ringid);
}
/*
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 07fc99724d41..4ed98107ace3 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -211,7 +211,7 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr,
static void dump_common_audit_data(struct audit_buffer *ab,
struct common_audit_data *a)
{
- struct task_struct *tsk = current;
+ char comm[sizeof(current->comm)];
/*
* To keep stack sizes in check force programers to notice if they
@@ -220,8 +220,8 @@ static void dump_common_audit_data(struct audit_buffer *ab,
*/
BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2);
- audit_log_format(ab, " pid=%d comm=", task_pid_nr(tsk));
- audit_log_untrustedstring(ab, tsk->comm);
+ audit_log_format(ab, " pid=%d comm=", task_pid_nr(current));
+ audit_log_untrustedstring(ab, memcpy(comm, current->comm, sizeof(comm)));
switch (a->type) {
case LSM_AUDIT_DATA_NONE:
@@ -237,7 +237,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
audit_log_d_path(ab, " path=", &a->u.path);
- inode = a->u.path.dentry->d_inode;
+ inode = d_backing_inode(a->u.path.dentry);
if (inode) {
audit_log_format(ab, " dev=");
audit_log_untrustedstring(ab, inode->i_sb->s_id);
@@ -251,7 +251,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, a->u.dentry->d_name.name);
- inode = a->u.dentry->d_inode;
+ inode = d_backing_inode(a->u.dentry);
if (inode) {
audit_log_format(ab, " dev=");
audit_log_untrustedstring(ab, inode->i_sb->s_id);
@@ -276,16 +276,19 @@ static void dump_common_audit_data(struct audit_buffer *ab,
audit_log_format(ab, " ino=%lu", inode->i_ino);
break;
}
- case LSM_AUDIT_DATA_TASK:
- tsk = a->u.tsk;
+ case LSM_AUDIT_DATA_TASK: {
+ struct task_struct *tsk = a->u.tsk;
if (tsk) {
pid_t pid = task_pid_nr(tsk);
if (pid) {
+ char comm[sizeof(tsk->comm)];
audit_log_format(ab, " opid=%d ocomm=", pid);
- audit_log_untrustedstring(ab, tsk->comm);
+ audit_log_untrustedstring(ab,
+ memcpy(comm, tsk->comm, sizeof(comm)));
}
}
break;
+ }
case LSM_AUDIT_DATA_NET:
if (a->u.net->sk) {
struct sock *sk = a->u.net->sk;
diff --git a/security/security.c b/security/security.c
index e81d5bbe7363..595fffab48b0 100644
--- a/security/security.c
+++ b/security/security.c
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/integrity.h>
#include <linux/ima.h>
#include <linux/evm.h>
@@ -29,24 +29,13 @@
#define MAX_LSM_EVM_XATTR 2
+/* Maximum number of letters for an LSM name string */
+#define SECURITY_NAME_MAX 10
+
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
CONFIG_DEFAULT_SECURITY;
-static struct security_operations *security_ops;
-static struct security_operations default_security_ops = {
- .name = "default",
-};
-
-static inline int __init verify(struct security_operations *ops)
-{
- /* verify the security_operations structure exists */
- if (!ops)
- return -EINVAL;
- security_fixup_ops(ops);
- return 0;
-}
-
static void __init do_security_initcalls(void)
{
initcall_t *call;
@@ -64,20 +53,27 @@ static void __init do_security_initcalls(void)
*/
int __init security_init(void)
{
- printk(KERN_INFO "Security Framework initialized\n");
+ pr_info("Security Framework initialized\n");
- security_fixup_ops(&default_security_ops);
- security_ops = &default_security_ops;
+ /*
+ * Always load the capability module.
+ */
+ capability_add_hooks();
+#ifdef CONFIG_SECURITY_YAMA_STACKED
+ /*
+ * If Yama is configured for stacking load it next.
+ */
+ yama_add_hooks();
+#endif
+ /*
+ * Load the chosen module if there is one.
+ * This will also find yama if it is stacking
+ */
do_security_initcalls();
return 0;
}
-void reset_security_ops(void)
-{
- security_ops = &default_security_ops;
-}
-
/* Save user chosen LSM */
static int __init choose_lsm(char *str)
{
@@ -88,7 +84,7 @@ __setup("security=", choose_lsm);
/**
* security_module_enable - Load given security module on boot ?
- * @ops: a pointer to the struct security_operations that is to be checked.
+ * @module: the name of the module
*
* Each LSM must pass this method before registering its own operations
* to avoid security registration races. This method may also be used
@@ -100,84 +96,76 @@ __setup("security=", choose_lsm);
* choose an alternate LSM at boot time.
* Otherwise, return false.
*/
-int __init security_module_enable(struct security_operations *ops)
+int __init security_module_enable(const char *module)
{
- return !strcmp(ops->name, chosen_lsm);
+ return !strcmp(module, chosen_lsm);
}
-/**
- * register_security - registers a security framework with the kernel
- * @ops: a pointer to the struct security_options that is to be registered
+/*
+ * Hook list operation macros.
*
- * This function allows a security module to register itself with the
- * kernel security subsystem. Some rudimentary checking is done on the @ops
- * value passed to this function. You'll need to check first if your LSM
- * is allowed to register its @ops by calling security_module_enable(@ops).
+ * call_void_hook:
+ * This is a hook that does not return a value.
*
- * If there is already a security module registered with the kernel,
- * an error will be returned. Otherwise %0 is returned on success.
+ * call_int_hook:
+ * This is a hook that returns a value.
*/
-int __init register_security(struct security_operations *ops)
-{
- if (verify(ops)) {
- printk(KERN_DEBUG "%s could not verify "
- "security_operations structure.\n", __func__);
- return -EINVAL;
- }
-
- if (security_ops != &default_security_ops)
- return -EAGAIN;
- security_ops = ops;
-
- return 0;
-}
+#define call_void_hook(FUNC, ...) \
+ do { \
+ struct security_hook_list *P; \
+ \
+ list_for_each_entry(P, &security_hook_heads.FUNC, list) \
+ P->hook.FUNC(__VA_ARGS__); \
+ } while (0)
+
+#define call_int_hook(FUNC, IRC, ...) ({ \
+ int RC = IRC; \
+ do { \
+ struct security_hook_list *P; \
+ \
+ list_for_each_entry(P, &security_hook_heads.FUNC, list) { \
+ RC = P->hook.FUNC(__VA_ARGS__); \
+ if (RC != 0) \
+ break; \
+ } \
+ } while (0); \
+ RC; \
+})
/* Security operations */
int security_binder_set_context_mgr(struct task_struct *mgr)
{
- return security_ops->binder_set_context_mgr(mgr);
+ return call_int_hook(binder_set_context_mgr, 0, mgr);
}
int security_binder_transaction(struct task_struct *from,
struct task_struct *to)
{
- return security_ops->binder_transaction(from, to);
+ return call_int_hook(binder_transaction, 0, from, to);
}
int security_binder_transfer_binder(struct task_struct *from,
struct task_struct *to)
{
- return security_ops->binder_transfer_binder(from, to);
+ return call_int_hook(binder_transfer_binder, 0, from, to);
}
int security_binder_transfer_file(struct task_struct *from,
struct task_struct *to, struct file *file)
{
- return security_ops->binder_transfer_file(from, to, file);
+ return call_int_hook(binder_transfer_file, 0, from, to, file);
}
int security_ptrace_access_check(struct task_struct *child, unsigned int mode)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- int rc;
- rc = yama_ptrace_access_check(child, mode);
- if (rc)
- return rc;
-#endif
- return security_ops->ptrace_access_check(child, mode);
+ return call_int_hook(ptrace_access_check, 0, child, mode);
}
int security_ptrace_traceme(struct task_struct *parent)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- int rc;
- rc = yama_ptrace_traceme(parent);
- if (rc)
- return rc;
-#endif
- return security_ops->ptrace_traceme(parent);
+ return call_int_hook(ptrace_traceme, 0, parent);
}
int security_capget(struct task_struct *target,
@@ -185,7 +173,8 @@ int security_capget(struct task_struct *target,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
{
- return security_ops->capget(target, effective, inheritable, permitted);
+ return call_int_hook(capget, 0, target,
+ effective, inheritable, permitted);
}
int security_capset(struct cred *new, const struct cred *old,
@@ -193,57 +182,75 @@ int security_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- return security_ops->capset(new, old,
- effective, inheritable, permitted);
+ return call_int_hook(capset, 0, new, old,
+ effective, inheritable, permitted);
}
int security_capable(const struct cred *cred, struct user_namespace *ns,
int cap)
{
- return security_ops->capable(cred, ns, cap, SECURITY_CAP_AUDIT);
+ return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT);
}
int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
int cap)
{
- return security_ops->capable(cred, ns, cap, SECURITY_CAP_NOAUDIT);
+ return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT);
}
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
{
- return security_ops->quotactl(cmds, type, id, sb);
+ return call_int_hook(quotactl, 0, cmds, type, id, sb);
}
int security_quota_on(struct dentry *dentry)
{
- return security_ops->quota_on(dentry);
+ return call_int_hook(quota_on, 0, dentry);
}
int security_syslog(int type)
{
- return security_ops->syslog(type);
+ return call_int_hook(syslog, 0, type);
}
int security_settime(const struct timespec *ts, const struct timezone *tz)
{
- return security_ops->settime(ts, tz);
+ return call_int_hook(settime, 0, ts, tz);
}
int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
{
- return security_ops->vm_enough_memory(mm, pages);
+ struct security_hook_list *hp;
+ int cap_sys_admin = 1;
+ int rc;
+
+ /*
+ * The module will respond with a positive value if
+ * it thinks the __vm_enough_memory() call should be
+ * made with the cap_sys_admin set. If all of the modules
+ * agree that it should be set it will. If any module
+ * thinks it should not be set it won't.
+ */
+ list_for_each_entry(hp, &security_hook_heads.vm_enough_memory, list) {
+ rc = hp->hook.vm_enough_memory(mm, pages);
+ if (rc <= 0) {
+ cap_sys_admin = 0;
+ break;
+ }
+ }
+ return __vm_enough_memory(mm, pages, cap_sys_admin);
}
int security_bprm_set_creds(struct linux_binprm *bprm)
{
- return security_ops->bprm_set_creds(bprm);
+ return call_int_hook(bprm_set_creds, 0, bprm);
}
int security_bprm_check(struct linux_binprm *bprm)
{
int ret;
- ret = security_ops->bprm_check_security(bprm);
+ ret = call_int_hook(bprm_check_security, 0, bprm);
if (ret)
return ret;
return ima_bprm_check(bprm);
@@ -251,69 +258,69 @@ int security_bprm_check(struct linux_binprm *bprm)
void security_bprm_committing_creds(struct linux_binprm *bprm)
{
- security_ops->bprm_committing_creds(bprm);
+ call_void_hook(bprm_committing_creds, bprm);
}
void security_bprm_committed_creds(struct linux_binprm *bprm)
{
- security_ops->bprm_committed_creds(bprm);
+ call_void_hook(bprm_committed_creds, bprm);
}
int security_bprm_secureexec(struct linux_binprm *bprm)
{
- return security_ops->bprm_secureexec(bprm);
+ return call_int_hook(bprm_secureexec, 0, bprm);
}
int security_sb_alloc(struct super_block *sb)
{
- return security_ops->sb_alloc_security(sb);
+ return call_int_hook(sb_alloc_security, 0, sb);
}
void security_sb_free(struct super_block *sb)
{
- security_ops->sb_free_security(sb);
+ call_void_hook(sb_free_security, sb);
}
int security_sb_copy_data(char *orig, char *copy)
{
- return security_ops->sb_copy_data(orig, copy);
+ return call_int_hook(sb_copy_data, 0, orig, copy);
}
EXPORT_SYMBOL(security_sb_copy_data);
int security_sb_remount(struct super_block *sb, void *data)
{
- return security_ops->sb_remount(sb, data);
+ return call_int_hook(sb_remount, 0, sb, data);
}
int security_sb_kern_mount(struct super_block *sb, int flags, void *data)
{
- return security_ops->sb_kern_mount(sb, flags, data);
+ return call_int_hook(sb_kern_mount, 0, sb, flags, data);
}
int security_sb_show_options(struct seq_file *m, struct super_block *sb)
{
- return security_ops->sb_show_options(m, sb);
+ return call_int_hook(sb_show_options, 0, m, sb);
}
int security_sb_statfs(struct dentry *dentry)
{
- return security_ops->sb_statfs(dentry);
+ return call_int_hook(sb_statfs, 0, dentry);
}
int security_sb_mount(const char *dev_name, struct path *path,
const char *type, unsigned long flags, void *data)
{
- return security_ops->sb_mount(dev_name, path, type, flags, data);
+ return call_int_hook(sb_mount, 0, dev_name, path, type, flags, data);
}
int security_sb_umount(struct vfsmount *mnt, int flags)
{
- return security_ops->sb_umount(mnt, flags);
+ return call_int_hook(sb_umount, 0, mnt, flags);
}
int security_sb_pivotroot(struct path *old_path, struct path *new_path)
{
- return security_ops->sb_pivotroot(old_path, new_path);
+ return call_int_hook(sb_pivotroot, 0, old_path, new_path);
}
int security_sb_set_mnt_opts(struct super_block *sb,
@@ -321,42 +328,43 @@ int security_sb_set_mnt_opts(struct super_block *sb,
unsigned long kern_flags,
unsigned long *set_kern_flags)
{
- return security_ops->sb_set_mnt_opts(sb, opts, kern_flags,
- set_kern_flags);
+ return call_int_hook(sb_set_mnt_opts,
+ opts->num_mnt_opts ? -EOPNOTSUPP : 0, sb,
+ opts, kern_flags, set_kern_flags);
}
EXPORT_SYMBOL(security_sb_set_mnt_opts);
int security_sb_clone_mnt_opts(const struct super_block *oldsb,
struct super_block *newsb)
{
- return security_ops->sb_clone_mnt_opts(oldsb, newsb);
+ return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb);
}
EXPORT_SYMBOL(security_sb_clone_mnt_opts);
int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts)
{
- return security_ops->sb_parse_opts_str(options, opts);
+ return call_int_hook(sb_parse_opts_str, 0, options, opts);
}
EXPORT_SYMBOL(security_sb_parse_opts_str);
int security_inode_alloc(struct inode *inode)
{
inode->i_security = NULL;
- return security_ops->inode_alloc_security(inode);
+ return call_int_hook(inode_alloc_security, 0, inode);
}
void security_inode_free(struct inode *inode)
{
integrity_inode_free(inode);
- security_ops->inode_free_security(inode);
+ call_void_hook(inode_free_security, inode);
}
int security_dentry_init_security(struct dentry *dentry, int mode,
struct qstr *name, void **ctx,
u32 *ctxlen)
{
- return security_ops->dentry_init_security(dentry, mode, name,
- ctx, ctxlen);
+ return call_int_hook(dentry_init_security, -EOPNOTSUPP, dentry, mode,
+ name, ctx, ctxlen);
}
EXPORT_SYMBOL(security_dentry_init_security);
@@ -372,11 +380,11 @@ int security_inode_init_security(struct inode *inode, struct inode *dir,
return 0;
if (!initxattrs)
- return security_ops->inode_init_security(inode, dir, qstr,
+ return call_int_hook(inode_init_security, 0, inode, dir, qstr,
NULL, NULL, NULL);
memset(new_xattrs, 0, sizeof(new_xattrs));
lsm_xattr = new_xattrs;
- ret = security_ops->inode_init_security(inode, dir, qstr,
+ ret = call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, qstr,
&lsm_xattr->name,
&lsm_xattr->value,
&lsm_xattr->value_len);
@@ -401,8 +409,8 @@ int security_old_inode_init_security(struct inode *inode, struct inode *dir,
{
if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
- return security_ops->inode_init_security(inode, dir, qstr, name, value,
- len);
+ return call_int_hook(inode_init_security, 0, inode, dir, qstr,
+ name, value, len);
}
EXPORT_SYMBOL(security_old_inode_init_security);
@@ -410,95 +418,95 @@ EXPORT_SYMBOL(security_old_inode_init_security);
int security_path_mknod(struct path *dir, struct dentry *dentry, umode_t mode,
unsigned int dev)
{
- if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
return 0;
- return security_ops->path_mknod(dir, dentry, mode, dev);
+ return call_int_hook(path_mknod, 0, dir, dentry, mode, dev);
}
EXPORT_SYMBOL(security_path_mknod);
int security_path_mkdir(struct path *dir, struct dentry *dentry, umode_t mode)
{
- if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
return 0;
- return security_ops->path_mkdir(dir, dentry, mode);
+ return call_int_hook(path_mkdir, 0, dir, dentry, mode);
}
EXPORT_SYMBOL(security_path_mkdir);
int security_path_rmdir(struct path *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
return 0;
- return security_ops->path_rmdir(dir, dentry);
+ return call_int_hook(path_rmdir, 0, dir, dentry);
}
int security_path_unlink(struct path *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
return 0;
- return security_ops->path_unlink(dir, dentry);
+ return call_int_hook(path_unlink, 0, dir, dentry);
}
EXPORT_SYMBOL(security_path_unlink);
int security_path_symlink(struct path *dir, struct dentry *dentry,
const char *old_name)
{
- if (unlikely(IS_PRIVATE(dir->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry))))
return 0;
- return security_ops->path_symlink(dir, dentry, old_name);
+ return call_int_hook(path_symlink, 0, dir, dentry, old_name);
}
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
struct dentry *new_dentry)
{
- if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
return 0;
- return security_ops->path_link(old_dentry, new_dir, new_dentry);
+ return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry);
}
int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
struct path *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
- if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
- (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
+ (d_is_positive(new_dentry) && IS_PRIVATE(d_backing_inode(new_dentry)))))
return 0;
if (flags & RENAME_EXCHANGE) {
- int err = security_ops->path_rename(new_dir, new_dentry,
- old_dir, old_dentry);
+ int err = call_int_hook(path_rename, 0, new_dir, new_dentry,
+ old_dir, old_dentry);
if (err)
return err;
}
- return security_ops->path_rename(old_dir, old_dentry, new_dir,
- new_dentry);
+ return call_int_hook(path_rename, 0, old_dir, old_dentry, new_dir,
+ new_dentry);
}
EXPORT_SYMBOL(security_path_rename);
int security_path_truncate(struct path *path)
{
- if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
return 0;
- return security_ops->path_truncate(path);
+ return call_int_hook(path_truncate, 0, path);
}
int security_path_chmod(struct path *path, umode_t mode)
{
- if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
return 0;
- return security_ops->path_chmod(path, mode);
+ return call_int_hook(path_chmod, 0, path, mode);
}
int security_path_chown(struct path *path, kuid_t uid, kgid_t gid)
{
- if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
return 0;
- return security_ops->path_chown(path, uid, gid);
+ return call_int_hook(path_chown, 0, path, uid, gid);
}
int security_path_chroot(struct path *path)
{
- return security_ops->path_chroot(path);
+ return call_int_hook(path_chroot, 0, path);
}
#endif
@@ -506,23 +514,23 @@ int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_create(dir, dentry, mode);
+ return call_int_hook(inode_create, 0, dir, dentry, mode);
}
EXPORT_SYMBOL_GPL(security_inode_create);
int security_inode_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
- if (unlikely(IS_PRIVATE(old_dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry))))
return 0;
- return security_ops->inode_link(old_dentry, dir, new_dentry);
+ return call_int_hook(inode_link, 0, old_dentry, dir, new_dentry);
}
int security_inode_unlink(struct inode *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- return security_ops->inode_unlink(dir, dentry);
+ return call_int_hook(inode_unlink, 0, dir, dentry);
}
int security_inode_symlink(struct inode *dir, struct dentry *dentry,
@@ -530,89 +538,90 @@ int security_inode_symlink(struct inode *dir, struct dentry *dentry,
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_symlink(dir, dentry, old_name);
+ return call_int_hook(inode_symlink, 0, dir, dentry, old_name);
}
int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_mkdir(dir, dentry, mode);
+ return call_int_hook(inode_mkdir, 0, dir, dentry, mode);
}
EXPORT_SYMBOL_GPL(security_inode_mkdir);
int security_inode_rmdir(struct inode *dir, struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- return security_ops->inode_rmdir(dir, dentry);
+ return call_int_hook(inode_rmdir, 0, dir, dentry);
}
int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
{
if (unlikely(IS_PRIVATE(dir)))
return 0;
- return security_ops->inode_mknod(dir, dentry, mode, dev);
+ return call_int_hook(inode_mknod, 0, dir, dentry, mode, dev);
}
int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
unsigned int flags)
{
- if (unlikely(IS_PRIVATE(old_dentry->d_inode) ||
- (new_dentry->d_inode && IS_PRIVATE(new_dentry->d_inode))))
+ if (unlikely(IS_PRIVATE(d_backing_inode(old_dentry)) ||
+ (d_is_positive(new_dentry) && IS_PRIVATE(d_backing_inode(new_dentry)))))
return 0;
if (flags & RENAME_EXCHANGE) {
- int err = security_ops->inode_rename(new_dir, new_dentry,
+ int err = call_int_hook(inode_rename, 0, new_dir, new_dentry,
old_dir, old_dentry);
if (err)
return err;
}
- return security_ops->inode_rename(old_dir, old_dentry,
+ return call_int_hook(inode_rename, 0, old_dir, old_dentry,
new_dir, new_dentry);
}
int security_inode_readlink(struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- return security_ops->inode_readlink(dentry);
+ return call_int_hook(inode_readlink, 0, dentry);
}
-int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
+int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
+ bool rcu)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(inode)))
return 0;
- return security_ops->inode_follow_link(dentry, nd);
+ return call_int_hook(inode_follow_link, 0, dentry, inode, rcu);
}
int security_inode_permission(struct inode *inode, int mask)
{
if (unlikely(IS_PRIVATE(inode)))
return 0;
- return security_ops->inode_permission(inode, mask);
+ return call_int_hook(inode_permission, 0, inode, mask);
}
int security_inode_setattr(struct dentry *dentry, struct iattr *attr)
{
int ret;
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- ret = security_ops->inode_setattr(dentry, attr);
+ ret = call_int_hook(inode_setattr, 0, dentry, attr);
if (ret)
return ret;
return evm_inode_setattr(dentry, attr);
}
EXPORT_SYMBOL_GPL(security_inode_setattr);
-int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+int security_inode_getattr(const struct path *path)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(path->dentry))))
return 0;
- return security_ops->inode_getattr(mnt, dentry);
+ return call_int_hook(inode_getattr, 0, path);
}
int security_inode_setxattr(struct dentry *dentry, const char *name,
@@ -620,9 +629,17 @@ int security_inode_setxattr(struct dentry *dentry, const char *name,
{
int ret;
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- ret = security_ops->inode_setxattr(dentry, name, value, size, flags);
+ /*
+ * SELinux and Smack integrate the cap call,
+ * so assume that all LSMs supplying this call do so.
+ */
+ ret = call_int_hook(inode_setxattr, 1, dentry, name, value, size,
+ flags);
+
+ if (ret == 1)
+ ret = cap_inode_setxattr(dentry, name, value, size, flags);
if (ret)
return ret;
ret = ima_inode_setxattr(dentry, name, value, size);
@@ -634,33 +651,39 @@ int security_inode_setxattr(struct dentry *dentry, const char *name,
void security_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return;
- security_ops->inode_post_setxattr(dentry, name, value, size, flags);
+ call_void_hook(inode_post_setxattr, dentry, name, value, size, flags);
evm_inode_post_setxattr(dentry, name, value, size);
}
int security_inode_getxattr(struct dentry *dentry, const char *name)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- return security_ops->inode_getxattr(dentry, name);
+ return call_int_hook(inode_getxattr, 0, dentry, name);
}
int security_inode_listxattr(struct dentry *dentry)
{
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- return security_ops->inode_listxattr(dentry);
+ return call_int_hook(inode_listxattr, 0, dentry);
}
int security_inode_removexattr(struct dentry *dentry, const char *name)
{
int ret;
- if (unlikely(IS_PRIVATE(dentry->d_inode)))
+ if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
return 0;
- ret = security_ops->inode_removexattr(dentry, name);
+ /*
+ * SELinux and Smack integrate the cap call,
+ * so assume that all LSMs supplying this call do so.
+ */
+ ret = call_int_hook(inode_removexattr, 1, dentry, name);
+ if (ret == 1)
+ ret = cap_inode_removexattr(dentry, name);
if (ret)
return ret;
ret = ima_inode_removexattr(dentry, name);
@@ -671,46 +694,48 @@ int security_inode_removexattr(struct dentry *dentry, const char *name)
int security_inode_need_killpriv(struct dentry *dentry)
{
- return security_ops->inode_need_killpriv(dentry);
+ return call_int_hook(inode_need_killpriv, 0, dentry);
}
int security_inode_killpriv(struct dentry *dentry)
{
- return security_ops->inode_killpriv(dentry);
+ return call_int_hook(inode_killpriv, 0, dentry);
}
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc)
{
if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
- return security_ops->inode_getsecurity(inode, name, buffer, alloc);
+ return call_int_hook(inode_getsecurity, -EOPNOTSUPP, inode, name,
+ buffer, alloc);
}
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
{
if (unlikely(IS_PRIVATE(inode)))
return -EOPNOTSUPP;
- return security_ops->inode_setsecurity(inode, name, value, size, flags);
+ return call_int_hook(inode_setsecurity, -EOPNOTSUPP, inode, name,
+ value, size, flags);
}
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
{
if (unlikely(IS_PRIVATE(inode)))
return 0;
- return security_ops->inode_listsecurity(inode, buffer, buffer_size);
+ return call_int_hook(inode_listsecurity, 0, inode, buffer, buffer_size);
}
EXPORT_SYMBOL(security_inode_listsecurity);
void security_inode_getsecid(const struct inode *inode, u32 *secid)
{
- security_ops->inode_getsecid(inode, secid);
+ call_void_hook(inode_getsecid, inode, secid);
}
int security_file_permission(struct file *file, int mask)
{
int ret;
- ret = security_ops->file_permission(file, mask);
+ ret = call_int_hook(file_permission, 0, file, mask);
if (ret)
return ret;
@@ -719,17 +744,17 @@ int security_file_permission(struct file *file, int mask)
int security_file_alloc(struct file *file)
{
- return security_ops->file_alloc_security(file);
+ return call_int_hook(file_alloc_security, 0, file);
}
void security_file_free(struct file *file)
{
- security_ops->file_free_security(file);
+ call_void_hook(file_free_security, file);
}
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- return security_ops->file_ioctl(file, cmd, arg);
+ return call_int_hook(file_ioctl, 0, file, cmd, arg);
}
static inline unsigned long mmap_prot(struct file *file, unsigned long prot)
@@ -769,7 +794,7 @@ int security_mmap_file(struct file *file, unsigned long prot,
unsigned long flags)
{
int ret;
- ret = security_ops->mmap_file(file, prot,
+ ret = call_int_hook(mmap_file, 0, file, prot,
mmap_prot(file, prot), flags);
if (ret)
return ret;
@@ -778,46 +803,46 @@ int security_mmap_file(struct file *file, unsigned long prot,
int security_mmap_addr(unsigned long addr)
{
- return security_ops->mmap_addr(addr);
+ return call_int_hook(mmap_addr, 0, addr);
}
int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot,
unsigned long prot)
{
- return security_ops->file_mprotect(vma, reqprot, prot);
+ return call_int_hook(file_mprotect, 0, vma, reqprot, prot);
}
int security_file_lock(struct file *file, unsigned int cmd)
{
- return security_ops->file_lock(file, cmd);
+ return call_int_hook(file_lock, 0, file, cmd);
}
int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
{
- return security_ops->file_fcntl(file, cmd, arg);
+ return call_int_hook(file_fcntl, 0, file, cmd, arg);
}
void security_file_set_fowner(struct file *file)
{
- security_ops->file_set_fowner(file);
+ call_void_hook(file_set_fowner, file);
}
int security_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int sig)
{
- return security_ops->file_send_sigiotask(tsk, fown, sig);
+ return call_int_hook(file_send_sigiotask, 0, tsk, fown, sig);
}
int security_file_receive(struct file *file)
{
- return security_ops->file_receive(file);
+ return call_int_hook(file_receive, 0, file);
}
int security_file_open(struct file *file, const struct cred *cred)
{
int ret;
- ret = security_ops->file_open(file, cred);
+ ret = call_int_hook(file_open, 0, file, cred);
if (ret)
return ret;
@@ -826,52 +851,49 @@ int security_file_open(struct file *file, const struct cred *cred)
int security_task_create(unsigned long clone_flags)
{
- return security_ops->task_create(clone_flags);
+ return call_int_hook(task_create, 0, clone_flags);
}
void security_task_free(struct task_struct *task)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- yama_task_free(task);
-#endif
- security_ops->task_free(task);
+ call_void_hook(task_free, task);
}
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
- return security_ops->cred_alloc_blank(cred, gfp);
+ return call_int_hook(cred_alloc_blank, 0, cred, gfp);
}
void security_cred_free(struct cred *cred)
{
- security_ops->cred_free(cred);
+ call_void_hook(cred_free, cred);
}
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
{
- return security_ops->cred_prepare(new, old, gfp);
+ return call_int_hook(cred_prepare, 0, new, old, gfp);
}
void security_transfer_creds(struct cred *new, const struct cred *old)
{
- security_ops->cred_transfer(new, old);
+ call_void_hook(cred_transfer, new, old);
}
int security_kernel_act_as(struct cred *new, u32 secid)
{
- return security_ops->kernel_act_as(new, secid);
+ return call_int_hook(kernel_act_as, 0, new, secid);
}
int security_kernel_create_files_as(struct cred *new, struct inode *inode)
{
- return security_ops->kernel_create_files_as(new, inode);
+ return call_int_hook(kernel_create_files_as, 0, new, inode);
}
int security_kernel_fw_from_file(struct file *file, char *buf, size_t size)
{
int ret;
- ret = security_ops->kernel_fw_from_file(file, buf, size);
+ ret = call_int_hook(kernel_fw_from_file, 0, file, buf, size);
if (ret)
return ret;
return ima_fw_from_file(file, buf, size);
@@ -880,14 +902,14 @@ EXPORT_SYMBOL_GPL(security_kernel_fw_from_file);
int security_kernel_module_request(char *kmod_name)
{
- return security_ops->kernel_module_request(kmod_name);
+ return call_int_hook(kernel_module_request, 0, kmod_name);
}
int security_kernel_module_from_file(struct file *file)
{
int ret;
- ret = security_ops->kernel_module_from_file(file);
+ ret = call_int_hook(kernel_module_from_file, 0, file);
if (ret)
return ret;
return ima_module_check(file);
@@ -896,259 +918,269 @@ int security_kernel_module_from_file(struct file *file)
int security_task_fix_setuid(struct cred *new, const struct cred *old,
int flags)
{
- return security_ops->task_fix_setuid(new, old, flags);
+ return call_int_hook(task_fix_setuid, 0, new, old, flags);
}
int security_task_setpgid(struct task_struct *p, pid_t pgid)
{
- return security_ops->task_setpgid(p, pgid);
+ return call_int_hook(task_setpgid, 0, p, pgid);
}
int security_task_getpgid(struct task_struct *p)
{
- return security_ops->task_getpgid(p);
+ return call_int_hook(task_getpgid, 0, p);
}
int security_task_getsid(struct task_struct *p)
{
- return security_ops->task_getsid(p);
+ return call_int_hook(task_getsid, 0, p);
}
void security_task_getsecid(struct task_struct *p, u32 *secid)
{
- security_ops->task_getsecid(p, secid);
+ *secid = 0;
+ call_void_hook(task_getsecid, p, secid);
}
EXPORT_SYMBOL(security_task_getsecid);
int security_task_setnice(struct task_struct *p, int nice)
{
- return security_ops->task_setnice(p, nice);
+ return call_int_hook(task_setnice, 0, p, nice);
}
int security_task_setioprio(struct task_struct *p, int ioprio)
{
- return security_ops->task_setioprio(p, ioprio);
+ return call_int_hook(task_setioprio, 0, p, ioprio);
}
int security_task_getioprio(struct task_struct *p)
{
- return security_ops->task_getioprio(p);
+ return call_int_hook(task_getioprio, 0, p);
}
int security_task_setrlimit(struct task_struct *p, unsigned int resource,
struct rlimit *new_rlim)
{
- return security_ops->task_setrlimit(p, resource, new_rlim);
+ return call_int_hook(task_setrlimit, 0, p, resource, new_rlim);
}
int security_task_setscheduler(struct task_struct *p)
{
- return security_ops->task_setscheduler(p);
+ return call_int_hook(task_setscheduler, 0, p);
}
int security_task_getscheduler(struct task_struct *p)
{
- return security_ops->task_getscheduler(p);
+ return call_int_hook(task_getscheduler, 0, p);
}
int security_task_movememory(struct task_struct *p)
{
- return security_ops->task_movememory(p);
+ return call_int_hook(task_movememory, 0, p);
}
int security_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid)
{
- return security_ops->task_kill(p, info, sig, secid);
+ return call_int_hook(task_kill, 0, p, info, sig, secid);
}
int security_task_wait(struct task_struct *p)
{
- return security_ops->task_wait(p);
+ return call_int_hook(task_wait, 0, p);
}
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
-#ifdef CONFIG_SECURITY_YAMA_STACKED
- int rc;
- rc = yama_task_prctl(option, arg2, arg3, arg4, arg5);
- if (rc != -ENOSYS)
- return rc;
-#endif
- return security_ops->task_prctl(option, arg2, arg3, arg4, arg5);
+ int thisrc;
+ int rc = -ENOSYS;
+ struct security_hook_list *hp;
+
+ list_for_each_entry(hp, &security_hook_heads.task_prctl, list) {
+ thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5);
+ if (thisrc != -ENOSYS) {
+ rc = thisrc;
+ if (thisrc != 0)
+ break;
+ }
+ }
+ return rc;
}
void security_task_to_inode(struct task_struct *p, struct inode *inode)
{
- security_ops->task_to_inode(p, inode);
+ call_void_hook(task_to_inode, p, inode);
}
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
{
- return security_ops->ipc_permission(ipcp, flag);
+ return call_int_hook(ipc_permission, 0, ipcp, flag);
}
void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
{
- security_ops->ipc_getsecid(ipcp, secid);
+ *secid = 0;
+ call_void_hook(ipc_getsecid, ipcp, secid);
}
int security_msg_msg_alloc(struct msg_msg *msg)
{
- return security_ops->msg_msg_alloc_security(msg);
+ return call_int_hook(msg_msg_alloc_security, 0, msg);
}
void security_msg_msg_free(struct msg_msg *msg)
{
- security_ops->msg_msg_free_security(msg);
+ call_void_hook(msg_msg_free_security, msg);
}
int security_msg_queue_alloc(struct msg_queue *msq)
{
- return security_ops->msg_queue_alloc_security(msq);
+ return call_int_hook(msg_queue_alloc_security, 0, msq);
}
void security_msg_queue_free(struct msg_queue *msq)
{
- security_ops->msg_queue_free_security(msq);
+ call_void_hook(msg_queue_free_security, msq);
}
int security_msg_queue_associate(struct msg_queue *msq, int msqflg)
{
- return security_ops->msg_queue_associate(msq, msqflg);
+ return call_int_hook(msg_queue_associate, 0, msq, msqflg);
}
int security_msg_queue_msgctl(struct msg_queue *msq, int cmd)
{
- return security_ops->msg_queue_msgctl(msq, cmd);
+ return call_int_hook(msg_queue_msgctl, 0, msq, cmd);
}
int security_msg_queue_msgsnd(struct msg_queue *msq,
struct msg_msg *msg, int msqflg)
{
- return security_ops->msg_queue_msgsnd(msq, msg, msqflg);
+ return call_int_hook(msg_queue_msgsnd, 0, msq, msg, msqflg);
}
int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
struct task_struct *target, long type, int mode)
{
- return security_ops->msg_queue_msgrcv(msq, msg, target, type, mode);
+ return call_int_hook(msg_queue_msgrcv, 0, msq, msg, target, type, mode);
}
int security_shm_alloc(struct shmid_kernel *shp)
{
- return security_ops->shm_alloc_security(shp);
+ return call_int_hook(shm_alloc_security, 0, shp);
}
void security_shm_free(struct shmid_kernel *shp)
{
- security_ops->shm_free_security(shp);
+ call_void_hook(shm_free_security, shp);
}
int security_shm_associate(struct shmid_kernel *shp, int shmflg)
{
- return security_ops->shm_associate(shp, shmflg);
+ return call_int_hook(shm_associate, 0, shp, shmflg);
}
int security_shm_shmctl(struct shmid_kernel *shp, int cmd)
{
- return security_ops->shm_shmctl(shp, cmd);
+ return call_int_hook(shm_shmctl, 0, shp, cmd);
}
int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg)
{
- return security_ops->shm_shmat(shp, shmaddr, shmflg);
+ return call_int_hook(shm_shmat, 0, shp, shmaddr, shmflg);
}
int security_sem_alloc(struct sem_array *sma)
{
- return security_ops->sem_alloc_security(sma);
+ return call_int_hook(sem_alloc_security, 0, sma);
}
void security_sem_free(struct sem_array *sma)
{
- security_ops->sem_free_security(sma);
+ call_void_hook(sem_free_security, sma);
}
int security_sem_associate(struct sem_array *sma, int semflg)
{
- return security_ops->sem_associate(sma, semflg);
+ return call_int_hook(sem_associate, 0, sma, semflg);
}
int security_sem_semctl(struct sem_array *sma, int cmd)
{
- return security_ops->sem_semctl(sma, cmd);
+ return call_int_hook(sem_semctl, 0, sma, cmd);
}
int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
unsigned nsops, int alter)
{
- return security_ops->sem_semop(sma, sops, nsops, alter);
+ return call_int_hook(sem_semop, 0, sma, sops, nsops, alter);
}
void security_d_instantiate(struct dentry *dentry, struct inode *inode)
{
if (unlikely(inode && IS_PRIVATE(inode)))
return;
- security_ops->d_instantiate(dentry, inode);
+ call_void_hook(d_instantiate, dentry, inode);
}
EXPORT_SYMBOL(security_d_instantiate);
int security_getprocattr(struct task_struct *p, char *name, char **value)
{
- return security_ops->getprocattr(p, name, value);
+ return call_int_hook(getprocattr, -EINVAL, p, name, value);
}
int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
{
- return security_ops->setprocattr(p, name, value, size);
+ return call_int_hook(setprocattr, -EINVAL, p, name, value, size);
}
int security_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- return security_ops->netlink_send(sk, skb);
+ return call_int_hook(netlink_send, 0, sk, skb);
}
int security_ismaclabel(const char *name)
{
- return security_ops->ismaclabel(name);
+ return call_int_hook(ismaclabel, 0, name);
}
EXPORT_SYMBOL(security_ismaclabel);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
{
- return security_ops->secid_to_secctx(secid, secdata, seclen);
+ return call_int_hook(secid_to_secctx, -EOPNOTSUPP, secid, secdata,
+ seclen);
}
EXPORT_SYMBOL(security_secid_to_secctx);
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
- return security_ops->secctx_to_secid(secdata, seclen, secid);
+ *secid = 0;
+ return call_int_hook(secctx_to_secid, 0, secdata, seclen, secid);
}
EXPORT_SYMBOL(security_secctx_to_secid);
void security_release_secctx(char *secdata, u32 seclen)
{
- security_ops->release_secctx(secdata, seclen);
+ call_void_hook(release_secctx, secdata, seclen);
}
EXPORT_SYMBOL(security_release_secctx);
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
- return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
+ return call_int_hook(inode_notifysecctx, 0, inode, ctx, ctxlen);
}
EXPORT_SYMBOL(security_inode_notifysecctx);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
{
- return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
+ return call_int_hook(inode_setsecctx, 0, dentry, ctx, ctxlen);
}
EXPORT_SYMBOL(security_inode_setsecctx);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
{
- return security_ops->inode_getsecctx(inode, ctx, ctxlen);
+ return call_int_hook(inode_getsecctx, -EOPNOTSUPP, inode, ctx, ctxlen);
}
EXPORT_SYMBOL(security_inode_getsecctx);
@@ -1156,214 +1188,210 @@ EXPORT_SYMBOL(security_inode_getsecctx);
int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk)
{
- return security_ops->unix_stream_connect(sock, other, newsk);
+ return call_int_hook(unix_stream_connect, 0, sock, other, newsk);
}
EXPORT_SYMBOL(security_unix_stream_connect);
int security_unix_may_send(struct socket *sock, struct socket *other)
{
- return security_ops->unix_may_send(sock, other);
+ return call_int_hook(unix_may_send, 0, sock, other);
}
EXPORT_SYMBOL(security_unix_may_send);
int security_socket_create(int family, int type, int protocol, int kern)
{
- return security_ops->socket_create(family, type, protocol, kern);
+ return call_int_hook(socket_create, 0, family, type, protocol, kern);
}
int security_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern)
{
- return security_ops->socket_post_create(sock, family, type,
+ return call_int_hook(socket_post_create, 0, sock, family, type,
protocol, kern);
}
int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
{
- return security_ops->socket_bind(sock, address, addrlen);
+ return call_int_hook(socket_bind, 0, sock, address, addrlen);
}
int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen)
{
- return security_ops->socket_connect(sock, address, addrlen);
+ return call_int_hook(socket_connect, 0, sock, address, addrlen);
}
int security_socket_listen(struct socket *sock, int backlog)
{
- return security_ops->socket_listen(sock, backlog);
+ return call_int_hook(socket_listen, 0, sock, backlog);
}
int security_socket_accept(struct socket *sock, struct socket *newsock)
{
- return security_ops->socket_accept(sock, newsock);
+ return call_int_hook(socket_accept, 0, sock, newsock);
}
int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size)
{
- return security_ops->socket_sendmsg(sock, msg, size);
+ return call_int_hook(socket_sendmsg, 0, sock, msg, size);
}
int security_socket_recvmsg(struct socket *sock, struct msghdr *msg,
int size, int flags)
{
- return security_ops->socket_recvmsg(sock, msg, size, flags);
+ return call_int_hook(socket_recvmsg, 0, sock, msg, size, flags);
}
int security_socket_getsockname(struct socket *sock)
{
- return security_ops->socket_getsockname(sock);
+ return call_int_hook(socket_getsockname, 0, sock);
}
int security_socket_getpeername(struct socket *sock)
{
- return security_ops->socket_getpeername(sock);
+ return call_int_hook(socket_getpeername, 0, sock);
}
int security_socket_getsockopt(struct socket *sock, int level, int optname)
{
- return security_ops->socket_getsockopt(sock, level, optname);
+ return call_int_hook(socket_getsockopt, 0, sock, level, optname);
}
int security_socket_setsockopt(struct socket *sock, int level, int optname)
{
- return security_ops->socket_setsockopt(sock, level, optname);
+ return call_int_hook(socket_setsockopt, 0, sock, level, optname);
}
int security_socket_shutdown(struct socket *sock, int how)
{
- return security_ops->socket_shutdown(sock, how);
+ return call_int_hook(socket_shutdown, 0, sock, how);
}
int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- return security_ops->socket_sock_rcv_skb(sk, skb);
+ return call_int_hook(socket_sock_rcv_skb, 0, sk, skb);
}
EXPORT_SYMBOL(security_sock_rcv_skb);
int security_socket_getpeersec_stream(struct socket *sock, char __user *optval,
int __user *optlen, unsigned len)
{
- return security_ops->socket_getpeersec_stream(sock, optval, optlen, len);
+ return call_int_hook(socket_getpeersec_stream, -ENOPROTOOPT, sock,
+ optval, optlen, len);
}
int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
{
- return security_ops->socket_getpeersec_dgram(sock, skb, secid);
+ return call_int_hook(socket_getpeersec_dgram, 0, sock, skb, secid);
}
EXPORT_SYMBOL(security_socket_getpeersec_dgram);
int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
{
- return security_ops->sk_alloc_security(sk, family, priority);
+ return call_int_hook(sk_alloc_security, 0, sk, family, priority);
}
void security_sk_free(struct sock *sk)
{
- security_ops->sk_free_security(sk);
+ call_void_hook(sk_free_security, sk);
}
void security_sk_clone(const struct sock *sk, struct sock *newsk)
{
- security_ops->sk_clone_security(sk, newsk);
+ call_void_hook(sk_clone_security, sk, newsk);
}
EXPORT_SYMBOL(security_sk_clone);
void security_sk_classify_flow(struct sock *sk, struct flowi *fl)
{
- security_ops->sk_getsecid(sk, &fl->flowi_secid);
+ call_void_hook(sk_getsecid, sk, &fl->flowi_secid);
}
EXPORT_SYMBOL(security_sk_classify_flow);
void security_req_classify_flow(const struct request_sock *req, struct flowi *fl)
{
- security_ops->req_classify_flow(req, fl);
+ call_void_hook(req_classify_flow, req, fl);
}
EXPORT_SYMBOL(security_req_classify_flow);
void security_sock_graft(struct sock *sk, struct socket *parent)
{
- security_ops->sock_graft(sk, parent);
+ call_void_hook(sock_graft, sk, parent);
}
EXPORT_SYMBOL(security_sock_graft);
int security_inet_conn_request(struct sock *sk,
struct sk_buff *skb, struct request_sock *req)
{
- return security_ops->inet_conn_request(sk, skb, req);
+ return call_int_hook(inet_conn_request, 0, sk, skb, req);
}
EXPORT_SYMBOL(security_inet_conn_request);
void security_inet_csk_clone(struct sock *newsk,
const struct request_sock *req)
{
- security_ops->inet_csk_clone(newsk, req);
+ call_void_hook(inet_csk_clone, newsk, req);
}
void security_inet_conn_established(struct sock *sk,
struct sk_buff *skb)
{
- security_ops->inet_conn_established(sk, skb);
+ call_void_hook(inet_conn_established, sk, skb);
}
int security_secmark_relabel_packet(u32 secid)
{
- return security_ops->secmark_relabel_packet(secid);
+ return call_int_hook(secmark_relabel_packet, 0, secid);
}
EXPORT_SYMBOL(security_secmark_relabel_packet);
void security_secmark_refcount_inc(void)
{
- security_ops->secmark_refcount_inc();
+ call_void_hook(secmark_refcount_inc);
}
EXPORT_SYMBOL(security_secmark_refcount_inc);
void security_secmark_refcount_dec(void)
{
- security_ops->secmark_refcount_dec();
+ call_void_hook(secmark_refcount_dec);
}
EXPORT_SYMBOL(security_secmark_refcount_dec);
int security_tun_dev_alloc_security(void **security)
{
- return security_ops->tun_dev_alloc_security(security);
+ return call_int_hook(tun_dev_alloc_security, 0, security);
}
EXPORT_SYMBOL(security_tun_dev_alloc_security);
void security_tun_dev_free_security(void *security)
{
- security_ops->tun_dev_free_security(security);
+ call_void_hook(tun_dev_free_security, security);
}
EXPORT_SYMBOL(security_tun_dev_free_security);
int security_tun_dev_create(void)
{
- return security_ops->tun_dev_create();
+ return call_int_hook(tun_dev_create, 0);
}
EXPORT_SYMBOL(security_tun_dev_create);
int security_tun_dev_attach_queue(void *security)
{
- return security_ops->tun_dev_attach_queue(security);
+ return call_int_hook(tun_dev_attach_queue, 0, security);
}
EXPORT_SYMBOL(security_tun_dev_attach_queue);
int security_tun_dev_attach(struct sock *sk, void *security)
{
- return security_ops->tun_dev_attach(sk, security);
+ return call_int_hook(tun_dev_attach, 0, sk, security);
}
EXPORT_SYMBOL(security_tun_dev_attach);
int security_tun_dev_open(void *security)
{
- return security_ops->tun_dev_open(security);
+ return call_int_hook(tun_dev_open, 0, security);
}
EXPORT_SYMBOL(security_tun_dev_open);
-void security_skb_owned_by(struct sk_buff *skb, struct sock *sk)
-{
- security_ops->skb_owned_by(skb, sk);
-}
-
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef CONFIG_SECURITY_NETWORK_XFRM
@@ -1372,71 +1400,89 @@ int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp,
struct xfrm_user_sec_ctx *sec_ctx,
gfp_t gfp)
{
- return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx, gfp);
+ return call_int_hook(xfrm_policy_alloc_security, 0, ctxp, sec_ctx, gfp);
}
EXPORT_SYMBOL(security_xfrm_policy_alloc);
int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx,
struct xfrm_sec_ctx **new_ctxp)
{
- return security_ops->xfrm_policy_clone_security(old_ctx, new_ctxp);
+ return call_int_hook(xfrm_policy_clone_security, 0, old_ctx, new_ctxp);
}
void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx)
{
- security_ops->xfrm_policy_free_security(ctx);
+ call_void_hook(xfrm_policy_free_security, ctx);
}
EXPORT_SYMBOL(security_xfrm_policy_free);
int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx)
{
- return security_ops->xfrm_policy_delete_security(ctx);
+ return call_int_hook(xfrm_policy_delete_security, 0, ctx);
}
int security_xfrm_state_alloc(struct xfrm_state *x,
struct xfrm_user_sec_ctx *sec_ctx)
{
- return security_ops->xfrm_state_alloc(x, sec_ctx);
+ return call_int_hook(xfrm_state_alloc, 0, x, sec_ctx);
}
EXPORT_SYMBOL(security_xfrm_state_alloc);
int security_xfrm_state_alloc_acquire(struct xfrm_state *x,
struct xfrm_sec_ctx *polsec, u32 secid)
{
- return security_ops->xfrm_state_alloc_acquire(x, polsec, secid);
+ return call_int_hook(xfrm_state_alloc_acquire, 0, x, polsec, secid);
}
int security_xfrm_state_delete(struct xfrm_state *x)
{
- return security_ops->xfrm_state_delete_security(x);
+ return call_int_hook(xfrm_state_delete_security, 0, x);
}
EXPORT_SYMBOL(security_xfrm_state_delete);
void security_xfrm_state_free(struct xfrm_state *x)
{
- security_ops->xfrm_state_free_security(x);
+ call_void_hook(xfrm_state_free_security, x);
}
int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir)
{
- return security_ops->xfrm_policy_lookup(ctx, fl_secid, dir);
+ return call_int_hook(xfrm_policy_lookup, 0, ctx, fl_secid, dir);
}
int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
struct xfrm_policy *xp,
const struct flowi *fl)
{
- return security_ops->xfrm_state_pol_flow_match(x, xp, fl);
+ struct security_hook_list *hp;
+ int rc = 1;
+
+ /*
+ * Since this function is expected to return 0 or 1, the judgment
+ * becomes difficult if multiple LSMs supply this call. Fortunately,
+ * we can use the first LSM's judgment because currently only SELinux
+ * supplies this call.
+ *
+ * For speed optimization, we explicitly break the loop rather than
+ * using the macro
+ */
+ list_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match,
+ list) {
+ rc = hp->hook.xfrm_state_pol_flow_match(x, xp, fl);
+ break;
+ }
+ return rc;
}
int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
{
- return security_ops->xfrm_decode_session(skb, secid, 1);
+ return call_int_hook(xfrm_decode_session, 0, skb, secid, 1);
}
void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl)
{
- int rc = security_ops->xfrm_decode_session(skb, &fl->flowi_secid, 0);
+ int rc = call_int_hook(xfrm_decode_session, 0, skb, &fl->flowi_secid,
+ 0);
BUG_ON(rc);
}
@@ -1449,23 +1495,24 @@ EXPORT_SYMBOL(security_skb_classify_flow);
int security_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
- return security_ops->key_alloc(key, cred, flags);
+ return call_int_hook(key_alloc, 0, key, cred, flags);
}
void security_key_free(struct key *key)
{
- security_ops->key_free(key);
+ call_void_hook(key_free, key);
}
int security_key_permission(key_ref_t key_ref,
const struct cred *cred, unsigned perm)
{
- return security_ops->key_permission(key_ref, cred, perm);
+ return call_int_hook(key_permission, 0, key_ref, cred, perm);
}
int security_key_getsecurity(struct key *key, char **_buffer)
{
- return security_ops->key_getsecurity(key, _buffer);
+ *_buffer = NULL;
+ return call_int_hook(key_getsecurity, 0, key, _buffer);
}
#endif /* CONFIG_KEYS */
@@ -1474,23 +1521,369 @@ int security_key_getsecurity(struct key *key, char **_buffer)
int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule)
{
- return security_ops->audit_rule_init(field, op, rulestr, lsmrule);
+ return call_int_hook(audit_rule_init, 0, field, op, rulestr, lsmrule);
}
int security_audit_rule_known(struct audit_krule *krule)
{
- return security_ops->audit_rule_known(krule);
+ return call_int_hook(audit_rule_known, 0, krule);
}
void security_audit_rule_free(void *lsmrule)
{
- security_ops->audit_rule_free(lsmrule);
+ call_void_hook(audit_rule_free, lsmrule);
}
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
struct audit_context *actx)
{
- return security_ops->audit_rule_match(secid, field, op, lsmrule, actx);
+ return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
+ actx);
}
+#endif /* CONFIG_AUDIT */
+struct security_hook_heads security_hook_heads = {
+ .binder_set_context_mgr =
+ LIST_HEAD_INIT(security_hook_heads.binder_set_context_mgr),
+ .binder_transaction =
+ LIST_HEAD_INIT(security_hook_heads.binder_transaction),
+ .binder_transfer_binder =
+ LIST_HEAD_INIT(security_hook_heads.binder_transfer_binder),
+ .binder_transfer_file =
+ LIST_HEAD_INIT(security_hook_heads.binder_transfer_file),
+
+ .ptrace_access_check =
+ LIST_HEAD_INIT(security_hook_heads.ptrace_access_check),
+ .ptrace_traceme =
+ LIST_HEAD_INIT(security_hook_heads.ptrace_traceme),
+ .capget = LIST_HEAD_INIT(security_hook_heads.capget),
+ .capset = LIST_HEAD_INIT(security_hook_heads.capset),
+ .capable = LIST_HEAD_INIT(security_hook_heads.capable),
+ .quotactl = LIST_HEAD_INIT(security_hook_heads.quotactl),
+ .quota_on = LIST_HEAD_INIT(security_hook_heads.quota_on),
+ .syslog = LIST_HEAD_INIT(security_hook_heads.syslog),
+ .settime = LIST_HEAD_INIT(security_hook_heads.settime),
+ .vm_enough_memory =
+ LIST_HEAD_INIT(security_hook_heads.vm_enough_memory),
+ .bprm_set_creds =
+ LIST_HEAD_INIT(security_hook_heads.bprm_set_creds),
+ .bprm_check_security =
+ LIST_HEAD_INIT(security_hook_heads.bprm_check_security),
+ .bprm_secureexec =
+ LIST_HEAD_INIT(security_hook_heads.bprm_secureexec),
+ .bprm_committing_creds =
+ LIST_HEAD_INIT(security_hook_heads.bprm_committing_creds),
+ .bprm_committed_creds =
+ LIST_HEAD_INIT(security_hook_heads.bprm_committed_creds),
+ .sb_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.sb_alloc_security),
+ .sb_free_security =
+ LIST_HEAD_INIT(security_hook_heads.sb_free_security),
+ .sb_copy_data = LIST_HEAD_INIT(security_hook_heads.sb_copy_data),
+ .sb_remount = LIST_HEAD_INIT(security_hook_heads.sb_remount),
+ .sb_kern_mount =
+ LIST_HEAD_INIT(security_hook_heads.sb_kern_mount),
+ .sb_show_options =
+ LIST_HEAD_INIT(security_hook_heads.sb_show_options),
+ .sb_statfs = LIST_HEAD_INIT(security_hook_heads.sb_statfs),
+ .sb_mount = LIST_HEAD_INIT(security_hook_heads.sb_mount),
+ .sb_umount = LIST_HEAD_INIT(security_hook_heads.sb_umount),
+ .sb_pivotroot = LIST_HEAD_INIT(security_hook_heads.sb_pivotroot),
+ .sb_set_mnt_opts =
+ LIST_HEAD_INIT(security_hook_heads.sb_set_mnt_opts),
+ .sb_clone_mnt_opts =
+ LIST_HEAD_INIT(security_hook_heads.sb_clone_mnt_opts),
+ .sb_parse_opts_str =
+ LIST_HEAD_INIT(security_hook_heads.sb_parse_opts_str),
+ .dentry_init_security =
+ LIST_HEAD_INIT(security_hook_heads.dentry_init_security),
+#ifdef CONFIG_SECURITY_PATH
+ .path_unlink = LIST_HEAD_INIT(security_hook_heads.path_unlink),
+ .path_mkdir = LIST_HEAD_INIT(security_hook_heads.path_mkdir),
+ .path_rmdir = LIST_HEAD_INIT(security_hook_heads.path_rmdir),
+ .path_mknod = LIST_HEAD_INIT(security_hook_heads.path_mknod),
+ .path_truncate =
+ LIST_HEAD_INIT(security_hook_heads.path_truncate),
+ .path_symlink = LIST_HEAD_INIT(security_hook_heads.path_symlink),
+ .path_link = LIST_HEAD_INIT(security_hook_heads.path_link),
+ .path_rename = LIST_HEAD_INIT(security_hook_heads.path_rename),
+ .path_chmod = LIST_HEAD_INIT(security_hook_heads.path_chmod),
+ .path_chown = LIST_HEAD_INIT(security_hook_heads.path_chown),
+ .path_chroot = LIST_HEAD_INIT(security_hook_heads.path_chroot),
+#endif
+ .inode_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.inode_alloc_security),
+ .inode_free_security =
+ LIST_HEAD_INIT(security_hook_heads.inode_free_security),
+ .inode_init_security =
+ LIST_HEAD_INIT(security_hook_heads.inode_init_security),
+ .inode_create = LIST_HEAD_INIT(security_hook_heads.inode_create),
+ .inode_link = LIST_HEAD_INIT(security_hook_heads.inode_link),
+ .inode_unlink = LIST_HEAD_INIT(security_hook_heads.inode_unlink),
+ .inode_symlink =
+ LIST_HEAD_INIT(security_hook_heads.inode_symlink),
+ .inode_mkdir = LIST_HEAD_INIT(security_hook_heads.inode_mkdir),
+ .inode_rmdir = LIST_HEAD_INIT(security_hook_heads.inode_rmdir),
+ .inode_mknod = LIST_HEAD_INIT(security_hook_heads.inode_mknod),
+ .inode_rename = LIST_HEAD_INIT(security_hook_heads.inode_rename),
+ .inode_readlink =
+ LIST_HEAD_INIT(security_hook_heads.inode_readlink),
+ .inode_follow_link =
+ LIST_HEAD_INIT(security_hook_heads.inode_follow_link),
+ .inode_permission =
+ LIST_HEAD_INIT(security_hook_heads.inode_permission),
+ .inode_setattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_setattr),
+ .inode_getattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_getattr),
+ .inode_setxattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_setxattr),
+ .inode_post_setxattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_post_setxattr),
+ .inode_getxattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_getxattr),
+ .inode_listxattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_listxattr),
+ .inode_removexattr =
+ LIST_HEAD_INIT(security_hook_heads.inode_removexattr),
+ .inode_need_killpriv =
+ LIST_HEAD_INIT(security_hook_heads.inode_need_killpriv),
+ .inode_killpriv =
+ LIST_HEAD_INIT(security_hook_heads.inode_killpriv),
+ .inode_getsecurity =
+ LIST_HEAD_INIT(security_hook_heads.inode_getsecurity),
+ .inode_setsecurity =
+ LIST_HEAD_INIT(security_hook_heads.inode_setsecurity),
+ .inode_listsecurity =
+ LIST_HEAD_INIT(security_hook_heads.inode_listsecurity),
+ .inode_getsecid =
+ LIST_HEAD_INIT(security_hook_heads.inode_getsecid),
+ .file_permission =
+ LIST_HEAD_INIT(security_hook_heads.file_permission),
+ .file_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.file_alloc_security),
+ .file_free_security =
+ LIST_HEAD_INIT(security_hook_heads.file_free_security),
+ .file_ioctl = LIST_HEAD_INIT(security_hook_heads.file_ioctl),
+ .mmap_addr = LIST_HEAD_INIT(security_hook_heads.mmap_addr),
+ .mmap_file = LIST_HEAD_INIT(security_hook_heads.mmap_file),
+ .file_mprotect =
+ LIST_HEAD_INIT(security_hook_heads.file_mprotect),
+ .file_lock = LIST_HEAD_INIT(security_hook_heads.file_lock),
+ .file_fcntl = LIST_HEAD_INIT(security_hook_heads.file_fcntl),
+ .file_set_fowner =
+ LIST_HEAD_INIT(security_hook_heads.file_set_fowner),
+ .file_send_sigiotask =
+ LIST_HEAD_INIT(security_hook_heads.file_send_sigiotask),
+ .file_receive = LIST_HEAD_INIT(security_hook_heads.file_receive),
+ .file_open = LIST_HEAD_INIT(security_hook_heads.file_open),
+ .task_create = LIST_HEAD_INIT(security_hook_heads.task_create),
+ .task_free = LIST_HEAD_INIT(security_hook_heads.task_free),
+ .cred_alloc_blank =
+ LIST_HEAD_INIT(security_hook_heads.cred_alloc_blank),
+ .cred_free = LIST_HEAD_INIT(security_hook_heads.cred_free),
+ .cred_prepare = LIST_HEAD_INIT(security_hook_heads.cred_prepare),
+ .cred_transfer =
+ LIST_HEAD_INIT(security_hook_heads.cred_transfer),
+ .kernel_act_as =
+ LIST_HEAD_INIT(security_hook_heads.kernel_act_as),
+ .kernel_create_files_as =
+ LIST_HEAD_INIT(security_hook_heads.kernel_create_files_as),
+ .kernel_fw_from_file =
+ LIST_HEAD_INIT(security_hook_heads.kernel_fw_from_file),
+ .kernel_module_request =
+ LIST_HEAD_INIT(security_hook_heads.kernel_module_request),
+ .kernel_module_from_file =
+ LIST_HEAD_INIT(security_hook_heads.kernel_module_from_file),
+ .task_fix_setuid =
+ LIST_HEAD_INIT(security_hook_heads.task_fix_setuid),
+ .task_setpgid = LIST_HEAD_INIT(security_hook_heads.task_setpgid),
+ .task_getpgid = LIST_HEAD_INIT(security_hook_heads.task_getpgid),
+ .task_getsid = LIST_HEAD_INIT(security_hook_heads.task_getsid),
+ .task_getsecid =
+ LIST_HEAD_INIT(security_hook_heads.task_getsecid),
+ .task_setnice = LIST_HEAD_INIT(security_hook_heads.task_setnice),
+ .task_setioprio =
+ LIST_HEAD_INIT(security_hook_heads.task_setioprio),
+ .task_getioprio =
+ LIST_HEAD_INIT(security_hook_heads.task_getioprio),
+ .task_setrlimit =
+ LIST_HEAD_INIT(security_hook_heads.task_setrlimit),
+ .task_setscheduler =
+ LIST_HEAD_INIT(security_hook_heads.task_setscheduler),
+ .task_getscheduler =
+ LIST_HEAD_INIT(security_hook_heads.task_getscheduler),
+ .task_movememory =
+ LIST_HEAD_INIT(security_hook_heads.task_movememory),
+ .task_kill = LIST_HEAD_INIT(security_hook_heads.task_kill),
+ .task_wait = LIST_HEAD_INIT(security_hook_heads.task_wait),
+ .task_prctl = LIST_HEAD_INIT(security_hook_heads.task_prctl),
+ .task_to_inode =
+ LIST_HEAD_INIT(security_hook_heads.task_to_inode),
+ .ipc_permission =
+ LIST_HEAD_INIT(security_hook_heads.ipc_permission),
+ .ipc_getsecid = LIST_HEAD_INIT(security_hook_heads.ipc_getsecid),
+ .msg_msg_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.msg_msg_alloc_security),
+ .msg_msg_free_security =
+ LIST_HEAD_INIT(security_hook_heads.msg_msg_free_security),
+ .msg_queue_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.msg_queue_alloc_security),
+ .msg_queue_free_security =
+ LIST_HEAD_INIT(security_hook_heads.msg_queue_free_security),
+ .msg_queue_associate =
+ LIST_HEAD_INIT(security_hook_heads.msg_queue_associate),
+ .msg_queue_msgctl =
+ LIST_HEAD_INIT(security_hook_heads.msg_queue_msgctl),
+ .msg_queue_msgsnd =
+ LIST_HEAD_INIT(security_hook_heads.msg_queue_msgsnd),
+ .msg_queue_msgrcv =
+ LIST_HEAD_INIT(security_hook_heads.msg_queue_msgrcv),
+ .shm_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.shm_alloc_security),
+ .shm_free_security =
+ LIST_HEAD_INIT(security_hook_heads.shm_free_security),
+ .shm_associate =
+ LIST_HEAD_INIT(security_hook_heads.shm_associate),
+ .shm_shmctl = LIST_HEAD_INIT(security_hook_heads.shm_shmctl),
+ .shm_shmat = LIST_HEAD_INIT(security_hook_heads.shm_shmat),
+ .sem_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.sem_alloc_security),
+ .sem_free_security =
+ LIST_HEAD_INIT(security_hook_heads.sem_free_security),
+ .sem_associate =
+ LIST_HEAD_INIT(security_hook_heads.sem_associate),
+ .sem_semctl = LIST_HEAD_INIT(security_hook_heads.sem_semctl),
+ .sem_semop = LIST_HEAD_INIT(security_hook_heads.sem_semop),
+ .netlink_send = LIST_HEAD_INIT(security_hook_heads.netlink_send),
+ .d_instantiate =
+ LIST_HEAD_INIT(security_hook_heads.d_instantiate),
+ .getprocattr = LIST_HEAD_INIT(security_hook_heads.getprocattr),
+ .setprocattr = LIST_HEAD_INIT(security_hook_heads.setprocattr),
+ .ismaclabel = LIST_HEAD_INIT(security_hook_heads.ismaclabel),
+ .secid_to_secctx =
+ LIST_HEAD_INIT(security_hook_heads.secid_to_secctx),
+ .secctx_to_secid =
+ LIST_HEAD_INIT(security_hook_heads.secctx_to_secid),
+ .release_secctx =
+ LIST_HEAD_INIT(security_hook_heads.release_secctx),
+ .inode_notifysecctx =
+ LIST_HEAD_INIT(security_hook_heads.inode_notifysecctx),
+ .inode_setsecctx =
+ LIST_HEAD_INIT(security_hook_heads.inode_setsecctx),
+ .inode_getsecctx =
+ LIST_HEAD_INIT(security_hook_heads.inode_getsecctx),
+#ifdef CONFIG_SECURITY_NETWORK
+ .unix_stream_connect =
+ LIST_HEAD_INIT(security_hook_heads.unix_stream_connect),
+ .unix_may_send =
+ LIST_HEAD_INIT(security_hook_heads.unix_may_send),
+ .socket_create =
+ LIST_HEAD_INIT(security_hook_heads.socket_create),
+ .socket_post_create =
+ LIST_HEAD_INIT(security_hook_heads.socket_post_create),
+ .socket_bind = LIST_HEAD_INIT(security_hook_heads.socket_bind),
+ .socket_connect =
+ LIST_HEAD_INIT(security_hook_heads.socket_connect),
+ .socket_listen =
+ LIST_HEAD_INIT(security_hook_heads.socket_listen),
+ .socket_accept =
+ LIST_HEAD_INIT(security_hook_heads.socket_accept),
+ .socket_sendmsg =
+ LIST_HEAD_INIT(security_hook_heads.socket_sendmsg),
+ .socket_recvmsg =
+ LIST_HEAD_INIT(security_hook_heads.socket_recvmsg),
+ .socket_getsockname =
+ LIST_HEAD_INIT(security_hook_heads.socket_getsockname),
+ .socket_getpeername =
+ LIST_HEAD_INIT(security_hook_heads.socket_getpeername),
+ .socket_getsockopt =
+ LIST_HEAD_INIT(security_hook_heads.socket_getsockopt),
+ .socket_setsockopt =
+ LIST_HEAD_INIT(security_hook_heads.socket_setsockopt),
+ .socket_shutdown =
+ LIST_HEAD_INIT(security_hook_heads.socket_shutdown),
+ .socket_sock_rcv_skb =
+ LIST_HEAD_INIT(security_hook_heads.socket_sock_rcv_skb),
+ .socket_getpeersec_stream =
+ LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_stream),
+ .socket_getpeersec_dgram =
+ LIST_HEAD_INIT(security_hook_heads.socket_getpeersec_dgram),
+ .sk_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.sk_alloc_security),
+ .sk_free_security =
+ LIST_HEAD_INIT(security_hook_heads.sk_free_security),
+ .sk_clone_security =
+ LIST_HEAD_INIT(security_hook_heads.sk_clone_security),
+ .sk_getsecid = LIST_HEAD_INIT(security_hook_heads.sk_getsecid),
+ .sock_graft = LIST_HEAD_INIT(security_hook_heads.sock_graft),
+ .inet_conn_request =
+ LIST_HEAD_INIT(security_hook_heads.inet_conn_request),
+ .inet_csk_clone =
+ LIST_HEAD_INIT(security_hook_heads.inet_csk_clone),
+ .inet_conn_established =
+ LIST_HEAD_INIT(security_hook_heads.inet_conn_established),
+ .secmark_relabel_packet =
+ LIST_HEAD_INIT(security_hook_heads.secmark_relabel_packet),
+ .secmark_refcount_inc =
+ LIST_HEAD_INIT(security_hook_heads.secmark_refcount_inc),
+ .secmark_refcount_dec =
+ LIST_HEAD_INIT(security_hook_heads.secmark_refcount_dec),
+ .req_classify_flow =
+ LIST_HEAD_INIT(security_hook_heads.req_classify_flow),
+ .tun_dev_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.tun_dev_alloc_security),
+ .tun_dev_free_security =
+ LIST_HEAD_INIT(security_hook_heads.tun_dev_free_security),
+ .tun_dev_create =
+ LIST_HEAD_INIT(security_hook_heads.tun_dev_create),
+ .tun_dev_attach_queue =
+ LIST_HEAD_INIT(security_hook_heads.tun_dev_attach_queue),
+ .tun_dev_attach =
+ LIST_HEAD_INIT(security_hook_heads.tun_dev_attach),
+ .tun_dev_open = LIST_HEAD_INIT(security_hook_heads.tun_dev_open),
+ .skb_owned_by = LIST_HEAD_INIT(security_hook_heads.skb_owned_by),
+#endif /* CONFIG_SECURITY_NETWORK */
+#ifdef CONFIG_SECURITY_NETWORK_XFRM
+ .xfrm_policy_alloc_security =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_policy_alloc_security),
+ .xfrm_policy_clone_security =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_policy_clone_security),
+ .xfrm_policy_free_security =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_policy_free_security),
+ .xfrm_policy_delete_security =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_policy_delete_security),
+ .xfrm_state_alloc =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc),
+ .xfrm_state_alloc_acquire =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_state_alloc_acquire),
+ .xfrm_state_free_security =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_state_free_security),
+ .xfrm_state_delete_security =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_state_delete_security),
+ .xfrm_policy_lookup =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_policy_lookup),
+ .xfrm_state_pol_flow_match =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_state_pol_flow_match),
+ .xfrm_decode_session =
+ LIST_HEAD_INIT(security_hook_heads.xfrm_decode_session),
+#endif /* CONFIG_SECURITY_NETWORK_XFRM */
+#ifdef CONFIG_KEYS
+ .key_alloc = LIST_HEAD_INIT(security_hook_heads.key_alloc),
+ .key_free = LIST_HEAD_INIT(security_hook_heads.key_free),
+ .key_permission =
+ LIST_HEAD_INIT(security_hook_heads.key_permission),
+ .key_getsecurity =
+ LIST_HEAD_INIT(security_hook_heads.key_getsecurity),
+#endif /* CONFIG_KEYS */
+#ifdef CONFIG_AUDIT
+ .audit_rule_init =
+ LIST_HEAD_INIT(security_hook_heads.audit_rule_init),
+ .audit_rule_known =
+ LIST_HEAD_INIT(security_hook_heads.audit_rule_known),
+ .audit_rule_match =
+ LIST_HEAD_INIT(security_hook_heads.audit_rule_match),
+ .audit_rule_free =
+ LIST_HEAD_INIT(security_hook_heads.audit_rule_free),
#endif /* CONFIG_AUDIT */
+};
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index afcc0aed9393..0b122b1421a9 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -724,12 +724,10 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
rcu_read_lock();
node = avc_lookup(ssid, tsid, tclass);
- if (unlikely(!node)) {
+ if (unlikely(!node))
node = avc_compute_av(ssid, tsid, tclass, avd);
- } else {
+ else
memcpy(avd, &node->ae.avd, sizeof(*avd));
- avd = &node->ae.avd;
- }
denied = requested & ~(avd->allowed);
if (unlikely(denied))
@@ -763,7 +761,23 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
- rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
+ rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, 0);
+ if (rc2)
+ return rc2;
+ return rc;
+}
+
+int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *auditdata,
+ int flags)
+{
+ struct av_decision avd;
+ int rc, rc2;
+
+ rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
+
+ rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc,
+ auditdata, flags);
if (rc2)
return rc2;
return rc;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4d1a54190388..623108199641 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -29,7 +29,7 @@
#include <linux/tracehook.h>
#include <linux/errno.h>
#include <linux/sched.h>
-#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/xattr.h>
#include <linux/capability.h>
#include <linux/unistd.h>
@@ -51,7 +51,6 @@
#include <linux/tty.h>
#include <net/icmp.h>
#include <net/ip.h> /* for local_port_range[] */
-#include <net/sock.h>
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
#include <net/inet_connection_sock.h>
#include <net/net_namespace.h>
@@ -404,6 +403,7 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
return sbsec->behavior == SECURITY_FS_USE_XATTR ||
sbsec->behavior == SECURITY_FS_USE_TRANS ||
sbsec->behavior == SECURITY_FS_USE_TASK ||
+ sbsec->behavior == SECURITY_FS_USE_NATIVE ||
/* Special handling. Genfs but also in-core setxattr handler */
!strcmp(sb->s_type->name, "sysfs") ||
!strcmp(sb->s_type->name, "pstore") ||
@@ -415,7 +415,7 @@ static int sb_finish_set_opts(struct super_block *sb)
{
struct superblock_security_struct *sbsec = sb->s_security;
struct dentry *root = sb->s_root;
- struct inode *root_inode = root->d_inode;
+ struct inode *root_inode = d_backing_inode(root);
int rc = 0;
if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
@@ -553,7 +553,7 @@ static int selinux_get_mnt_opts(const struct super_block *sb,
opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
}
if (sbsec->flags & ROOTCONTEXT_MNT) {
- struct inode *root = sbsec->sb->s_root->d_inode;
+ struct inode *root = d_backing_inode(sbsec->sb->s_root);
struct inode_security_struct *isec = root->i_security;
rc = security_sid_to_context(isec->sid, &context, &len);
@@ -609,7 +609,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
int rc = 0, i;
struct superblock_security_struct *sbsec = sb->s_security;
const char *name = sb->s_type->name;
- struct inode *inode = sbsec->sb->s_root->d_inode;
+ struct inode *inode = d_backing_inode(sbsec->sb->s_root);
struct inode_security_struct *root_isec = inode->i_security;
u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
u32 defcontext_sid = 0;
@@ -725,7 +725,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,
}
if (strcmp(sb->s_type->name, "proc") == 0)
- sbsec->flags |= SE_SBPROC;
+ sbsec->flags |= SE_SBPROC | SE_SBGENFS;
+
+ if (!strcmp(sb->s_type->name, "debugfs") ||
+ !strcmp(sb->s_type->name, "sysfs") ||
+ !strcmp(sb->s_type->name, "pstore"))
+ sbsec->flags |= SE_SBGENFS;
if (!sbsec->behavior) {
/*
@@ -836,8 +841,8 @@ static int selinux_cmp_sb_context(const struct super_block *oldsb,
if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
goto mismatch;
if (oldflags & ROOTCONTEXT_MNT) {
- struct inode_security_struct *oldroot = oldsb->s_root->d_inode->i_security;
- struct inode_security_struct *newroot = newsb->s_root->d_inode->i_security;
+ struct inode_security_struct *oldroot = d_backing_inode(oldsb->s_root)->i_security;
+ struct inode_security_struct *newroot = d_backing_inode(newsb->s_root)->i_security;
if (oldroot->sid != newroot->sid)
goto mismatch;
}
@@ -887,16 +892,16 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (!set_fscontext)
newsbsec->sid = sid;
if (!set_rootcontext) {
- struct inode *newinode = newsb->s_root->d_inode;
+ struct inode *newinode = d_backing_inode(newsb->s_root);
struct inode_security_struct *newisec = newinode->i_security;
newisec->sid = sid;
}
newsbsec->mntpoint_sid = sid;
}
if (set_rootcontext) {
- const struct inode *oldinode = oldsb->s_root->d_inode;
+ const struct inode *oldinode = d_backing_inode(oldsb->s_root);
const struct inode_security_struct *oldisec = oldinode->i_security;
- struct inode *newinode = newsb->s_root->d_inode;
+ struct inode *newinode = d_backing_inode(newsb->s_root);
struct inode_security_struct *newisec = newinode->i_security;
newisec->sid = oldisec->sid;
@@ -1189,8 +1194,6 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
switch (protocol) {
case NETLINK_ROUTE:
return SECCLASS_NETLINK_ROUTE_SOCKET;
- case NETLINK_FIREWALL:
- return SECCLASS_NETLINK_FIREWALL_SOCKET;
case NETLINK_SOCK_DIAG:
return SECCLASS_NETLINK_TCPDIAG_SOCKET;
case NETLINK_NFLOG:
@@ -1199,14 +1202,28 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_NETLINK_XFRM_SOCKET;
case NETLINK_SELINUX:
return SECCLASS_NETLINK_SELINUX_SOCKET;
+ case NETLINK_ISCSI:
+ return SECCLASS_NETLINK_ISCSI_SOCKET;
case NETLINK_AUDIT:
return SECCLASS_NETLINK_AUDIT_SOCKET;
- case NETLINK_IP6_FW:
- return SECCLASS_NETLINK_IP6FW_SOCKET;
+ case NETLINK_FIB_LOOKUP:
+ return SECCLASS_NETLINK_FIB_LOOKUP_SOCKET;
+ case NETLINK_CONNECTOR:
+ return SECCLASS_NETLINK_CONNECTOR_SOCKET;
+ case NETLINK_NETFILTER:
+ return SECCLASS_NETLINK_NETFILTER_SOCKET;
case NETLINK_DNRTMSG:
return SECCLASS_NETLINK_DNRT_SOCKET;
case NETLINK_KOBJECT_UEVENT:
return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
+ case NETLINK_GENERIC:
+ return SECCLASS_NETLINK_GENERIC_SOCKET;
+ case NETLINK_SCSITRANSPORT:
+ return SECCLASS_NETLINK_SCSITRANSPORT_SOCKET;
+ case NETLINK_RDMA:
+ return SECCLASS_NETLINK_RDMA_SOCKET;
+ case NETLINK_CRYPTO:
+ return SECCLASS_NETLINK_CRYPTO_SOCKET;
default:
return SECCLASS_NETLINK_SOCKET;
}
@@ -1221,12 +1238,13 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc
return SECCLASS_SOCKET;
}
-#ifdef CONFIG_PROC_FS
-static int selinux_proc_get_sid(struct dentry *dentry,
- u16 tclass,
- u32 *sid)
+static int selinux_genfs_get_sid(struct dentry *dentry,
+ u16 tclass,
+ u16 flags,
+ u32 *sid)
{
int rc;
+ struct super_block *sb = dentry->d_inode->i_sb;
char *buffer, *path;
buffer = (char *)__get_free_page(GFP_KERNEL);
@@ -1237,26 +1255,20 @@ static int selinux_proc_get_sid(struct dentry *dentry,
if (IS_ERR(path))
rc = PTR_ERR(path);
else {
- /* each process gets a /proc/PID/ entry. Strip off the
- * PID part to get a valid selinux labeling.
- * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
- while (path[1] >= '0' && path[1] <= '9') {
- path[1] = '/';
- path++;
+ if (flags & SE_SBPROC) {
+ /* each process gets a /proc/PID/ entry. Strip off the
+ * PID part to get a valid selinux labeling.
+ * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
+ while (path[1] >= '0' && path[1] <= '9') {
+ path[1] = '/';
+ path++;
+ }
}
- rc = security_genfs_sid("proc", path, tclass, sid);
+ rc = security_genfs_sid(sb->s_type->name, path, tclass, sid);
}
free_page((unsigned long)buffer);
return rc;
}
-#else
-static int selinux_proc_get_sid(struct dentry *dentry,
- u16 tclass,
- u32 *sid)
-{
- return -EINVAL;
-}
-#endif
/* The inode's security attributes must be initialized before first use. */
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
@@ -1413,7 +1425,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
/* Default to the fs superblock SID. */
isec->sid = sbsec->sid;
- if ((sbsec->flags & SE_SBPROC) && !S_ISLNK(inode->i_mode)) {
+ if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
/* We must have a dentry to determine the label on
* procfs inodes */
if (opt_dentry)
@@ -1436,7 +1448,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (!dentry)
goto out_unlock;
isec->sclass = inode_mode_to_security_class(inode->i_mode);
- rc = selinux_proc_get_sid(dentry, isec->sclass, &sid);
+ rc = selinux_genfs_get_sid(dentry, isec->sclass,
+ sbsec->flags, &sid);
dput(dentry);
if (rc)
goto out_unlock;
@@ -1565,7 +1578,7 @@ static int cred_has_capability(const struct cred *cred,
rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
if (audit == SECURITY_CAP_AUDIT) {
- int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
+ int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
if (rc2)
return rc2;
}
@@ -1611,7 +1624,7 @@ static inline int dentry_has_perm(const struct cred *cred,
struct dentry *dentry,
u32 av)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
struct common_audit_data ad;
ad.type = LSM_AUDIT_DATA_DENTRY;
@@ -1623,10 +1636,10 @@ static inline int dentry_has_perm(const struct cred *cred,
the path to help the auditing code to more easily generate the
pathname if needed. */
static inline int path_has_perm(const struct cred *cred,
- struct path *path,
+ const struct path *path,
u32 av)
{
- struct inode *inode = path->dentry->d_inode;
+ struct inode *inode = d_backing_inode(path->dentry);
struct common_audit_data ad;
ad.type = LSM_AUDIT_DATA_PATH;
@@ -1754,7 +1767,7 @@ static int may_link(struct inode *dir,
int rc;
dsec = dir->i_security;
- isec = dentry->d_inode->i_security;
+ isec = d_backing_inode(dentry)->i_security;
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
@@ -1798,7 +1811,7 @@ static inline int may_rename(struct inode *old_dir,
int rc;
old_dsec = old_dir->i_security;
- old_isec = old_dentry->d_inode->i_security;
+ old_isec = d_backing_inode(old_dentry)->i_security;
old_is_dir = d_is_dir(old_dentry);
new_dsec = new_dir->i_security;
@@ -1828,7 +1841,7 @@ static inline int may_rename(struct inode *old_dir,
if (rc)
return rc;
if (d_is_positive(new_dentry)) {
- new_isec = new_dentry->d_inode->i_security;
+ new_isec = d_backing_inode(new_dentry)->i_security;
new_is_dir = d_is_dir(new_dentry);
rc = avc_has_perm(sid, new_isec->sid,
new_isec->sclass,
@@ -1964,7 +1977,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
{
u32 sid = task_sid(to);
struct file_security_struct *fsec = file->f_security;
- struct inode *inode = file->f_path.dentry->d_inode;
+ struct inode *inode = d_backing_inode(file->f_path.dentry);
struct inode_security_struct *isec = inode->i_security;
struct common_audit_data ad;
int rc;
@@ -1991,12 +2004,6 @@ static int selinux_binder_transfer_file(struct task_struct *from,
static int selinux_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- int rc;
-
- rc = cap_ptrace_access_check(child, mode);
- if (rc)
- return rc;
-
if (mode & PTRACE_MODE_READ) {
u32 sid = current_sid();
u32 csid = task_sid(child);
@@ -2008,25 +2015,13 @@ static int selinux_ptrace_access_check(struct task_struct *child,
static int selinux_ptrace_traceme(struct task_struct *parent)
{
- int rc;
-
- rc = cap_ptrace_traceme(parent);
- if (rc)
- return rc;
-
return task_has_perm(parent, current, PROCESS__PTRACE);
}
static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
- int error;
-
- error = current_has_perm(target, PROCESS__GETCAP);
- if (error)
- return error;
-
- return cap_capget(target, effective, inheritable, permitted);
+ return current_has_perm(target, PROCESS__GETCAP);
}
static int selinux_capset(struct cred *new, const struct cred *old,
@@ -2034,13 +2029,6 @@ static int selinux_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted)
{
- int error;
-
- error = cap_capset(new, old,
- effective, inheritable, permitted);
- if (error)
- return error;
-
return cred_has_perm(old, new, PROCESS__SETCAP);
}
@@ -2057,12 +2045,6 @@ static int selinux_capset(struct cred *new, const struct cred *old,
static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
int cap, int audit)
{
- int rc;
-
- rc = cap_capable(cred, ns, cap, audit);
- if (rc)
- return rc;
-
return cred_has_capability(cred, cap, audit);
}
@@ -2140,12 +2122,12 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
{
int rc, cap_sys_admin = 0;
- rc = selinux_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
- SECURITY_CAP_NOAUDIT);
+ rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
+ SECURITY_CAP_NOAUDIT);
if (rc == 0)
cap_sys_admin = 1;
- return __vm_enough_memory(mm, pages, cap_sys_admin);
+ return cap_sys_admin;
}
/* binprm security operations */
@@ -2194,10 +2176,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
struct inode *inode = file_inode(bprm->file);
int rc;
- rc = cap_bprm_set_creds(bprm);
- if (rc)
- return rc;
-
/* SELinux context only depends on initial program or script and not
* the script interpreter */
if (bprm->cred_prepared)
@@ -2321,7 +2299,7 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm)
PROCESS__NOATSECURE, NULL);
}
- return (atsecure || cap_bprm_secureexec(bprm));
+ return !!atsecure;
}
static int match_file(const void *p, struct file *file, unsigned fd)
@@ -2452,10 +2430,12 @@ static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
for (i = 0; i < 3; i++)
do_setitimer(i, &itimer, NULL);
spin_lock_irq(&current->sighand->siglock);
- if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
- __flush_signals(current);
+ if (!fatal_signal_pending(current)) {
+ flush_sigqueue(&current->pending);
+ flush_sigqueue(&current->signal->shared_pending);
flush_signal_handlers(current, 1);
sigemptyset(&current->blocked);
+ recalc_sigpending();
}
spin_unlock_irq(&current->sighand->siglock);
}
@@ -2628,7 +2608,7 @@ static int selinux_sb_remount(struct super_block *sb, void *data)
break;
case ROOTCONTEXT_MNT: {
struct inode_security_struct *root_isec;
- root_isec = sb->s_root->d_inode->i_security;
+ root_isec = d_backing_inode(sb->s_root)->i_security;
if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
goto out_bad_option;
@@ -2728,7 +2708,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
struct task_security_struct *tsec;
struct inode_security_struct *dsec;
struct superblock_security_struct *sbsec;
- struct inode *dir = dentry->d_parent->d_inode;
+ struct inode *dir = d_backing_inode(dentry->d_parent);
u32 newsid;
int rc;
@@ -2862,11 +2842,23 @@ static int selinux_inode_readlink(struct dentry *dentry)
return dentry_has_perm(cred, dentry, FILE__READ);
}
-static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
+static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
+ bool rcu)
{
const struct cred *cred = current_cred();
+ struct common_audit_data ad;
+ struct inode_security_struct *isec;
+ u32 sid;
- return dentry_has_perm(cred, dentry, FILE__READ);
+ validate_creds(cred);
+
+ ad.type = LSM_AUDIT_DATA_DENTRY;
+ ad.u.dentry = dentry;
+ sid = cred_sid(cred);
+ isec = inode->i_security;
+
+ return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad,
+ rcu ? MAY_NOT_BLOCK : 0);
}
static noinline int audit_inode_permission(struct inode *inode,
@@ -2954,15 +2946,9 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
return dentry_has_perm(cred, dentry, av);
}
-static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+static int selinux_inode_getattr(const struct path *path)
{
- const struct cred *cred = current_cred();
- struct path path;
-
- path.dentry = dentry;
- path.mnt = mnt;
-
- return path_has_perm(cred, &path, FILE__GETATTR);
+ return path_has_perm(current_cred(), path, FILE__GETATTR);
}
static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
@@ -2989,7 +2975,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
struct inode_security_struct *isec = inode->i_security;
struct superblock_security_struct *sbsec;
struct common_audit_data ad;
@@ -3066,7 +3052,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size,
int flags)
{
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
struct inode_security_struct *isec = inode->i_security;
u32 newsid;
int rc;
@@ -3139,8 +3125,11 @@ static int selinux_inode_getsecurity(const struct inode *inode, const char *name
* and lack of permission just means that we fall back to the
* in-core context value, not a denial.
*/
- error = selinux_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
- SECURITY_CAP_NOAUDIT);
+ error = cap_capable(current_cred(), &init_user_ns, CAP_MAC_ADMIN,
+ SECURITY_CAP_NOAUDIT);
+ if (!error)
+ error = cred_has_capability(current_cred(), CAP_MAC_ADMIN,
+ SECURITY_CAP_NOAUDIT);
if (!error)
error = security_sid_to_context_force(isec->sid, &context,
&size);
@@ -3325,12 +3314,7 @@ error:
static int selinux_mmap_addr(unsigned long addr)
{
- int rc;
-
- /* do DAC check on address space usage */
- rc = cap_mmap_addr(addr);
- if (rc)
- return rc;
+ int rc = 0;
if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
u32 sid = current_sid();
@@ -3646,23 +3630,11 @@ static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
static int selinux_task_setnice(struct task_struct *p, int nice)
{
- int rc;
-
- rc = cap_task_setnice(p, nice);
- if (rc)
- return rc;
-
return current_has_perm(p, PROCESS__SETSCHED);
}
static int selinux_task_setioprio(struct task_struct *p, int ioprio)
{
- int rc;
-
- rc = cap_task_setioprio(p, ioprio);
- if (rc)
- return rc;
-
return current_has_perm(p, PROCESS__SETSCHED);
}
@@ -3688,12 +3660,6 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
static int selinux_task_setscheduler(struct task_struct *p)
{
- int rc;
-
- rc = cap_task_setscheduler(p);
- if (rc)
- return rc;
-
return current_has_perm(p, PROCESS__SETSCHED);
}
@@ -4652,11 +4618,6 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
}
-static void selinux_skb_owned_by(struct sk_buff *skb, struct sock *sk)
-{
- skb_set_owner_w(skb, sk);
-}
-
static int selinux_secmark_relabel_packet(u32 sid)
{
const struct task_security_struct *__tsec;
@@ -4780,8 +4741,9 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
if (err == -EINVAL) {
printk(KERN_WARNING
"SELinux: unrecognized netlink message:"
- " protocol=%hu nlmsg_type=%hu sclass=%hu\n",
- sk->sk_protocol, nlh->nlmsg_type, sksec->sclass);
+ " protocol=%hu nlmsg_type=%hu sclass=%s\n",
+ sk->sk_protocol, nlh->nlmsg_type,
+ secclass_map[sksec->sclass - 1].name);
if (!selinux_enforcing || security_get_allow_unknown())
err = 0;
}
@@ -4858,21 +4820,17 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
static unsigned int selinux_ipv4_forward(const struct nf_hook_ops *ops,
struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ const struct nf_hook_state *state)
{
- return selinux_ip_forward(skb, in, PF_INET);
+ return selinux_ip_forward(skb, state->in, PF_INET);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ const struct nf_hook_state *state)
{
- return selinux_ip_forward(skb, in, PF_INET6);
+ return selinux_ip_forward(skb, state->in, PF_INET6);
}
#endif /* IPV6 */
@@ -4920,9 +4878,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
static unsigned int selinux_ipv4_output(const struct nf_hook_ops *ops,
struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ const struct nf_hook_state *state)
{
return selinux_ip_output(skb, PF_INET);
}
@@ -5097,21 +5053,17 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
static unsigned int selinux_ipv4_postroute(const struct nf_hook_ops *ops,
struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ const struct nf_hook_state *state)
{
- return selinux_ip_postroute(skb, out, PF_INET);
+ return selinux_ip_postroute(skb, state->out, PF_INET);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ const struct nf_hook_state *state)
{
- return selinux_ip_postroute(skb, out, PF_INET6);
+ return selinux_ip_postroute(skb, state->out, PF_INET6);
}
#endif /* IPV6 */
@@ -5119,12 +5071,6 @@ static unsigned int selinux_ipv6_postroute(const struct nf_hook_ops *ops,
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
- int err;
-
- err = cap_netlink_send(sk, skb);
- if (err)
- return err;
-
return selinux_nlmsg_perm(sk, skb);
}
@@ -5862,219 +5808,220 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
#endif
-static struct security_operations selinux_ops = {
- .name = "selinux",
-
- .binder_set_context_mgr = selinux_binder_set_context_mgr,
- .binder_transaction = selinux_binder_transaction,
- .binder_transfer_binder = selinux_binder_transfer_binder,
- .binder_transfer_file = selinux_binder_transfer_file,
-
- .ptrace_access_check = selinux_ptrace_access_check,
- .ptrace_traceme = selinux_ptrace_traceme,
- .capget = selinux_capget,
- .capset = selinux_capset,
- .capable = selinux_capable,
- .quotactl = selinux_quotactl,
- .quota_on = selinux_quota_on,
- .syslog = selinux_syslog,
- .vm_enough_memory = selinux_vm_enough_memory,
-
- .netlink_send = selinux_netlink_send,
-
- .bprm_set_creds = selinux_bprm_set_creds,
- .bprm_committing_creds = selinux_bprm_committing_creds,
- .bprm_committed_creds = selinux_bprm_committed_creds,
- .bprm_secureexec = selinux_bprm_secureexec,
-
- .sb_alloc_security = selinux_sb_alloc_security,
- .sb_free_security = selinux_sb_free_security,
- .sb_copy_data = selinux_sb_copy_data,
- .sb_remount = selinux_sb_remount,
- .sb_kern_mount = selinux_sb_kern_mount,
- .sb_show_options = selinux_sb_show_options,
- .sb_statfs = selinux_sb_statfs,
- .sb_mount = selinux_mount,
- .sb_umount = selinux_umount,
- .sb_set_mnt_opts = selinux_set_mnt_opts,
- .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts,
- .sb_parse_opts_str = selinux_parse_opts_str,
-
- .dentry_init_security = selinux_dentry_init_security,
-
- .inode_alloc_security = selinux_inode_alloc_security,
- .inode_free_security = selinux_inode_free_security,
- .inode_init_security = selinux_inode_init_security,
- .inode_create = selinux_inode_create,
- .inode_link = selinux_inode_link,
- .inode_unlink = selinux_inode_unlink,
- .inode_symlink = selinux_inode_symlink,
- .inode_mkdir = selinux_inode_mkdir,
- .inode_rmdir = selinux_inode_rmdir,
- .inode_mknod = selinux_inode_mknod,
- .inode_rename = selinux_inode_rename,
- .inode_readlink = selinux_inode_readlink,
- .inode_follow_link = selinux_inode_follow_link,
- .inode_permission = selinux_inode_permission,
- .inode_setattr = selinux_inode_setattr,
- .inode_getattr = selinux_inode_getattr,
- .inode_setxattr = selinux_inode_setxattr,
- .inode_post_setxattr = selinux_inode_post_setxattr,
- .inode_getxattr = selinux_inode_getxattr,
- .inode_listxattr = selinux_inode_listxattr,
- .inode_removexattr = selinux_inode_removexattr,
- .inode_getsecurity = selinux_inode_getsecurity,
- .inode_setsecurity = selinux_inode_setsecurity,
- .inode_listsecurity = selinux_inode_listsecurity,
- .inode_getsecid = selinux_inode_getsecid,
-
- .file_permission = selinux_file_permission,
- .file_alloc_security = selinux_file_alloc_security,
- .file_free_security = selinux_file_free_security,
- .file_ioctl = selinux_file_ioctl,
- .mmap_file = selinux_mmap_file,
- .mmap_addr = selinux_mmap_addr,
- .file_mprotect = selinux_file_mprotect,
- .file_lock = selinux_file_lock,
- .file_fcntl = selinux_file_fcntl,
- .file_set_fowner = selinux_file_set_fowner,
- .file_send_sigiotask = selinux_file_send_sigiotask,
- .file_receive = selinux_file_receive,
-
- .file_open = selinux_file_open,
-
- .task_create = selinux_task_create,
- .cred_alloc_blank = selinux_cred_alloc_blank,
- .cred_free = selinux_cred_free,
- .cred_prepare = selinux_cred_prepare,
- .cred_transfer = selinux_cred_transfer,
- .kernel_act_as = selinux_kernel_act_as,
- .kernel_create_files_as = selinux_kernel_create_files_as,
- .kernel_module_request = selinux_kernel_module_request,
- .task_setpgid = selinux_task_setpgid,
- .task_getpgid = selinux_task_getpgid,
- .task_getsid = selinux_task_getsid,
- .task_getsecid = selinux_task_getsecid,
- .task_setnice = selinux_task_setnice,
- .task_setioprio = selinux_task_setioprio,
- .task_getioprio = selinux_task_getioprio,
- .task_setrlimit = selinux_task_setrlimit,
- .task_setscheduler = selinux_task_setscheduler,
- .task_getscheduler = selinux_task_getscheduler,
- .task_movememory = selinux_task_movememory,
- .task_kill = selinux_task_kill,
- .task_wait = selinux_task_wait,
- .task_to_inode = selinux_task_to_inode,
-
- .ipc_permission = selinux_ipc_permission,
- .ipc_getsecid = selinux_ipc_getsecid,
-
- .msg_msg_alloc_security = selinux_msg_msg_alloc_security,
- .msg_msg_free_security = selinux_msg_msg_free_security,
-
- .msg_queue_alloc_security = selinux_msg_queue_alloc_security,
- .msg_queue_free_security = selinux_msg_queue_free_security,
- .msg_queue_associate = selinux_msg_queue_associate,
- .msg_queue_msgctl = selinux_msg_queue_msgctl,
- .msg_queue_msgsnd = selinux_msg_queue_msgsnd,
- .msg_queue_msgrcv = selinux_msg_queue_msgrcv,
-
- .shm_alloc_security = selinux_shm_alloc_security,
- .shm_free_security = selinux_shm_free_security,
- .shm_associate = selinux_shm_associate,
- .shm_shmctl = selinux_shm_shmctl,
- .shm_shmat = selinux_shm_shmat,
-
- .sem_alloc_security = selinux_sem_alloc_security,
- .sem_free_security = selinux_sem_free_security,
- .sem_associate = selinux_sem_associate,
- .sem_semctl = selinux_sem_semctl,
- .sem_semop = selinux_sem_semop,
-
- .d_instantiate = selinux_d_instantiate,
-
- .getprocattr = selinux_getprocattr,
- .setprocattr = selinux_setprocattr,
-
- .ismaclabel = selinux_ismaclabel,
- .secid_to_secctx = selinux_secid_to_secctx,
- .secctx_to_secid = selinux_secctx_to_secid,
- .release_secctx = selinux_release_secctx,
- .inode_notifysecctx = selinux_inode_notifysecctx,
- .inode_setsecctx = selinux_inode_setsecctx,
- .inode_getsecctx = selinux_inode_getsecctx,
-
- .unix_stream_connect = selinux_socket_unix_stream_connect,
- .unix_may_send = selinux_socket_unix_may_send,
-
- .socket_create = selinux_socket_create,
- .socket_post_create = selinux_socket_post_create,
- .socket_bind = selinux_socket_bind,
- .socket_connect = selinux_socket_connect,
- .socket_listen = selinux_socket_listen,
- .socket_accept = selinux_socket_accept,
- .socket_sendmsg = selinux_socket_sendmsg,
- .socket_recvmsg = selinux_socket_recvmsg,
- .socket_getsockname = selinux_socket_getsockname,
- .socket_getpeername = selinux_socket_getpeername,
- .socket_getsockopt = selinux_socket_getsockopt,
- .socket_setsockopt = selinux_socket_setsockopt,
- .socket_shutdown = selinux_socket_shutdown,
- .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb,
- .socket_getpeersec_stream = selinux_socket_getpeersec_stream,
- .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram,
- .sk_alloc_security = selinux_sk_alloc_security,
- .sk_free_security = selinux_sk_free_security,
- .sk_clone_security = selinux_sk_clone_security,
- .sk_getsecid = selinux_sk_getsecid,
- .sock_graft = selinux_sock_graft,
- .inet_conn_request = selinux_inet_conn_request,
- .inet_csk_clone = selinux_inet_csk_clone,
- .inet_conn_established = selinux_inet_conn_established,
- .secmark_relabel_packet = selinux_secmark_relabel_packet,
- .secmark_refcount_inc = selinux_secmark_refcount_inc,
- .secmark_refcount_dec = selinux_secmark_refcount_dec,
- .req_classify_flow = selinux_req_classify_flow,
- .tun_dev_alloc_security = selinux_tun_dev_alloc_security,
- .tun_dev_free_security = selinux_tun_dev_free_security,
- .tun_dev_create = selinux_tun_dev_create,
- .tun_dev_attach_queue = selinux_tun_dev_attach_queue,
- .tun_dev_attach = selinux_tun_dev_attach,
- .tun_dev_open = selinux_tun_dev_open,
- .skb_owned_by = selinux_skb_owned_by,
+static struct security_hook_list selinux_hooks[] = {
+ LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
+ LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
+ LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
+ LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),
+
+ LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check),
+ LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme),
+ LSM_HOOK_INIT(capget, selinux_capget),
+ LSM_HOOK_INIT(capset, selinux_capset),
+ LSM_HOOK_INIT(capable, selinux_capable),
+ LSM_HOOK_INIT(quotactl, selinux_quotactl),
+ LSM_HOOK_INIT(quota_on, selinux_quota_on),
+ LSM_HOOK_INIT(syslog, selinux_syslog),
+ LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory),
+
+ LSM_HOOK_INIT(netlink_send, selinux_netlink_send),
+
+ LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
+ LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
+ LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
+ LSM_HOOK_INIT(bprm_secureexec, selinux_bprm_secureexec),
+
+ LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
+ LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
+ LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data),
+ LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
+ LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
+ LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
+ LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
+ LSM_HOOK_INIT(sb_mount, selinux_mount),
+ LSM_HOOK_INIT(sb_umount, selinux_umount),
+ LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
+ LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
+ LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str),
+
+ LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
+
+ LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
+ LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
+ LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
+ LSM_HOOK_INIT(inode_create, selinux_inode_create),
+ LSM_HOOK_INIT(inode_link, selinux_inode_link),
+ LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
+ LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink),
+ LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir),
+ LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir),
+ LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod),
+ LSM_HOOK_INIT(inode_rename, selinux_inode_rename),
+ LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink),
+ LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link),
+ LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
+ LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
+ LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
+ LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
+ LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
+ LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
+ LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
+ LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
+ LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
+ LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
+ LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
+ LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
+
+ 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),
+ LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
+ LSM_HOOK_INIT(file_lock, selinux_file_lock),
+ LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl),
+ LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner),
+ LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask),
+ LSM_HOOK_INIT(file_receive, selinux_file_receive),
+
+ LSM_HOOK_INIT(file_open, selinux_file_open),
+
+ LSM_HOOK_INIT(task_create, selinux_task_create),
+ 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(kernel_act_as, selinux_kernel_act_as),
+ LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
+ LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
+ LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
+ LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
+ LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
+ LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid),
+ LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
+ LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
+ LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
+ LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit),
+ LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler),
+ LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
+ LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
+ LSM_HOOK_INIT(task_kill, selinux_task_kill),
+ LSM_HOOK_INIT(task_wait, selinux_task_wait),
+ LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
+
+ LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
+ 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),
+
+ LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),
+
+ LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
+ LSM_HOOK_INIT(setprocattr, selinux_setprocattr),
+
+ LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
+ LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
+ LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
+ LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
+ LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
+ LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
+ LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
+
+ LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect),
+ LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send),
+
+ LSM_HOOK_INIT(socket_create, selinux_socket_create),
+ LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create),
+ LSM_HOOK_INIT(socket_bind, selinux_socket_bind),
+ LSM_HOOK_INIT(socket_connect, selinux_socket_connect),
+ LSM_HOOK_INIT(socket_listen, selinux_socket_listen),
+ LSM_HOOK_INIT(socket_accept, selinux_socket_accept),
+ LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg),
+ LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg),
+ LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname),
+ LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername),
+ LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
+ LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
+ LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
+ LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
+ LSM_HOOK_INIT(socket_getpeersec_stream,
+ selinux_socket_getpeersec_stream),
+ LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram),
+ LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
+ LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security),
+ LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
+ LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
+ LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
+ LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
+ LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
+ LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
+ LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet),
+ LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
+ LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
+ LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
+ LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
+ LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
+ LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
+ LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
+ LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
+ LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
#ifdef CONFIG_SECURITY_NETWORK_XFRM
- .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
- .xfrm_policy_clone_security = selinux_xfrm_policy_clone,
- .xfrm_policy_free_security = selinux_xfrm_policy_free,
- .xfrm_policy_delete_security = selinux_xfrm_policy_delete,
- .xfrm_state_alloc = selinux_xfrm_state_alloc,
- .xfrm_state_alloc_acquire = selinux_xfrm_state_alloc_acquire,
- .xfrm_state_free_security = selinux_xfrm_state_free,
- .xfrm_state_delete_security = selinux_xfrm_state_delete,
- .xfrm_policy_lookup = selinux_xfrm_policy_lookup,
- .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match,
- .xfrm_decode_session = selinux_xfrm_decode_session,
+ LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc),
+ LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
+ LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free),
+ LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete),
+ LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc),
+ LSM_HOOK_INIT(xfrm_state_alloc_acquire,
+ selinux_xfrm_state_alloc_acquire),
+ LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free),
+ LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete),
+ LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup),
+ LSM_HOOK_INIT(xfrm_state_pol_flow_match,
+ selinux_xfrm_state_pol_flow_match),
+ LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session),
#endif
#ifdef CONFIG_KEYS
- .key_alloc = selinux_key_alloc,
- .key_free = selinux_key_free,
- .key_permission = selinux_key_permission,
- .key_getsecurity = selinux_key_getsecurity,
+ LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
+ LSM_HOOK_INIT(key_free, selinux_key_free),
+ LSM_HOOK_INIT(key_permission, selinux_key_permission),
+ LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
#endif
#ifdef CONFIG_AUDIT
- .audit_rule_init = selinux_audit_rule_init,
- .audit_rule_known = selinux_audit_rule_known,
- .audit_rule_match = selinux_audit_rule_match,
- .audit_rule_free = selinux_audit_rule_free,
+ LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
+ LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
+ LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
+ LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
#endif
};
static __init int selinux_init(void)
{
- if (!security_module_enable(&selinux_ops)) {
+ if (!security_module_enable("selinux")) {
selinux_enabled = 0;
return 0;
}
@@ -6096,8 +6043,7 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL);
avc_init();
- if (register_security(&selinux_ops))
- panic("SELinux: Unable to register with kernel.\n");
+ security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC netcache callback\n");
@@ -6225,7 +6171,7 @@ int selinux_disable(void)
selinux_disabled = 1;
selinux_enabled = 0;
- reset_security_ops();
+ security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
/* Try to destroy the avc node cache */
avc_disable();
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index ddf8eec03f21..5973c327c54e 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -130,7 +130,8 @@ static inline int avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd,
int result,
- struct common_audit_data *a)
+ struct common_audit_data *a,
+ int flags)
{
u32 audited, denied;
audited = avc_audit_required(requested, avd, result, 0, &denied);
@@ -138,7 +139,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
return 0;
return slow_avc_audit(ssid, tsid, tclass,
requested, audited, denied, result,
- a, 0);
+ a, flags);
}
#define AVC_STRICT 1 /* Ignore permissive mode. */
@@ -150,6 +151,10 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
int avc_has_perm(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct common_audit_data *auditdata);
+int avc_has_perm_flags(u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct common_audit_data *auditdata,
+ int flags);
u32 avc_policy_seqno(void);
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h
index eccd61b3de8a..5a4eef59aeff 100644
--- a/security/selinux/include/classmap.h
+++ b/security/selinux/include/classmap.h
@@ -2,12 +2,12 @@
"getattr", "setattr", "lock", "relabelfrom", "relabelto", "append"
#define COMMON_FILE_PERMS COMMON_FILE_SOCK_PERMS, "unlink", "link", \
- "rename", "execute", "swapon", "quotaon", "mounton", "audit_access", \
+ "rename", "execute", "quotaon", "mounton", "audit_access", \
"open", "execmod"
#define COMMON_SOCK_PERMS COMMON_FILE_SOCK_PERMS, "bind", "connect", \
"listen", "accept", "getopt", "setopt", "shutdown", "recvfrom", \
- "sendto", "recv_msg", "send_msg", "name_bind"
+ "sendto", "name_bind"
#define COMMON_IPC_PERMS "create", "destroy", "getattr", "setattr", "read", \
"write", "associate", "unix_read", "unix_write"
@@ -44,7 +44,7 @@ struct security_class_mapping secclass_map[] = {
"audit_control", "setfcap", NULL } },
{ "filesystem",
{ "mount", "remount", "unmount", "getattr",
- "relabelfrom", "relabelto", "transition", "associate", "quotamod",
+ "relabelfrom", "relabelto", "associate", "quotamod",
"quotaget", NULL } },
{ "file",
{ COMMON_FILE_PERMS,
@@ -67,7 +67,7 @@ struct security_class_mapping secclass_map[] = {
{ COMMON_SOCK_PERMS, NULL } },
{ "tcp_socket",
{ COMMON_SOCK_PERMS,
- "connectto", "newconn", "acceptfrom", "node_bind", "name_connect",
+ "node_bind", "name_connect",
NULL } },
{ "udp_socket",
{ COMMON_SOCK_PERMS,
@@ -76,13 +76,9 @@ struct security_class_mapping secclass_map[] = {
{ COMMON_SOCK_PERMS,
"node_bind", NULL } },
{ "node",
- { "tcp_recv", "tcp_send", "udp_recv", "udp_send",
- "rawip_recv", "rawip_send", "enforce_dest",
- "dccp_recv", "dccp_send", "recvfrom", "sendto", NULL } },
+ { "recvfrom", "sendto", NULL } },
{ "netif",
- { "tcp_recv", "tcp_send", "udp_recv", "udp_send",
- "rawip_recv", "rawip_send", "dccp_recv", "dccp_send",
- "ingress", "egress", NULL } },
+ { "ingress", "egress", NULL } },
{ "netlink_socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "packet_socket",
@@ -90,11 +86,9 @@ struct security_class_mapping secclass_map[] = {
{ "key_socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "unix_stream_socket",
- { COMMON_SOCK_PERMS, "connectto", "newconn", "acceptfrom", NULL
- } },
+ { COMMON_SOCK_PERMS, "connectto", NULL } },
{ "unix_dgram_socket",
- { COMMON_SOCK_PERMS, NULL
- } },
+ { COMMON_SOCK_PERMS, NULL } },
{ "sem",
{ COMMON_IPC_PERMS, NULL } },
{ "msg", { "send", "receive", NULL } },
@@ -107,9 +101,6 @@ struct security_class_mapping secclass_map[] = {
{ "netlink_route_socket",
{ COMMON_SOCK_PERMS,
"nlmsg_read", "nlmsg_write", NULL } },
- { "netlink_firewall_socket",
- { COMMON_SOCK_PERMS,
- "nlmsg_read", "nlmsg_write", NULL } },
{ "netlink_tcpdiag_socket",
{ COMMON_SOCK_PERMS,
"nlmsg_read", "nlmsg_write", NULL } },
@@ -120,19 +111,32 @@ struct security_class_mapping secclass_map[] = {
"nlmsg_read", "nlmsg_write", NULL } },
{ "netlink_selinux_socket",
{ COMMON_SOCK_PERMS, NULL } },
+ { "netlink_iscsi_socket",
+ { COMMON_SOCK_PERMS, NULL } },
{ "netlink_audit_socket",
{ COMMON_SOCK_PERMS,
"nlmsg_read", "nlmsg_write", "nlmsg_relay", "nlmsg_readpriv",
"nlmsg_tty_audit", NULL } },
- { "netlink_ip6fw_socket",
- { COMMON_SOCK_PERMS,
- "nlmsg_read", "nlmsg_write", NULL } },
+ { "netlink_fib_lookup_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "netlink_connector_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "netlink_netfilter_socket",
+ { COMMON_SOCK_PERMS, NULL } },
{ "netlink_dnrt_socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "association",
{ "sendto", "recvfrom", "setcontext", "polmatch", NULL } },
{ "netlink_kobject_uevent_socket",
{ COMMON_SOCK_PERMS, NULL } },
+ { "netlink_generic_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "netlink_scsitransport_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "netlink_rdma_socket",
+ { COMMON_SOCK_PERMS, NULL } },
+ { "netlink_crypto_socket",
+ { COMMON_SOCK_PERMS, NULL } },
{ "appletalk_socket",
{ COMMON_SOCK_PERMS, NULL } },
{ "packet",
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index d1e0b239b602..36993ad1c067 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -56,6 +56,7 @@
/* Non-mount related flags */
#define SE_SBINITIALIZED 0x0100
#define SE_SBPROC 0x0200
+#define SE_SBGENFS 0x0400
#define CONTEXT_STR "context="
#define FSCONTEXT_STR "fscontext="
diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c
index 2df7b900e259..2bbb41822d8e 100644
--- a/security/selinux/nlmsgtab.c
+++ b/security/selinux/nlmsgtab.c
@@ -73,6 +73,9 @@ static struct nlmsg_perm nlmsg_route_perms[] =
{ RTM_NEWMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_DELMDB, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
{ RTM_GETMDB, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWNSID, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETNSID, NETLINK_ROUTE_SOCKET__NLMSG_READ },
};
static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
@@ -100,6 +103,13 @@ static struct nlmsg_perm nlmsg_xfrm_perms[] =
{ XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
{ XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_REPORT, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_MIGRATE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_NEWSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_GETSADINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_NEWSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETSPDINFO, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_MAPPING, NETLINK_XFRM_SOCKET__NLMSG_READ },
};
static struct nlmsg_perm nlmsg_audit_perms[] =
@@ -143,6 +153,8 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
switch (sclass) {
case SECCLASS_NETLINK_ROUTE_SOCKET:
+ /* RTM_MAX always point to RTM_SETxxxx, ie RTM_NEWxxx + 3 */
+ BUILD_BUG_ON(RTM_MAX != (RTM_NEWNSID + 3));
err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms,
sizeof(nlmsg_route_perms));
break;
@@ -153,6 +165,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm)
break;
case SECCLASS_NETLINK_XFRM_SOCKET:
+ BUILD_BUG_ON(XFRM_MSG_MAX != XFRM_MSG_MAPPING);
err = nlmsg_perm(nlmsg_type, perm, nlmsg_xfrm_perms,
sizeof(nlmsg_xfrm_perms));
break;
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 5fde34326dcf..d2787cca1fcb 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1737,7 +1737,7 @@ static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
inc_nlink(inode);
d_add(dentry, inode);
/* bump link count on parent directory, too */
- inc_nlink(dir->d_inode);
+ inc_nlink(d_inode(dir));
return dentry;
}
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index a3dd9faa19c0..b64f2772b030 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -25,10 +25,43 @@
static struct kmem_cache *avtab_node_cachep;
-static inline int avtab_hash(struct avtab_key *keyp, u16 mask)
+/* Based on MurmurHash3, written by Austin Appleby and placed in the
+ * public domain.
+ */
+static inline int avtab_hash(struct avtab_key *keyp, u32 mask)
{
- return ((keyp->target_class + (keyp->target_type << 2) +
- (keyp->source_type << 9)) & mask);
+ static const u32 c1 = 0xcc9e2d51;
+ static const u32 c2 = 0x1b873593;
+ static const u32 r1 = 15;
+ static const u32 r2 = 13;
+ static const u32 m = 5;
+ static const u32 n = 0xe6546b64;
+
+ u32 hash = 0;
+
+#define mix(input) { \
+ u32 v = input; \
+ v *= c1; \
+ v = (v << r1) | (v >> (32 - r1)); \
+ v *= c2; \
+ hash ^= v; \
+ hash = (hash << r2) | (hash >> (32 - r2)); \
+ hash = hash * m + n; \
+}
+
+ mix(keyp->target_class);
+ mix(keyp->target_type);
+ mix(keyp->source_type);
+
+#undef mix
+
+ hash ^= hash >> 16;
+ hash *= 0x85ebca6b;
+ hash ^= hash >> 13;
+ hash *= 0xc2b2ae35;
+ hash ^= hash >> 16;
+
+ return hash & mask;
}
static struct avtab_node*
@@ -46,8 +79,12 @@ avtab_insert_node(struct avtab *h, int hvalue,
newnode->next = prev->next;
prev->next = newnode;
} else {
- newnode->next = h->htable[hvalue];
- h->htable[hvalue] = newnode;
+ newnode->next = flex_array_get_ptr(h->htable, hvalue);
+ if (flex_array_put_ptr(h->htable, hvalue, newnode,
+ GFP_KERNEL|__GFP_ZERO)) {
+ kmem_cache_free(avtab_node_cachep, newnode);
+ return NULL;
+ }
}
h->nel++;
@@ -64,7 +101,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat
return -EINVAL;
hvalue = avtab_hash(key, h->mask);
- for (prev = NULL, cur = h->htable[hvalue];
+ for (prev = NULL, cur = flex_array_get_ptr(h->htable, hvalue);
cur;
prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
@@ -104,7 +141,7 @@ avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datu
if (!h || !h->htable)
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (prev = NULL, cur = h->htable[hvalue];
+ for (prev = NULL, cur = flex_array_get_ptr(h->htable, hvalue);
cur;
prev = cur, cur = cur->next) {
if (key->source_type == cur->key.source_type &&
@@ -135,7 +172,8 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+ for (cur = flex_array_get_ptr(h->htable, hvalue); cur;
+ cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
@@ -170,7 +208,8 @@ avtab_search_node(struct avtab *h, struct avtab_key *key)
return NULL;
hvalue = avtab_hash(key, h->mask);
- for (cur = h->htable[hvalue]; cur; cur = cur->next) {
+ for (cur = flex_array_get_ptr(h->htable, hvalue); cur;
+ cur = cur->next) {
if (key->source_type == cur->key.source_type &&
key->target_type == cur->key.target_type &&
key->target_class == cur->key.target_class &&
@@ -228,15 +267,14 @@ void avtab_destroy(struct avtab *h)
return;
for (i = 0; i < h->nslot; i++) {
- cur = h->htable[i];
+ cur = flex_array_get_ptr(h->htable, i);
while (cur) {
temp = cur;
cur = cur->next;
kmem_cache_free(avtab_node_cachep, temp);
}
- h->htable[i] = NULL;
}
- kfree(h->htable);
+ flex_array_free(h->htable);
h->htable = NULL;
h->nslot = 0;
h->mask = 0;
@@ -251,7 +289,7 @@ int avtab_init(struct avtab *h)
int avtab_alloc(struct avtab *h, u32 nrules)
{
- u16 mask = 0;
+ u32 mask = 0;
u32 shift = 0;
u32 work = nrules;
u32 nslot = 0;
@@ -270,7 +308,8 @@ int avtab_alloc(struct avtab *h, u32 nrules)
nslot = MAX_AVTAB_HASH_BUCKETS;
mask = nslot - 1;
- h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
+ h->htable = flex_array_alloc(sizeof(struct avtab_node *), nslot,
+ GFP_KERNEL | __GFP_ZERO);
if (!h->htable)
return -ENOMEM;
@@ -293,7 +332,7 @@ void avtab_hash_eval(struct avtab *h, char *tag)
max_chain_len = 0;
chain2_len_sum = 0;
for (i = 0; i < h->nslot; i++) {
- cur = h->htable[i];
+ cur = flex_array_get_ptr(h->htable, i);
if (cur) {
slots_used++;
chain_len = 0;
@@ -534,7 +573,8 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp)
return rc;
for (i = 0; i < a->nslot; i++) {
- for (cur = a->htable[i]; cur; cur = cur->next) {
+ for (cur = flex_array_get_ptr(a->htable, i); cur;
+ cur = cur->next) {
rc = avtab_write_item(p, cur, fp);
if (rc)
return rc;
diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h
index 63ce2f9e441d..adb451cd44f9 100644
--- a/security/selinux/ss/avtab.h
+++ b/security/selinux/ss/avtab.h
@@ -23,6 +23,8 @@
#ifndef _SS_AVTAB_H_
#define _SS_AVTAB_H_
+#include <linux/flex_array.h>
+
struct avtab_key {
u16 source_type; /* source type */
u16 target_type; /* target type */
@@ -51,10 +53,10 @@ struct avtab_node {
};
struct avtab {
- struct avtab_node **htable;
+ struct flex_array *htable;
u32 nel; /* number of elements */
u32 nslot; /* number of hash slots */
- u16 mask; /* mask to compute hash func */
+ u32 mask; /* mask to compute hash func */
};
@@ -84,7 +86,7 @@ struct avtab_node *avtab_search_node_next(struct avtab_node *node, int specified
void avtab_cache_init(void);
void avtab_cache_destroy(void);
-#define MAX_AVTAB_HASH_BITS 11
+#define MAX_AVTAB_HASH_BITS 16
#define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
#endif /* _SS_AVTAB_H_ */
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index d307b37ddc2b..e1088842232c 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -654,19 +654,15 @@ int mls_import_netlbl_cat(struct context *context,
rc = ebitmap_netlbl_import(&context->range.level[0].cat,
secattr->attr.mls.cat);
- if (rc != 0)
- goto import_netlbl_cat_failure;
-
- rc = ebitmap_cpy(&context->range.level[1].cat,
- &context->range.level[0].cat);
- if (rc != 0)
+ if (rc)
goto import_netlbl_cat_failure;
+ memcpy(&context->range.level[1].cat, &context->range.level[0].cat,
+ sizeof(context->range.level[0].cat));
return 0;
import_netlbl_cat_failure:
ebitmap_destroy(&context->range.level[0].cat);
- ebitmap_destroy(&context->range.level[1].cat);
return rc;
}
#endif /* CONFIG_NETLABEL */
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index a1d3944751b9..9e2d82070915 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -3179,13 +3179,9 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
ctx_new.type = ctx->type;
mls_import_netlbl_lvl(&ctx_new, secattr);
if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
- rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat,
- secattr->attr.mls.cat);
+ rc = mls_import_netlbl_cat(&ctx_new, secattr);
if (rc)
goto out;
- memcpy(&ctx_new.range.level[1].cat,
- &ctx_new.range.level[0].cat,
- sizeof(ctx_new.range.level[0].cat));
}
rc = -EIDRM;
if (!mls_context_isvalid(&policydb, &ctx_new))
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 98b042630a9e..56e354fcdfc6 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -35,9 +35,6 @@
#include <linux/init.h>
#include <linux/security.h>
#include <linux/types.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv6.h>
#include <linux/slab.h>
#include <linux/ip.h>
#include <linux/tcp.h>
diff --git a/security/smack/smack.h b/security/smack/smack.h
index 67ccb7b2b89b..244e035e5a99 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -15,7 +15,7 @@
#include <linux/capability.h>
#include <linux/spinlock.h>
-#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/in.h>
#include <net/netlabel.h>
#include <linux/list.h>
@@ -105,6 +105,7 @@ struct task_smack {
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */
#define SMK_INODE_CHANGED 0x04 /* smack was transmuted */
+#define SMK_INODE_IMPURE 0x08 /* involved in an impure transaction */
/*
* A label access rule.
@@ -137,6 +138,11 @@ struct smk_port_label {
struct smack_known *smk_out; /* outgoing label */
};
+struct smack_onlycap {
+ struct list_head list;
+ struct smack_known *smk_label;
+};
+
/*
* Mount options
*/
@@ -193,6 +199,10 @@ struct smk_port_label {
#define MAY_LOCK 0x00002000 /* Locks should be writes, but ... */
#define MAY_BRINGUP 0x00004000 /* Report use of this rule */
+#define SMACK_BRINGUP_ALLOW 1 /* Allow bringup mode */
+#define SMACK_UNCONFINED_SUBJECT 2 /* Allow unconfined label */
+#define SMACK_UNCONFINED_OBJECT 3 /* Allow unconfined label */
+
/*
* Just to make the common cases easier to deal with
*/
@@ -244,6 +254,7 @@ int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
+int smack_privileged(int cap);
/*
* Shared data.
@@ -252,8 +263,10 @@ extern int smack_enabled;
extern int smack_cipso_direct;
extern int smack_cipso_mapped;
extern struct smack_known *smack_net_ambient;
-extern struct smack_known *smack_onlycap;
extern struct smack_known *smack_syslog_label;
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+extern struct smack_known *smack_unconfined;
+#endif
extern struct smack_known smack_cipso_option;
extern int smack_ptrace_rule;
@@ -268,7 +281,8 @@ extern struct mutex smack_known_lock;
extern struct list_head smack_known_list;
extern struct list_head smk_netlbladdr_list;
-extern struct security_operations smack_ops;
+extern struct mutex smack_onlycap_lock;
+extern struct list_head smack_onlycap_list;
#define SMACK_HASH_SLOTS 16
extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
@@ -326,21 +340,6 @@ static inline struct smack_known *smk_of_current(void)
}
/*
- * Is the task privileged and allowed to be privileged
- * by the onlycap rule.
- */
-static inline int smack_privileged(int cap)
-{
- struct smack_known *skp = smk_of_current();
-
- if (!capable(cap))
- return 0;
- if (smack_onlycap == NULL || smack_onlycap == skp)
- return 1;
- return 0;
-}
-
-/*
* logging functions
*/
#define SMACK_AUDIT_DENIED 0x1
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 1158430f5bb9..00f6b38bffbd 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -130,7 +130,8 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
/*
* Hardcoded comparisons.
- *
+ */
+ /*
* A star subject can't access any object.
*/
if (subject == &smack_known_star) {
@@ -189,10 +190,20 @@ int smk_access(struct smack_known *subject, struct smack_known *object,
* succeed because of "b" rules.
*/
if (may & MAY_BRINGUP)
- rc = MAY_BRINGUP;
+ rc = SMACK_BRINGUP_ALLOW;
#endif
out_audit:
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+ if (rc < 0) {
+ if (object == smack_unconfined)
+ rc = SMACK_UNCONFINED_OBJECT;
+ if (subject == smack_unconfined)
+ rc = SMACK_UNCONFINED_SUBJECT;
+ }
+#endif
+
#ifdef CONFIG_AUDIT
if (a)
smack_log(subject->smk_known, object->smk_known,
@@ -338,19 +349,16 @@ static void smack_log_callback(struct audit_buffer *ab, void *a)
void smack_log(char *subject_label, char *object_label, int request,
int result, struct smk_audit_info *ad)
{
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+ char request_buffer[SMK_NUM_ACCESS_TYPE + 5];
+#else
char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
+#endif
struct smack_audit_data *sad;
struct common_audit_data *a = &ad->a;
-#ifdef CONFIG_SECURITY_SMACK_BRINGUP
- /*
- * The result may be positive in bringup mode.
- */
- if (result > 0)
- result = 0;
-#endif
/* check if we have to log the current event */
- if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
+ if (result < 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
return;
if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
return;
@@ -364,6 +372,21 @@ void smack_log(char *subject_label, char *object_label, int request,
smack_str_from_perm(request_buffer, request);
sad->subject = subject_label;
sad->object = object_label;
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+ /*
+ * The result may be positive in bringup mode.
+ * A positive result is an allow, but not for normal reasons.
+ * Mark it as successful, but don't filter it out even if
+ * the logging policy says to do so.
+ */
+ if (result == SMACK_UNCONFINED_SUBJECT)
+ strcat(request_buffer, "(US)");
+ else if (result == SMACK_UNCONFINED_OBJECT)
+ strcat(request_buffer, "(UO)");
+
+ if (result > 0)
+ result = 0;
+#endif
sad->request = request_buffer;
sad->result = result;
@@ -402,7 +425,7 @@ void smk_insert_entry(struct smack_known *skp)
* @string: a text string that might be a Smack label
*
* Returns a pointer to the entry in the label list that
- * matches the passed string.
+ * matches the passed string or NULL if not found.
*/
struct smack_known *smk_find_entry(const char *string)
{
@@ -425,7 +448,7 @@ struct smack_known *smk_find_entry(const char *string)
* @string: a text string that might contain a Smack label
* @len: the maximum size, or zero if it is NULL terminated.
*
- * Returns a pointer to the clean label, or NULL
+ * Returns a pointer to the clean label or an error code.
*/
char *smk_parse_smack(const char *string, int len)
{
@@ -441,7 +464,7 @@ char *smk_parse_smack(const char *string, int len)
* including /smack/cipso and /smack/cipso2
*/
if (string[0] == '-')
- return NULL;
+ return ERR_PTR(-EINVAL);
for (i = 0; i < len; i++)
if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
@@ -449,11 +472,13 @@ char *smk_parse_smack(const char *string, int len)
break;
if (i == 0 || i >= SMK_LONGLABEL)
- return NULL;
+ return ERR_PTR(-EINVAL);
smack = kzalloc(i + 1, GFP_KERNEL);
- if (smack != NULL)
- strncpy(smack, string, i);
+ if (smack == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ strncpy(smack, string, i);
return smack;
}
@@ -500,7 +525,8 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
* @len: the maximum size, or zero if it is NULL terminated.
*
* Returns a pointer to the entry in the label list that
- * matches the passed string, adding it if necessary.
+ * matches the passed string, adding it if necessary,
+ * or an error code.
*/
struct smack_known *smk_import_entry(const char *string, int len)
{
@@ -510,8 +536,8 @@ struct smack_known *smk_import_entry(const char *string, int len)
int rc;
smack = smk_parse_smack(string, len);
- if (smack == NULL)
- return NULL;
+ if (IS_ERR(smack))
+ return ERR_CAST(smack);
mutex_lock(&smack_known_lock);
@@ -520,8 +546,10 @@ struct smack_known *smk_import_entry(const char *string, int len)
goto freeout;
skp = kzalloc(sizeof(*skp), GFP_KERNEL);
- if (skp == NULL)
+ if (skp == NULL) {
+ skp = ERR_PTR(-ENOMEM);
goto freeout;
+ }
skp->smk_known = smack;
skp->smk_secid = smack_next_secid++;
@@ -554,7 +582,7 @@ struct smack_known *smk_import_entry(const char *string, int len)
* smk_netlbl_mls failed.
*/
kfree(skp);
- skp = NULL;
+ skp = ERR_PTR(rc);
freeout:
kfree(smack);
unlockout:
@@ -589,3 +617,44 @@ struct smack_known *smack_from_secid(const u32 secid)
rcu_read_unlock();
return &smack_known_invalid;
}
+
+/*
+ * Unless a process is running with one of these labels
+ * even having CAP_MAC_OVERRIDE isn't enough to grant
+ * privilege to violate MAC policy. If no labels are
+ * designated (the empty list case) capabilities apply to
+ * everyone.
+ */
+LIST_HEAD(smack_onlycap_list);
+DEFINE_MUTEX(smack_onlycap_lock);
+
+/*
+ * Is the task privileged and allowed to be privileged
+ * by the onlycap rule.
+ *
+ * Returns 1 if the task is allowed to be privileged, 0 if it's not.
+ */
+int smack_privileged(int cap)
+{
+ struct smack_known *skp = smk_of_current();
+ struct smack_onlycap *sop;
+
+ if (!capable(cap))
+ return 0;
+
+ rcu_read_lock();
+ if (list_empty(&smack_onlycap_list)) {
+ rcu_read_unlock();
+ return 1;
+ }
+
+ list_for_each_entry_rcu(sop, &smack_onlycap_list, list) {
+ if (sop->smk_label == skp) {
+ rcu_read_unlock();
+ return 1;
+ }
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index c934311812f1..a143328f75eb 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -57,6 +57,13 @@ static struct kmem_cache *smack_inode_cache;
int smack_enabled;
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+static char *smk_bu_mess[] = {
+ "Bringup Error", /* Unused */
+ "Bringup", /* SMACK_BRINGUP_ALLOW */
+ "Unconfined Subject", /* SMACK_UNCONFINED_SUBJECT */
+ "Unconfined Object", /* SMACK_UNCONFINED_OBJECT */
+};
+
static void smk_bu_mode(int mode, char *s)
{
int i = 0;
@@ -87,9 +94,11 @@ static int smk_bu_note(char *note, struct smack_known *sskp,
if (rc <= 0)
return rc;
+ if (rc > SMACK_UNCONFINED_OBJECT)
+ rc = 0;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) %s\n",
+ pr_info("Smack %s: (%s %s %s) %s\n", smk_bu_mess[rc],
sskp->smk_known, oskp->smk_known, acc, note);
return 0;
}
@@ -106,9 +115,11 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
if (rc <= 0)
return rc;
+ if (rc > SMACK_UNCONFINED_OBJECT)
+ rc = 0;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) %s %s\n",
+ pr_info("Smack %s: (%s %s %s) %s %s\n", smk_bu_mess[rc],
tsp->smk_task->smk_known, oskp->smk_known,
acc, current->comm, note);
return 0;
@@ -126,9 +137,11 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc)
if (rc <= 0)
return rc;
+ if (rc > SMACK_UNCONFINED_OBJECT)
+ rc = 0;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) %s to %s\n",
+ pr_info("Smack %s: (%s %s %s) %s to %s\n", smk_bu_mess[rc],
tsp->smk_task->smk_known, smk_task->smk_known, acc,
current->comm, otp->comm);
return 0;
@@ -141,14 +154,25 @@ 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 = current_security();
+ struct inode_smack *isp = inode->i_security;
char acc[SMK_NUM_ACCESS_TYPE + 1];
+ if (isp->smk_flags & SMK_INODE_IMPURE)
+ pr_info("Smack Unconfined Corruption: inode=(%s %ld) %s\n",
+ inode->i_sb->s_id, inode->i_ino, current->comm);
+
if (rc <= 0)
return rc;
+ if (rc > SMACK_UNCONFINED_OBJECT)
+ rc = 0;
+ if (rc == SMACK_UNCONFINED_SUBJECT &&
+ (mode & (MAY_WRITE | MAY_APPEND)))
+ isp->smk_flags |= SMK_INODE_IMPURE;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) inode=(%s %ld) %s\n",
- tsp->smk_task->smk_known, smk_of_inode(inode)->smk_known, acc,
+
+ pr_info("Smack %s: (%s %s %s) inode=(%s %ld) %s\n", smk_bu_mess[rc],
+ tsp->smk_task->smk_known, isp->smk_inode->smk_known, acc,
inode->i_sb->s_id, inode->i_ino, current->comm);
return 0;
}
@@ -162,13 +186,20 @@ static int smk_bu_file(struct file *file, int mode, int rc)
struct task_smack *tsp = current_security();
struct smack_known *sskp = tsp->smk_task;
struct inode *inode = file_inode(file);
+ struct inode_smack *isp = inode->i_security;
char acc[SMK_NUM_ACCESS_TYPE + 1];
+ if (isp->smk_flags & SMK_INODE_IMPURE)
+ pr_info("Smack Unconfined Corruption: inode=(%s %ld) %s\n",
+ inode->i_sb->s_id, inode->i_ino, current->comm);
+
if (rc <= 0)
return rc;
+ if (rc > SMACK_UNCONFINED_OBJECT)
+ rc = 0;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
+ pr_info("Smack %s: (%s %s %s) file=(%s %ld %pD) %s\n", smk_bu_mess[rc],
sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
inode->i_sb->s_id, inode->i_ino, file,
current->comm);
@@ -185,13 +216,20 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
struct task_smack *tsp = cred->security;
struct smack_known *sskp = tsp->smk_task;
struct inode *inode = file->f_inode;
+ struct inode_smack *isp = inode->i_security;
char acc[SMK_NUM_ACCESS_TYPE + 1];
+ if (isp->smk_flags & SMK_INODE_IMPURE)
+ pr_info("Smack Unconfined Corruption: inode=(%s %ld) %s\n",
+ inode->i_sb->s_id, inode->i_ino, current->comm);
+
if (rc <= 0)
return rc;
+ if (rc > SMACK_UNCONFINED_OBJECT)
+ rc = 0;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
+ pr_info("Smack %s: (%s %s %s) file=(%s %ld %pD) %s\n", smk_bu_mess[rc],
sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
inode->i_sb->s_id, inode->i_ino, file,
current->comm);
@@ -207,8 +245,8 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
* @ip: a pointer to the inode
* @dp: a pointer to the dentry
*
- * Returns a pointer to the master list entry for the Smack label
- * or NULL if there was no label to fetch.
+ * Returns a pointer to the master list entry for the Smack label,
+ * NULL if there was no label to fetch, or an error code.
*/
static struct smack_known *smk_fetch(const char *name, struct inode *ip,
struct dentry *dp)
@@ -218,14 +256,18 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
struct smack_known *skp = NULL;
if (ip->i_op->getxattr == NULL)
- return NULL;
+ return ERR_PTR(-EOPNOTSUPP);
buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL);
if (buffer == NULL)
- return NULL;
+ return ERR_PTR(-ENOMEM);
rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL);
- if (rc > 0)
+ if (rc < 0)
+ skp = ERR_PTR(rc);
+ else if (rc == 0)
+ skp = NULL;
+ else
skp = smk_import_entry(buffer, rc);
kfree(buffer);
@@ -398,17 +440,11 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
*/
static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)
{
- int rc;
struct smack_known *skp;
- rc = cap_ptrace_access_check(ctp, mode);
- if (rc != 0)
- return rc;
-
skp = smk_of_task_struct(ctp);
- rc = smk_ptrace_rule_check(current, skp, mode, __func__);
- return rc;
+ return smk_ptrace_rule_check(current, skp, mode, __func__);
}
/**
@@ -424,10 +460,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
int rc;
struct smack_known *skp;
- rc = cap_ptrace_traceme(ptp);
- if (rc != 0)
- return rc;
-
skp = smk_of_task(current_security());
rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
@@ -555,7 +587,7 @@ static int smack_sb_copy_data(char *orig, char *smackopts)
static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
{
struct dentry *root = sb->s_root;
- struct inode *inode = root->d_inode;
+ struct inode *inode = d_backing_inode(root);
struct superblock_smack *sp = sb->s_security;
struct inode_smack *isp;
struct smack_known *skp;
@@ -577,40 +609,44 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
op += strlen(SMK_FSHAT);
skp = smk_import_entry(op, 0);
- if (skp != NULL) {
- sp->smk_hat = skp;
- specified = 1;
- }
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sp->smk_hat = skp;
+ specified = 1;
+
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
op += strlen(SMK_FSFLOOR);
skp = smk_import_entry(op, 0);
- if (skp != NULL) {
- sp->smk_floor = skp;
- specified = 1;
- }
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sp->smk_floor = skp;
+ specified = 1;
+
} else if (strncmp(op, SMK_FSDEFAULT,
strlen(SMK_FSDEFAULT)) == 0) {
op += strlen(SMK_FSDEFAULT);
skp = smk_import_entry(op, 0);
- if (skp != NULL) {
- sp->smk_default = skp;
- specified = 1;
- }
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sp->smk_default = skp;
+ specified = 1;
+
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
op += strlen(SMK_FSROOT);
skp = smk_import_entry(op, 0);
- if (skp != NULL) {
- sp->smk_root = skp;
- specified = 1;
- }
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sp->smk_root = skp;
+ specified = 1;
+
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
op += strlen(SMK_FSTRANS);
skp = smk_import_entry(op, 0);
- if (skp != NULL) {
- sp->smk_root = skp;
- transmute = 1;
- specified = 1;
- }
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+ sp->smk_root = skp;
+ transmute = 1;
+ specified = 1;
}
}
@@ -683,10 +719,6 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
struct inode_smack *isp;
int rc;
- rc = cap_bprm_set_creds(bprm);
- if (rc != 0)
- return rc;
-
if (bprm->cred_prepared)
return 0;
@@ -741,12 +773,11 @@ static void smack_bprm_committing_creds(struct linux_binprm *bprm)
static int smack_bprm_secureexec(struct linux_binprm *bprm)
{
struct task_smack *tsp = current_security();
- int ret = cap_bprm_secureexec(bprm);
- if (!ret && (tsp->smk_task != tsp->smk_forked))
- ret = 1;
+ if (tsp->smk_task != tsp->smk_forked)
+ return 1;
- return ret;
+ return 0;
}
/*
@@ -851,15 +882,15 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
- isp = smk_of_inode(old_dentry->d_inode);
+ isp = smk_of_inode(d_backing_inode(old_dentry));
rc = smk_curacc(isp, MAY_WRITE, &ad);
- rc = smk_bu_inode(old_dentry->d_inode, MAY_WRITE, rc);
+ rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_WRITE, rc);
if (rc == 0 && d_is_positive(new_dentry)) {
- isp = smk_of_inode(new_dentry->d_inode);
+ isp = smk_of_inode(d_backing_inode(new_dentry));
smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
rc = smk_curacc(isp, MAY_WRITE, &ad);
- rc = smk_bu_inode(new_dentry->d_inode, MAY_WRITE, rc);
+ rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_WRITE, rc);
}
return rc;
@@ -875,7 +906,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,
*/
static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)
{
- struct inode *ip = dentry->d_inode;
+ struct inode *ip = d_backing_inode(dentry);
struct smk_audit_info ad;
int rc;
@@ -918,8 +949,8 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)
/*
* You need write access to the thing you're removing
*/
- rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
- rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
if (rc == 0) {
/*
* You also need write access to the containing directory
@@ -957,15 +988,15 @@ static int smack_inode_rename(struct inode *old_inode,
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry);
- isp = smk_of_inode(old_dentry->d_inode);
+ isp = smk_of_inode(d_backing_inode(old_dentry));
rc = smk_curacc(isp, MAY_READWRITE, &ad);
- rc = smk_bu_inode(old_dentry->d_inode, MAY_READWRITE, rc);
+ rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_READWRITE, rc);
if (rc == 0 && d_is_positive(new_dentry)) {
- isp = smk_of_inode(new_dentry->d_inode);
+ isp = smk_of_inode(d_backing_inode(new_dentry));
smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry);
rc = smk_curacc(isp, MAY_READWRITE, &ad);
- rc = smk_bu_inode(new_dentry->d_inode, MAY_READWRITE, rc);
+ rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_READWRITE, rc);
}
return rc;
}
@@ -1022,8 +1053,8 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
- rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
return rc;
}
@@ -1034,19 +1065,16 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)
*
* Returns 0 if access is permitted, an error code otherwise
*/
-static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+static int smack_inode_getattr(const struct path *path)
{
struct smk_audit_info ad;
- struct path path;
+ struct inode *inode = d_backing_inode(path->dentry);
int rc;
- path.dentry = dentry;
- path.mnt = mnt;
-
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
- smk_ad_setfield_u_fs_path(&ad, path);
- rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
- rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+ smk_ad_setfield_u_fs_path(&ad, *path);
+ rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad);
+ rc = smk_bu_inode(inode, MAY_READ, rc);
return rc;
}
@@ -1098,7 +1126,9 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
if (rc == 0 && check_import) {
skp = size ? smk_import_entry(value, size) : NULL;
- if (skp == NULL || (check_star &&
+ if (IS_ERR(skp))
+ rc = PTR_ERR(skp);
+ else if (skp == NULL || (check_star &&
(skp == &smack_known_star || skp == &smack_known_web)))
rc = -EINVAL;
}
@@ -1107,8 +1137,8 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
if (rc == 0) {
- rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
- rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
}
return rc;
@@ -1129,7 +1159,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 = dentry->d_inode->i_security;
+ struct inode_smack *isp = d_backing_inode(dentry)->i_security;
if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
isp->smk_flags |= SMK_INODE_TRANSMUTE;
@@ -1138,19 +1168,19 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
skp = smk_import_entry(value, size);
- if (skp != NULL)
+ if (!IS_ERR(skp))
isp->smk_inode = skp;
else
isp->smk_inode = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) {
skp = smk_import_entry(value, size);
- if (skp != NULL)
+ if (!IS_ERR(skp))
isp->smk_task = skp;
else
isp->smk_task = &smack_known_invalid;
} else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
skp = smk_import_entry(value, size);
- if (skp != NULL)
+ if (!IS_ERR(skp))
isp->smk_mmap = skp;
else
isp->smk_mmap = &smack_known_invalid;
@@ -1174,8 +1204,8 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);
- rc = smk_bu_inode(dentry->d_inode, MAY_READ, rc);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_READ, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_READ, rc);
return rc;
}
@@ -1211,12 +1241,12 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
- rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad);
- rc = smk_bu_inode(dentry->d_inode, MAY_WRITE, rc);
+ rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad);
+ rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc);
if (rc != 0)
return rc;
- isp = dentry->d_inode->i_security;
+ isp = d_backing_inode(dentry)->i_security;
/*
* Don't do anything special for these.
* XATTR_NAME_SMACKIPIN
@@ -1638,6 +1668,9 @@ static int smack_file_receive(struct file *file)
struct smk_audit_info ad;
struct inode *inode = file_inode(file);
+ if (unlikely(IS_PRIVATE(inode)))
+ return 0;
+
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
smk_ad_setfield_u_fs_path(&ad, file->f_path);
/*
@@ -1899,12 +1932,7 @@ static void smack_task_getsecid(struct task_struct *p, u32 *secid)
*/
static int smack_task_setnice(struct task_struct *p, int nice)
{
- int rc;
-
- rc = cap_task_setnice(p, nice);
- if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
- return rc;
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -1916,12 +1944,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)
*/
static int smack_task_setioprio(struct task_struct *p, int ioprio)
{
- int rc;
-
- rc = cap_task_setioprio(p, ioprio);
- if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
- return rc;
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -1945,12 +1968,7 @@ static int smack_task_getioprio(struct task_struct *p)
*/
static int smack_task_setscheduler(struct task_struct *p)
{
- int rc;
-
- rc = cap_task_setscheduler(p);
- if (rc == 0)
- rc = smk_curacc_on_task(p, MAY_WRITE, __func__);
- return rc;
+ return smk_curacc_on_task(p, MAY_WRITE, __func__);
}
/**
@@ -2395,8 +2413,8 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
return -EINVAL;
skp = smk_import_entry(value, size);
- if (skp == NULL)
- return -EINVAL;
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
nsp->smk_inode = skp;
@@ -2452,7 +2470,21 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
static int smack_socket_post_create(struct socket *sock, int family,
int type, int protocol, int kern)
{
- if (family != PF_INET || sock->sk == NULL)
+ struct socket_smack *ssp;
+
+ if (sock->sk == NULL)
+ return 0;
+
+ /*
+ * Sockets created by kernel threads receive web label.
+ */
+ if (unlikely(current->flags & PF_KTHREAD)) {
+ ssp = sock->sk->sk_security;
+ ssp->smk_in = &smack_known_web;
+ ssp->smk_out = &smack_known_web;
+ }
+
+ if (family != PF_INET)
return 0;
/*
* Set the outbound netlbl.
@@ -3155,7 +3187,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
dp = dget(opt_dentry);
skp = smk_fetch(XATTR_NAME_SMACK, inode, dp);
- if (skp != NULL)
+ if (!IS_ERR_OR_NULL(skp))
final = skp;
/*
@@ -3192,11 +3224,14 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* Don't let the exec or mmap label be "*" or "@".
*/
skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
- if (skp == &smack_known_star || skp == &smack_known_web)
+ if (IS_ERR(skp) || skp == &smack_known_star ||
+ skp == &smack_known_web)
skp = NULL;
isp->smk_task = skp;
+
skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
- if (skp == &smack_known_star || skp == &smack_known_web)
+ if (IS_ERR(skp) || skp == &smack_known_star ||
+ skp == &smack_known_web)
skp = NULL;
isp->smk_mmap = skp;
@@ -3280,8 +3315,8 @@ static int smack_setprocattr(struct task_struct *p, char *name,
return -EINVAL;
skp = smk_import_entry(value, size);
- if (skp == NULL)
- return -EINVAL;
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
/*
* No process is ever allowed the web ("@") label.
@@ -3986,6 +4021,36 @@ static int smack_key_permission(key_ref_t key_ref,
rc = smk_bu_note("key access", tkp, keyp->security, request, rc);
return rc;
}
+
+/*
+ * smack_key_getsecurity - Smack label tagging the key
+ * @key points to the key to be queried
+ * @_buffer points to a pointer that should be set to point to the
+ * resulting string (if no label or an error occurs).
+ * Return the length of the string (including terminating NUL) or -ve if
+ * an error.
+ * May also return 0 (and a NULL buffer pointer) if there is no label.
+ */
+static int smack_key_getsecurity(struct key *key, char **_buffer)
+{
+ struct smack_known *skp = key->security;
+ size_t length;
+ char *copy;
+
+ if (key->security == NULL) {
+ *_buffer = NULL;
+ return 0;
+ }
+
+ copy = kstrdup(skp->smk_known, GFP_KERNEL);
+ if (copy == NULL)
+ return -ENOMEM;
+ length = strlen(copy) + 1;
+
+ *_buffer = copy;
+ return length;
+}
+
#endif /* CONFIG_KEYS */
/*
@@ -4026,8 +4091,10 @@ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
return -EINVAL;
skp = smk_import_entry(rulestr, 0);
- if (skp)
- *rule = skp->smk_known;
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+
+ *rule = skp->smk_known;
return 0;
}
@@ -4187,146 +4254,145 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
return 0;
}
-struct security_operations smack_ops = {
- .name = "smack",
-
- .ptrace_access_check = smack_ptrace_access_check,
- .ptrace_traceme = smack_ptrace_traceme,
- .syslog = smack_syslog,
-
- .sb_alloc_security = smack_sb_alloc_security,
- .sb_free_security = smack_sb_free_security,
- .sb_copy_data = smack_sb_copy_data,
- .sb_kern_mount = smack_sb_kern_mount,
- .sb_statfs = smack_sb_statfs,
-
- .bprm_set_creds = smack_bprm_set_creds,
- .bprm_committing_creds = smack_bprm_committing_creds,
- .bprm_secureexec = smack_bprm_secureexec,
-
- .inode_alloc_security = smack_inode_alloc_security,
- .inode_free_security = smack_inode_free_security,
- .inode_init_security = smack_inode_init_security,
- .inode_link = smack_inode_link,
- .inode_unlink = smack_inode_unlink,
- .inode_rmdir = smack_inode_rmdir,
- .inode_rename = smack_inode_rename,
- .inode_permission = smack_inode_permission,
- .inode_setattr = smack_inode_setattr,
- .inode_getattr = smack_inode_getattr,
- .inode_setxattr = smack_inode_setxattr,
- .inode_post_setxattr = smack_inode_post_setxattr,
- .inode_getxattr = smack_inode_getxattr,
- .inode_removexattr = smack_inode_removexattr,
- .inode_getsecurity = smack_inode_getsecurity,
- .inode_setsecurity = smack_inode_setsecurity,
- .inode_listsecurity = smack_inode_listsecurity,
- .inode_getsecid = smack_inode_getsecid,
-
- .file_permission = smack_file_permission,
- .file_alloc_security = smack_file_alloc_security,
- .file_free_security = smack_file_free_security,
- .file_ioctl = smack_file_ioctl,
- .file_lock = smack_file_lock,
- .file_fcntl = smack_file_fcntl,
- .mmap_file = smack_mmap_file,
- .mmap_addr = cap_mmap_addr,
- .file_set_fowner = smack_file_set_fowner,
- .file_send_sigiotask = smack_file_send_sigiotask,
- .file_receive = smack_file_receive,
-
- .file_open = smack_file_open,
-
- .cred_alloc_blank = smack_cred_alloc_blank,
- .cred_free = smack_cred_free,
- .cred_prepare = smack_cred_prepare,
- .cred_transfer = smack_cred_transfer,
- .kernel_act_as = smack_kernel_act_as,
- .kernel_create_files_as = smack_kernel_create_files_as,
- .task_setpgid = smack_task_setpgid,
- .task_getpgid = smack_task_getpgid,
- .task_getsid = smack_task_getsid,
- .task_getsecid = smack_task_getsecid,
- .task_setnice = smack_task_setnice,
- .task_setioprio = smack_task_setioprio,
- .task_getioprio = smack_task_getioprio,
- .task_setscheduler = smack_task_setscheduler,
- .task_getscheduler = smack_task_getscheduler,
- .task_movememory = smack_task_movememory,
- .task_kill = smack_task_kill,
- .task_wait = smack_task_wait,
- .task_to_inode = smack_task_to_inode,
-
- .ipc_permission = smack_ipc_permission,
- .ipc_getsecid = smack_ipc_getsecid,
-
- .msg_msg_alloc_security = smack_msg_msg_alloc_security,
- .msg_msg_free_security = smack_msg_msg_free_security,
-
- .msg_queue_alloc_security = smack_msg_queue_alloc_security,
- .msg_queue_free_security = smack_msg_queue_free_security,
- .msg_queue_associate = smack_msg_queue_associate,
- .msg_queue_msgctl = smack_msg_queue_msgctl,
- .msg_queue_msgsnd = smack_msg_queue_msgsnd,
- .msg_queue_msgrcv = smack_msg_queue_msgrcv,
-
- .shm_alloc_security = smack_shm_alloc_security,
- .shm_free_security = smack_shm_free_security,
- .shm_associate = smack_shm_associate,
- .shm_shmctl = smack_shm_shmctl,
- .shm_shmat = smack_shm_shmat,
-
- .sem_alloc_security = smack_sem_alloc_security,
- .sem_free_security = smack_sem_free_security,
- .sem_associate = smack_sem_associate,
- .sem_semctl = smack_sem_semctl,
- .sem_semop = smack_sem_semop,
-
- .d_instantiate = smack_d_instantiate,
-
- .getprocattr = smack_getprocattr,
- .setprocattr = smack_setprocattr,
-
- .unix_stream_connect = smack_unix_stream_connect,
- .unix_may_send = smack_unix_may_send,
-
- .socket_post_create = smack_socket_post_create,
+struct security_hook_list smack_hooks[] = {
+ LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
+ LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
+ LSM_HOOK_INIT(syslog, smack_syslog),
+
+ LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security),
+ LSM_HOOK_INIT(sb_free_security, smack_sb_free_security),
+ LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data),
+ LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount),
+ LSM_HOOK_INIT(sb_statfs, smack_sb_statfs),
+
+ LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds),
+ LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds),
+ LSM_HOOK_INIT(bprm_secureexec, smack_bprm_secureexec),
+
+ 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),
+ LSM_HOOK_INIT(inode_rmdir, smack_inode_rmdir),
+ LSM_HOOK_INIT(inode_rename, smack_inode_rename),
+ LSM_HOOK_INIT(inode_permission, smack_inode_permission),
+ LSM_HOOK_INIT(inode_setattr, smack_inode_setattr),
+ LSM_HOOK_INIT(inode_getattr, smack_inode_getattr),
+ LSM_HOOK_INIT(inode_setxattr, smack_inode_setxattr),
+ LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr),
+ LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr),
+ LSM_HOOK_INIT(inode_removexattr, smack_inode_removexattr),
+ LSM_HOOK_INIT(inode_getsecurity, smack_inode_getsecurity),
+ LSM_HOOK_INIT(inode_setsecurity, smack_inode_setsecurity),
+ LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity),
+ LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
+
+ LSM_HOOK_INIT(file_permission, smack_file_permission),
+ 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),
+ LSM_HOOK_INIT(mmap_file, smack_mmap_file),
+ LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),
+ LSM_HOOK_INIT(file_set_fowner, smack_file_set_fowner),
+ LSM_HOOK_INIT(file_send_sigiotask, smack_file_send_sigiotask),
+ LSM_HOOK_INIT(file_receive, smack_file_receive),
+
+ LSM_HOOK_INIT(file_open, smack_file_open),
+
+ LSM_HOOK_INIT(cred_alloc_blank, smack_cred_alloc_blank),
+ LSM_HOOK_INIT(cred_free, smack_cred_free),
+ LSM_HOOK_INIT(cred_prepare, smack_cred_prepare),
+ LSM_HOOK_INIT(cred_transfer, smack_cred_transfer),
+ LSM_HOOK_INIT(kernel_act_as, smack_kernel_act_as),
+ LSM_HOOK_INIT(kernel_create_files_as, smack_kernel_create_files_as),
+ LSM_HOOK_INIT(task_setpgid, smack_task_setpgid),
+ LSM_HOOK_INIT(task_getpgid, smack_task_getpgid),
+ LSM_HOOK_INIT(task_getsid, smack_task_getsid),
+ LSM_HOOK_INIT(task_getsecid, smack_task_getsecid),
+ LSM_HOOK_INIT(task_setnice, smack_task_setnice),
+ LSM_HOOK_INIT(task_setioprio, smack_task_setioprio),
+ LSM_HOOK_INIT(task_getioprio, smack_task_getioprio),
+ LSM_HOOK_INIT(task_setscheduler, smack_task_setscheduler),
+ LSM_HOOK_INIT(task_getscheduler, smack_task_getscheduler),
+ LSM_HOOK_INIT(task_movememory, smack_task_movememory),
+ LSM_HOOK_INIT(task_kill, smack_task_kill),
+ LSM_HOOK_INIT(task_wait, smack_task_wait),
+ LSM_HOOK_INIT(task_to_inode, smack_task_to_inode),
+
+ LSM_HOOK_INIT(ipc_permission, smack_ipc_permission),
+ 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_msg_queue_alloc_security),
+ LSM_HOOK_INIT(msg_queue_free_security, smack_msg_queue_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_shm_alloc_security),
+ LSM_HOOK_INIT(shm_free_security, smack_shm_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_sem_alloc_security),
+ LSM_HOOK_INIT(sem_free_security, smack_sem_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),
+
+ LSM_HOOK_INIT(d_instantiate, smack_d_instantiate),
+
+ LSM_HOOK_INIT(getprocattr, smack_getprocattr),
+ LSM_HOOK_INIT(setprocattr, smack_setprocattr),
+
+ LSM_HOOK_INIT(unix_stream_connect, smack_unix_stream_connect),
+ LSM_HOOK_INIT(unix_may_send, smack_unix_may_send),
+
+ LSM_HOOK_INIT(socket_post_create, smack_socket_post_create),
#ifndef CONFIG_SECURITY_SMACK_NETFILTER
- .socket_bind = smack_socket_bind,
+ LSM_HOOK_INIT(socket_bind, smack_socket_bind),
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
- .socket_connect = smack_socket_connect,
- .socket_sendmsg = smack_socket_sendmsg,
- .socket_sock_rcv_skb = smack_socket_sock_rcv_skb,
- .socket_getpeersec_stream = smack_socket_getpeersec_stream,
- .socket_getpeersec_dgram = smack_socket_getpeersec_dgram,
- .sk_alloc_security = smack_sk_alloc_security,
- .sk_free_security = smack_sk_free_security,
- .sock_graft = smack_sock_graft,
- .inet_conn_request = smack_inet_conn_request,
- .inet_csk_clone = smack_inet_csk_clone,
+ LSM_HOOK_INIT(socket_connect, smack_socket_connect),
+ LSM_HOOK_INIT(socket_sendmsg, smack_socket_sendmsg),
+ LSM_HOOK_INIT(socket_sock_rcv_skb, smack_socket_sock_rcv_skb),
+ LSM_HOOK_INIT(socket_getpeersec_stream, smack_socket_getpeersec_stream),
+ LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram),
+ LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security),
+ LSM_HOOK_INIT(sk_free_security, smack_sk_free_security),
+ LSM_HOOK_INIT(sock_graft, smack_sock_graft),
+ LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request),
+ LSM_HOOK_INIT(inet_csk_clone, smack_inet_csk_clone),
/* key management security hooks */
#ifdef CONFIG_KEYS
- .key_alloc = smack_key_alloc,
- .key_free = smack_key_free,
- .key_permission = smack_key_permission,
+ LSM_HOOK_INIT(key_alloc, smack_key_alloc),
+ LSM_HOOK_INIT(key_free, smack_key_free),
+ LSM_HOOK_INIT(key_permission, smack_key_permission),
+ LSM_HOOK_INIT(key_getsecurity, smack_key_getsecurity),
#endif /* CONFIG_KEYS */
/* Audit hooks */
#ifdef CONFIG_AUDIT
- .audit_rule_init = smack_audit_rule_init,
- .audit_rule_known = smack_audit_rule_known,
- .audit_rule_match = smack_audit_rule_match,
- .audit_rule_free = smack_audit_rule_free,
+ LSM_HOOK_INIT(audit_rule_init, smack_audit_rule_init),
+ LSM_HOOK_INIT(audit_rule_known, smack_audit_rule_known),
+ LSM_HOOK_INIT(audit_rule_match, smack_audit_rule_match),
+ LSM_HOOK_INIT(audit_rule_free, smack_audit_rule_free),
#endif /* CONFIG_AUDIT */
- .ismaclabel = smack_ismaclabel,
- .secid_to_secctx = smack_secid_to_secctx,
- .secctx_to_secid = smack_secctx_to_secid,
- .release_secctx = smack_release_secctx,
- .inode_notifysecctx = smack_inode_notifysecctx,
- .inode_setsecctx = smack_inode_setsecctx,
- .inode_getsecctx = smack_inode_getsecctx,
+ LSM_HOOK_INIT(ismaclabel, smack_ismaclabel),
+ LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx),
+ LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid),
+ LSM_HOOK_INIT(release_secctx, smack_release_secctx),
+ LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx),
+ LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx),
+ LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx),
};
@@ -4371,7 +4437,7 @@ static __init int smack_init(void)
struct cred *cred;
struct task_smack *tsp;
- if (!security_module_enable(&smack_ops))
+ if (!security_module_enable("smack"))
return 0;
smack_enabled = 1;
@@ -4401,8 +4467,7 @@ static __init int smack_init(void)
/*
* Register with LSM
*/
- if (register_security(&smack_ops))
- panic("smack: Unable to register with kernel.\n");
+ security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks));
return 0;
}
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index c952632afb0d..a455cfc9ec1f 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -23,9 +23,7 @@
static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops,
struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ const struct nf_hook_state *state)
{
struct socket_smack *ssp;
struct smack_known *skp;
@@ -42,9 +40,7 @@ static unsigned int smack_ipv6_output(const struct nf_hook_ops *ops,
static unsigned int smack_ipv4_output(const struct nf_hook_ops *ops,
struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ const struct nf_hook_state *state)
{
struct socket_smack *ssp;
struct smack_known *skp;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index bce4e8f1b267..5e0a64ebdf23 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -54,6 +54,9 @@ enum smk_inos {
SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
SMK_SYSLOG = 20, /* change syslog label) */
SMK_PTRACE = 21, /* set ptrace rule */
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+ SMK_UNCONFINED = 22, /* define an unconfined label */
+#endif
};
/*
@@ -61,7 +64,6 @@ enum smk_inos {
*/
static DEFINE_MUTEX(smack_cipso_lock);
static DEFINE_MUTEX(smack_ambient_lock);
-static DEFINE_MUTEX(smack_syslog_lock);
static DEFINE_MUTEX(smk_netlbladdr_lock);
/*
@@ -85,15 +87,15 @@ int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT;
*/
int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT;
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
/*
- * Unless a process is running with this label even
- * having CAP_MAC_OVERRIDE isn't enough to grant
- * privilege to violate MAC policy. If no label is
- * designated (the NULL case) capabilities apply to
- * everyone. It is expected that the hat (^) label
- * will be used if any label is used.
+ * Allow one label to be unconfined. This is for
+ * debugging and application bring-up purposes only.
+ * It is bad and wrong, but everyone seems to expect
+ * to have it.
*/
-struct smack_known *smack_onlycap;
+struct smack_known *smack_unconfined;
+#endif
/*
* If this value is set restrict syslog use to the label specified.
@@ -326,8 +328,7 @@ static int smk_perm_from_str(const char *string)
* @import: if non-zero, import labels
* @len: label length limit
*
- * Returns 0 on success, -EINVAL on failure and -ENOENT when either subject
- * or object is missing.
+ * Returns 0 on success, appropriate error code on failure.
*/
static int smk_fill_rule(const char *subject, const char *object,
const char *access1, const char *access2,
@@ -339,16 +340,16 @@ static int smk_fill_rule(const char *subject, const char *object,
if (import) {
rule->smk_subject = smk_import_entry(subject, len);
- if (rule->smk_subject == NULL)
- return -EINVAL;
+ if (IS_ERR(rule->smk_subject))
+ return PTR_ERR(rule->smk_subject);
rule->smk_object = smk_import_entry(object, len);
- if (rule->smk_object == NULL)
- return -EINVAL;
+ if (IS_ERR(rule->smk_object))
+ return PTR_ERR(rule->smk_object);
} else {
cp = smk_parse_smack(subject, len);
- if (cp == NULL)
- return -EINVAL;
+ if (IS_ERR(cp))
+ return PTR_ERR(cp);
skp = smk_find_entry(cp);
kfree(cp);
if (skp == NULL)
@@ -356,8 +357,8 @@ static int smk_fill_rule(const char *subject, const char *object,
rule->smk_subject = skp;
cp = smk_parse_smack(object, len);
- if (cp == NULL)
- return -EINVAL;
+ if (IS_ERR(cp))
+ return PTR_ERR(cp);
skp = smk_find_entry(cp);
kfree(cp);
if (skp == NULL)
@@ -400,7 +401,7 @@ static int smk_parse_rule(const char *data, struct smack_parsed_rule *rule,
* @import: if non-zero, import labels
* @tokens: numer of substrings expected in data
*
- * Returns number of processed bytes on success, -1 on failure.
+ * Returns number of processed bytes on success, -ERRNO on failure.
*/
static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
int import, int tokens)
@@ -419,7 +420,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
if (data[cnt] == '\0')
/* Unexpected end of data */
- return -1;
+ return -EINVAL;
tok[i] = data + cnt;
@@ -517,14 +518,14 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
while (cnt < count) {
if (format == SMK_FIXED24_FMT) {
rc = smk_parse_rule(data, &rule, 1);
- if (rc != 0) {
- rc = -EINVAL;
+ if (rc < 0)
goto out;
- }
cnt = count;
} else {
rc = smk_parse_long_rule(data + cnt, &rule, 1, tokens);
- if (rc <= 0) {
+ if (rc < 0)
+ goto out;
+ if (rc == 0) {
rc = -EINVAL;
goto out;
}
@@ -555,23 +556,17 @@ static void *smk_seq_start(struct seq_file *s, loff_t *pos,
struct list_head *head)
{
struct list_head *list;
+ int i = *pos;
+
+ rcu_read_lock();
+ for (list = rcu_dereference(list_next_rcu(head));
+ list != head;
+ list = rcu_dereference(list_next_rcu(list))) {
+ if (i-- == 0)
+ return list;
+ }
- /*
- * This is 0 the first time through.
- */
- if (s->index == 0)
- s->private = head;
-
- if (s->private == NULL)
- return NULL;
-
- list = s->private;
- if (list_empty(list))
- return NULL;
-
- if (s->index == 0)
- return list->next;
- return list;
+ return NULL;
}
static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos,
@@ -579,17 +574,15 @@ static void *smk_seq_next(struct seq_file *s, void *v, loff_t *pos,
{
struct list_head *list = v;
- if (list_is_last(list, head)) {
- s->private = NULL;
- return NULL;
- }
- s->private = list->next;
- return list->next;
+ ++*pos;
+ list = rcu_dereference(list_next_rcu(list));
+
+ return (list == head) ? NULL : list;
}
static void smk_seq_stop(struct seq_file *s, void *v)
{
- /* No-op */
+ rcu_read_unlock();
}
static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
@@ -649,7 +642,7 @@ static int load_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_master_list *smlp =
- list_entry(list, struct smack_master_list, list);
+ list_entry_rcu(list, struct smack_master_list, list);
smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN);
@@ -797,7 +790,7 @@ static int cipso_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_known *skp =
- list_entry(list, struct smack_known, list);
+ list_entry_rcu(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
char sep = '/';
int i;
@@ -903,8 +896,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
mutex_lock(&smack_cipso_lock);
skp = smk_import_entry(rule, 0);
- if (skp == NULL)
+ if (IS_ERR(skp)) {
+ rc = PTR_ERR(skp);
goto out;
+ }
if (format == SMK_FIXED24_FMT)
rule += SMK_LABELLEN;
@@ -986,7 +981,7 @@ static int cipso2_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_known *skp =
- list_entry(list, struct smack_known, list);
+ list_entry_rcu(list, struct smack_known, list);
struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
char sep = '/';
int i;
@@ -1070,7 +1065,7 @@ static int netlbladdr_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smk_netlbladdr *skp =
- list_entry(list, struct smk_netlbladdr, list);
+ list_entry_rcu(list, struct smk_netlbladdr, list);
unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr;
int maskn;
u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr);
@@ -1225,8 +1220,8 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf,
*/
if (smack[0] != '-') {
skp = smk_import_entry(smack, 0);
- if (skp == NULL) {
- rc = -EINVAL;
+ if (IS_ERR(skp)) {
+ rc = PTR_ERR(skp);
goto free_out;
}
} else {
@@ -1607,8 +1602,8 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
}
skp = smk_import_entry(data, count);
- if (skp == NULL) {
- rc = -EINVAL;
+ if (IS_ERR(skp)) {
+ rc = PTR_ERR(skp);
goto out;
}
@@ -1631,8 +1626,172 @@ static const struct file_operations smk_ambient_ops = {
.llseek = default_llseek,
};
+/*
+ * Seq_file operations for /smack/onlycap
+ */
+static void *onlycap_seq_start(struct seq_file *s, loff_t *pos)
+{
+ return smk_seq_start(s, pos, &smack_onlycap_list);
+}
+
+static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ return smk_seq_next(s, v, pos, &smack_onlycap_list);
+}
+
+static int onlycap_seq_show(struct seq_file *s, void *v)
+{
+ struct list_head *list = v;
+ struct smack_onlycap *sop =
+ list_entry_rcu(list, struct smack_onlycap, list);
+
+ seq_puts(s, sop->smk_label->smk_known);
+ seq_putc(s, ' ');
+
+ return 0;
+}
+
+static const struct seq_operations onlycap_seq_ops = {
+ .start = onlycap_seq_start,
+ .next = onlycap_seq_next,
+ .show = onlycap_seq_show,
+ .stop = smk_seq_stop,
+};
+
+static int smk_open_onlycap(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &onlycap_seq_ops);
+}
+
+/**
+ * smk_list_swap_rcu - swap public list with a private one in RCU-safe way
+ * The caller must hold appropriate mutex to prevent concurrent modifications
+ * to the public list.
+ * Private list is assumed to be not accessible to other threads yet.
+ *
+ * @public: public list
+ * @private: private list
+ */
+static void smk_list_swap_rcu(struct list_head *public,
+ struct list_head *private)
+{
+ struct list_head *first, *last;
+
+ if (list_empty(public)) {
+ list_splice_init_rcu(private, public, synchronize_rcu);
+ } else {
+ /* Remember public list before replacing it */
+ first = public->next;
+ last = public->prev;
+
+ /* Publish private list in place of public in RCU-safe way */
+ private->prev->next = public;
+ private->next->prev = public;
+ rcu_assign_pointer(public->next, private->next);
+ public->prev = private->prev;
+
+ synchronize_rcu();
+
+ /* When all readers are done with the old public list,
+ * attach it in place of private */
+ private->next = first;
+ private->prev = last;
+ first->prev = private;
+ last->next = private;
+ }
+}
+
+/**
+ * smk_write_onlycap - write() for smackfs/onlycap
+ * @file: file pointer, not actually used
+ * @buf: where to get the data from
+ * @count: bytes sent
+ * @ppos: where to start
+ *
+ * Returns number of bytes written or error code, as appropriate
+ */
+static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ char *data;
+ char *data_parse;
+ char *tok;
+ struct smack_known *skp;
+ struct smack_onlycap *sop;
+ struct smack_onlycap *sop2;
+ LIST_HEAD(list_tmp);
+ int rc = count;
+
+ if (!smack_privileged(CAP_MAC_ADMIN))
+ return -EPERM;
+
+ data = kzalloc(count + 1, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ if (copy_from_user(data, buf, count) != 0) {
+ kfree(data);
+ return -EFAULT;
+ }
+
+ data_parse = data;
+ while ((tok = strsep(&data_parse, " ")) != NULL) {
+ if (!*tok)
+ continue;
+
+ skp = smk_import_entry(tok, 0);
+ if (IS_ERR(skp)) {
+ rc = PTR_ERR(skp);
+ break;
+ }
+
+ sop = kzalloc(sizeof(*sop), GFP_KERNEL);
+ if (sop == NULL) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ sop->smk_label = skp;
+ list_add_rcu(&sop->list, &list_tmp);
+ }
+ kfree(data);
+
+ /*
+ * Clear the smack_onlycap on invalid label errors. This means
+ * that we can pass a null string to unset the onlycap value.
+ *
+ * Importing will also reject a label beginning with '-',
+ * so "-usecapabilities" will also work.
+ *
+ * But do so only on invalid label, not on system errors.
+ * The invalid label must be first to count as clearing attempt.
+ */
+ if (rc == -EINVAL && list_empty(&list_tmp))
+ rc = count;
+
+ if (rc >= 0) {
+ mutex_lock(&smack_onlycap_lock);
+ smk_list_swap_rcu(&smack_onlycap_list, &list_tmp);
+ mutex_unlock(&smack_onlycap_lock);
+ }
+
+ list_for_each_entry_safe(sop, sop2, &list_tmp, list)
+ kfree(sop);
+
+ return rc;
+}
+
+static const struct file_operations smk_onlycap_ops = {
+ .open = smk_open_onlycap,
+ .read = seq_read,
+ .write = smk_write_onlycap,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
/**
- * smk_read_onlycap - read() for smackfs/onlycap
+ * smk_read_unconfined - read() for smackfs/unconfined
* @filp: file pointer, not actually used
* @buf: where to put the result
* @cn: maximum to send along
@@ -1640,8 +1799,8 @@ static const struct file_operations smk_ambient_ops = {
*
* Returns number of bytes read or error code, as appropriate
*/
-static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
- size_t cn, loff_t *ppos)
+static ssize_t smk_read_unconfined(struct file *filp, char __user *buf,
+ size_t cn, loff_t *ppos)
{
char *smack = "";
ssize_t rc = -EINVAL;
@@ -1650,8 +1809,8 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
if (*ppos != 0)
return 0;
- if (smack_onlycap != NULL)
- smack = smack_onlycap->smk_known;
+ if (smack_unconfined != NULL)
+ smack = smack_unconfined->smk_known;
asize = strlen(smack) + 1;
@@ -1662,7 +1821,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
}
/**
- * smk_write_onlycap - write() for smackfs/onlycap
+ * smk_write_unconfined - write() for smackfs/unconfined
* @file: file pointer, not actually used
* @buf: where to get the data from
* @count: bytes sent
@@ -1670,52 +1829,55 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
*
* Returns number of bytes written or error code, as appropriate
*/
-static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
{
char *data;
- struct smack_known *skp = smk_of_task(current->cred->security);
+ struct smack_known *skp;
int rc = count;
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
- /*
- * This can be done using smk_access() but is done
- * explicitly for clarity. The smk_access() implementation
- * would use smk_access(smack_onlycap, MAY_WRITE)
- */
- if (smack_onlycap != NULL && smack_onlycap != skp)
- return -EPERM;
-
data = kzalloc(count + 1, GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
+ if (copy_from_user(data, buf, count) != 0) {
+ rc = -EFAULT;
+ goto freeout;
+ }
+
/*
- * Should the null string be passed in unset the onlycap value.
- * This seems like something to be careful with as usually
- * smk_import only expects to return NULL for errors. It
- * is usually the case that a nullstring or "\n" would be
- * bad to pass to smk_import but in fact this is useful here.
+ * Clear the smack_unconfined on invalid label errors. This means
+ * that we can pass a null string to unset the unconfined value.
*
- * smk_import will also reject a label beginning with '-',
- * so "-usecapabilities" will also work.
+ * Importing will also reject a label beginning with '-',
+ * so "-confine" will also work.
+ *
+ * But do so only on invalid label, not on system errors.
*/
- if (copy_from_user(data, buf, count) != 0)
- rc = -EFAULT;
- else
- smack_onlycap = smk_import_entry(data, count);
+ skp = smk_import_entry(data, count);
+ if (PTR_ERR(skp) == -EINVAL)
+ skp = NULL;
+ else if (IS_ERR(skp)) {
+ rc = PTR_ERR(skp);
+ goto freeout;
+ }
+
+ smack_unconfined = skp;
+freeout:
kfree(data);
return rc;
}
-static const struct file_operations smk_onlycap_ops = {
- .read = smk_read_onlycap,
- .write = smk_write_onlycap,
+static const struct file_operations smk_unconfined_ops = {
+ .read = smk_read_unconfined,
+ .write = smk_write_unconfined,
.llseek = default_llseek,
};
+#endif /* CONFIG_SECURITY_SMACK_BRINGUP */
/**
* smk_read_logging - read() for /smack/logging
@@ -1804,7 +1966,7 @@ static int load_self_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_rule *srp =
- list_entry(list, struct smack_rule, list);
+ list_entry_rcu(list, struct smack_rule, list);
smk_rule_show(s, srp, SMK_LABELLEN);
@@ -1889,7 +2051,7 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
res = smk_access(rule.smk_subject, rule.smk_object,
rule.smk_access1, NULL);
else if (res != -ENOENT)
- return -EINVAL;
+ return res;
/*
* smk_access() can return a value > 0 in the "bringup" case.
@@ -1933,7 +2095,7 @@ static int load2_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_master_list *smlp =
- list_entry(list, struct smack_master_list, list);
+ list_entry_rcu(list, struct smack_master_list, list);
smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL);
@@ -2010,7 +2172,7 @@ static int load_self2_seq_show(struct seq_file *s, void *v)
{
struct list_head *list = v;
struct smack_rule *srp =
- list_entry(list, struct smack_rule, list);
+ list_entry_rcu(list, struct smack_rule, list);
smk_rule_show(s, srp, SMK_LONGLABEL);
@@ -2091,8 +2253,8 @@ static const struct file_operations smk_access2_ops = {
static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- char *data = NULL;
- const char *cp = NULL;
+ char *data;
+ const char *cp;
struct smack_known *skp;
struct smack_rule *sp;
struct list_head *rule_list;
@@ -2114,18 +2276,18 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
if (copy_from_user(data, buf, count) != 0) {
rc = -EFAULT;
- goto free_out;
+ goto out_data;
}
cp = smk_parse_smack(data, count);
- if (cp == NULL) {
- rc = -EINVAL;
- goto free_out;
+ if (IS_ERR(cp)) {
+ rc = PTR_ERR(cp);
+ goto out_data;
}
skp = smk_find_entry(cp);
if (skp == NULL)
- goto free_out;
+ goto out_cp;
rule_list = &skp->smk_rules;
rule_lock = &skp->smk_rules_lock;
@@ -2137,9 +2299,11 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
mutex_unlock(rule_lock);
-free_out:
- kfree(data);
+out_cp:
kfree(cp);
+out_data:
+ kfree(data);
+
return rc;
}
@@ -2250,10 +2414,10 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
rc = -EFAULT;
else {
skp = smk_import_entry(data, count);
- if (skp == NULL)
- rc = -EINVAL;
+ if (IS_ERR(skp))
+ rc = PTR_ERR(skp);
else
- smack_syslog_label = smk_import_entry(data, count);
+ smack_syslog_label = skp;
}
kfree(data);
@@ -2384,6 +2548,10 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
"syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR},
[SMK_PTRACE] = {
"ptrace", &smk_ptrace_ops, S_IRUGO|S_IWUSR},
+#ifdef CONFIG_SECURITY_SMACK_BRINGUP
+ [SMK_UNCONFINED] = {
+ "unconfined", &smk_unconfined_ops, S_IRUGO|S_IWUSR},
+#endif
/* last one */
{""}
};
@@ -2395,7 +2563,7 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
return rc;
}
- root_inode = sb->s_root->d_inode;
+ root_inode = d_inode(sb->s_root);
return 0;
}
@@ -2452,7 +2620,7 @@ static int __init init_smk_fs(void)
int err;
int rc;
- if (!security_module_enable(&smack_ops))
+ if (!security_module_enable("smack"))
return 0;
err = smk_init_sysfs();
diff --git a/security/tomoyo/.gitignore b/security/tomoyo/.gitignore
index 5caf1a6f5907..dc0f220a210b 100644
--- a/security/tomoyo/.gitignore
+++ b/security/tomoyo/.gitignore
@@ -1,2 +1,2 @@
builtin-policy.h
-policy/
+policy/*.conf
diff --git a/security/tomoyo/Kconfig b/security/tomoyo/Kconfig
index 604e718d68d3..404dce66952a 100644
--- a/security/tomoyo/Kconfig
+++ b/security/tomoyo/Kconfig
@@ -6,6 +6,7 @@ config SECURITY_TOMOYO
select SECURITY_PATH
select SECURITY_NETWORK
select SRCU
+ select BUILD_BIN2C
default n
help
This selects TOMOYO Linux, pathname-based access control.
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile
index 56a0c7be409e..65dbcb2fd850 100644
--- a/security/tomoyo/Makefile
+++ b/security/tomoyo/Makefile
@@ -1,48 +1,15 @@
obj-y = audit.o common.o condition.o domain.o environ.o file.o gc.o group.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tomoyo.o util.o
-$(obj)/policy/profile.conf:
- @mkdir -p $(obj)/policy/
- @echo Creating an empty policy/profile.conf
- @touch $@
-
-$(obj)/policy/exception_policy.conf:
- @mkdir -p $(obj)/policy/
- @echo Creating a default policy/exception_policy.conf
- @echo initialize_domain /sbin/modprobe from any >> $@
- @echo initialize_domain /sbin/hotplug from any >> $@
-
-$(obj)/policy/domain_policy.conf:
- @mkdir -p $(obj)/policy/
- @echo Creating an empty policy/domain_policy.conf
- @touch $@
-
-$(obj)/policy/manager.conf:
- @mkdir -p $(obj)/policy/
- @echo Creating an empty policy/manager.conf
- @touch $@
-
-$(obj)/policy/stat.conf:
- @mkdir -p $(obj)/policy/
- @echo Creating an empty policy/stat.conf
- @touch $@
-
-$(obj)/builtin-policy.h: $(obj)/policy/profile.conf $(obj)/policy/exception_policy.conf $(obj)/policy/domain_policy.conf $(obj)/policy/manager.conf $(obj)/policy/stat.conf
- @echo Generating built-in policy for TOMOYO 2.5.x.
- @echo "static char tomoyo_builtin_profile[] __initdata =" > $@.tmp
- @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/profile.conf >> $@.tmp
- @echo "\"\";" >> $@.tmp
- @echo "static char tomoyo_builtin_exception_policy[] __initdata =" >> $@.tmp
- @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/exception_policy.conf >> $@.tmp
- @echo "\"\";" >> $@.tmp
- @echo "static char tomoyo_builtin_domain_policy[] __initdata =" >> $@.tmp
- @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/domain_policy.conf >> $@.tmp
- @echo "\"\";" >> $@.tmp
- @echo "static char tomoyo_builtin_manager[] __initdata =" >> $@.tmp
- @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/manager.conf >> $@.tmp
- @echo "\"\";" >> $@.tmp
- @echo "static char tomoyo_builtin_stat[] __initdata =" >> $@.tmp
- @sed -e 's/\\/\\\\/g' -e 's/\"/\\"/g' -e 's/\(.*\)/"\1\\n"/' < $(obj)/policy/stat.conf >> $@.tmp
- @echo "\"\";" >> $@.tmp
- @mv $@.tmp $@
+targets += builtin-policy.h
+define do_policy
+echo "static char tomoyo_builtin_$(1)[] __initdata ="; \
+$(objtree)/scripts/basic/bin2c <$(firstword $(wildcard $(obj)/policy/$(1).conf $(srctree)/$(src)/policy/$(1).conf.default) /dev/null); \
+echo ";"
+endef
+quiet_cmd_policy = POLICY $@
+ cmd_policy = ($(call do_policy,profile); $(call do_policy,exception_policy); $(call do_policy,domain_policy); $(call do_policy,manager); $(call do_policy,stat)) >$@
+
+$(obj)/builtin-policy.h: $(wildcard $(obj)/policy/*.conf $(src)/policy/*.conf.default) FORCE
+ $(call if_changed,policy)
$(obj)/common.o: $(obj)/builtin-policy.h
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index b897d4862016..f9c9fb1d56b4 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -945,7 +945,7 @@ char *tomoyo_encode2(const char *str, int str_len);
char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
va_list args);
char *tomoyo_read_token(struct tomoyo_acl_param *param);
-char *tomoyo_realpath_from_path(struct path *path);
+char *tomoyo_realpath_from_path(const struct path *path);
char *tomoyo_realpath_nofollow(const char *pathname);
const char *tomoyo_get_exe(void);
const char *tomoyo_yesno(const unsigned int value);
@@ -978,7 +978,7 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
struct path *path2);
int tomoyo_path_number_perm(const u8 operation, struct path *path,
unsigned long number);
-int tomoyo_path_perm(const u8 operation, struct path *path,
+int tomoyo_path_perm(const u8 operation, const struct path *path,
const char *target);
unsigned int tomoyo_poll_control(struct file *file, poll_table *wait);
unsigned int tomoyo_poll_log(struct file *file, poll_table *wait);
diff --git a/security/tomoyo/condition.c b/security/tomoyo/condition.c
index 63681e8be628..6c4528d4b48f 100644
--- a/security/tomoyo/condition.c
+++ b/security/tomoyo/condition.c
@@ -714,7 +714,7 @@ void tomoyo_get_attributes(struct tomoyo_obj_info *obj)
dentry = dget_parent(dentry);
break;
}
- inode = dentry->d_inode;
+ inode = d_backing_inode(dentry);
if (inode) {
struct tomoyo_mini_stat *stat = &obj->stat[i];
stat->uid = inode->i_uid;
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index c151a1869597..2367b100cc62 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -145,7 +145,7 @@ static void tomoyo_add_slash(struct tomoyo_path_info *buf)
*
* Returns true on success, false otherwise.
*/
-static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
+static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, const struct path *path)
{
buf->name = tomoyo_realpath_from_path(path);
if (buf->name) {
@@ -782,7 +782,7 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_path_perm(const u8 operation, struct path *path, const char *target)
+int tomoyo_path_perm(const u8 operation, const struct path *path, const char *target)
{
struct tomoyo_request_info r;
struct tomoyo_obj_info obj = {
diff --git a/security/tomoyo/policy/exception_policy.conf.default b/security/tomoyo/policy/exception_policy.conf.default
new file mode 100644
index 000000000000..2678df4964ee
--- /dev/null
+++ b/security/tomoyo/policy/exception_policy.conf.default
@@ -0,0 +1,2 @@
+initialize_domain /sbin/modprobe from any
+initialize_domain /sbin/hotplug from any
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index bed745c8b1a3..5077f1968841 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -89,7 +89,7 @@ char *tomoyo_encode(const char *str)
*
* If dentry is a directory, trailing '/' is appended.
*/
-static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
+static char *tomoyo_get_absolute_path(const struct path *path, char * const buffer,
const int buflen)
{
char *pos = ERR_PTR(-ENOMEM);
@@ -97,7 +97,7 @@ static char *tomoyo_get_absolute_path(struct path *path, char * const buffer,
/* go to whatever namespace root we are under */
pos = d_absolute_path(path, buffer, buflen - 1);
if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
- struct inode *inode = path->dentry->d_inode;
+ struct inode *inode = d_backing_inode(path->dentry);
if (inode && S_ISDIR(inode->i_mode)) {
buffer[buflen - 2] = '/';
buffer[buflen - 1] = '\0';
@@ -125,7 +125,7 @@ static char *tomoyo_get_dentry_path(struct dentry *dentry, char * const buffer,
if (buflen >= 256) {
pos = dentry_path_raw(dentry, buffer, buflen - 1);
if (!IS_ERR(pos) && *pos == '/' && pos[1]) {
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = d_backing_inode(dentry);
if (inode && S_ISDIR(inode->i_mode)) {
buffer[buflen - 2] = '/';
buffer[buflen - 1] = '\0';
@@ -168,7 +168,7 @@ static char *tomoyo_get_local_path(struct dentry *dentry, char * const buffer,
if (!MAJOR(sb->s_dev))
goto prepend_filesystem_name;
{
- struct inode *inode = sb->s_root->d_inode;
+ struct inode *inode = d_backing_inode(sb->s_root);
/*
* Use filesystem name if filesystem does not support rename()
* operation.
@@ -216,10 +216,10 @@ out:
*
* Returns the buffer.
*/
-static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
+static char *tomoyo_get_socket_name(const struct path *path, char * const buffer,
const int buflen)
{
- struct inode *inode = path->dentry->d_inode;
+ struct inode *inode = d_backing_inode(path->dentry);
struct socket *sock = inode ? SOCKET_I(inode) : NULL;
struct sock *sk = sock ? sock->sk : NULL;
if (sk) {
@@ -247,7 +247,7 @@ static char *tomoyo_get_socket_name(struct path *path, char * const buffer,
* These functions use kzalloc(), so the caller must call kfree()
* if these functions didn't return NULL.
*/
-char *tomoyo_realpath_from_path(struct path *path)
+char *tomoyo_realpath_from_path(const struct path *path)
{
char *buf = NULL;
char *name = NULL;
@@ -277,7 +277,7 @@ char *tomoyo_realpath_from_path(struct path *path)
pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
goto encode;
}
- inode = sb->s_root->d_inode;
+ inode = d_backing_inode(sb->s_root);
/*
* Get local name for filesystems without rename() operation
* or dentry without vfsmount.
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index f0b756e27fed..cbf3df422c87 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -4,7 +4,7 @@
* Copyright (C) 2005-2011 NTT DATA CORPORATION
*/
-#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include "common.h"
/**
@@ -72,12 +72,6 @@ static void tomoyo_cred_free(struct cred *cred)
*/
static int tomoyo_bprm_set_creds(struct linux_binprm *bprm)
{
- int rc;
-
- rc = cap_bprm_set_creds(bprm);
- if (rc)
- return rc;
-
/*
* Do only if this function is called for the first time of an execve
* operation.
@@ -144,10 +138,9 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
*
* Returns 0 on success, negative value otherwise.
*/
-static int tomoyo_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
+static int tomoyo_inode_getattr(const struct path *path)
{
- struct path path = { mnt, dentry };
- return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, &path, NULL);
+ return tomoyo_path_perm(TOMOYO_TYPE_GETATTR, path, NULL);
}
/**
@@ -503,36 +496,35 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
*/
-static struct security_operations tomoyo_security_ops = {
- .name = "tomoyo",
- .cred_alloc_blank = tomoyo_cred_alloc_blank,
- .cred_prepare = tomoyo_cred_prepare,
- .cred_transfer = tomoyo_cred_transfer,
- .cred_free = tomoyo_cred_free,
- .bprm_set_creds = tomoyo_bprm_set_creds,
- .bprm_check_security = tomoyo_bprm_check_security,
- .file_fcntl = tomoyo_file_fcntl,
- .file_open = tomoyo_file_open,
- .path_truncate = tomoyo_path_truncate,
- .path_unlink = tomoyo_path_unlink,
- .path_mkdir = tomoyo_path_mkdir,
- .path_rmdir = tomoyo_path_rmdir,
- .path_symlink = tomoyo_path_symlink,
- .path_mknod = tomoyo_path_mknod,
- .path_link = tomoyo_path_link,
- .path_rename = tomoyo_path_rename,
- .inode_getattr = tomoyo_inode_getattr,
- .file_ioctl = tomoyo_file_ioctl,
- .path_chmod = tomoyo_path_chmod,
- .path_chown = tomoyo_path_chown,
- .path_chroot = tomoyo_path_chroot,
- .sb_mount = tomoyo_sb_mount,
- .sb_umount = tomoyo_sb_umount,
- .sb_pivotroot = tomoyo_sb_pivotroot,
- .socket_bind = tomoyo_socket_bind,
- .socket_connect = tomoyo_socket_connect,
- .socket_listen = tomoyo_socket_listen,
- .socket_sendmsg = tomoyo_socket_sendmsg,
+static struct security_hook_list tomoyo_hooks[] = {
+ LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank),
+ LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare),
+ LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer),
+ LSM_HOOK_INIT(cred_free, tomoyo_cred_free),
+ LSM_HOOK_INIT(bprm_set_creds, tomoyo_bprm_set_creds),
+ LSM_HOOK_INIT(bprm_check_security, tomoyo_bprm_check_security),
+ LSM_HOOK_INIT(file_fcntl, tomoyo_file_fcntl),
+ LSM_HOOK_INIT(file_open, tomoyo_file_open),
+ LSM_HOOK_INIT(path_truncate, tomoyo_path_truncate),
+ LSM_HOOK_INIT(path_unlink, tomoyo_path_unlink),
+ LSM_HOOK_INIT(path_mkdir, tomoyo_path_mkdir),
+ LSM_HOOK_INIT(path_rmdir, tomoyo_path_rmdir),
+ LSM_HOOK_INIT(path_symlink, tomoyo_path_symlink),
+ LSM_HOOK_INIT(path_mknod, tomoyo_path_mknod),
+ LSM_HOOK_INIT(path_link, tomoyo_path_link),
+ LSM_HOOK_INIT(path_rename, tomoyo_path_rename),
+ LSM_HOOK_INIT(inode_getattr, tomoyo_inode_getattr),
+ LSM_HOOK_INIT(file_ioctl, tomoyo_file_ioctl),
+ LSM_HOOK_INIT(path_chmod, tomoyo_path_chmod),
+ LSM_HOOK_INIT(path_chown, tomoyo_path_chown),
+ LSM_HOOK_INIT(path_chroot, tomoyo_path_chroot),
+ LSM_HOOK_INIT(sb_mount, tomoyo_sb_mount),
+ LSM_HOOK_INIT(sb_umount, tomoyo_sb_umount),
+ LSM_HOOK_INIT(sb_pivotroot, tomoyo_sb_pivotroot),
+ LSM_HOOK_INIT(socket_bind, tomoyo_socket_bind),
+ LSM_HOOK_INIT(socket_connect, tomoyo_socket_connect),
+ LSM_HOOK_INIT(socket_listen, tomoyo_socket_listen),
+ LSM_HOOK_INIT(socket_sendmsg, tomoyo_socket_sendmsg),
};
/* Lock for GC. */
@@ -547,11 +539,10 @@ static int __init tomoyo_init(void)
{
struct cred *cred = (struct cred *) current_cred();
- if (!security_module_enable(&tomoyo_security_ops))
+ if (!security_module_enable("tomoyo"))
return 0;
/* register ourselves with the security framework */
- if (register_security(&tomoyo_security_ops))
- panic("Failure registering TOMOYO Linux");
+ security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks));
printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain;
tomoyo_mm_init();
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
index 2952ba576fb9..b974a6997d7f 100644
--- a/security/tomoyo/util.c
+++ b/security/tomoyo/util.c
@@ -948,15 +948,18 @@ bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
*/
const char *tomoyo_get_exe(void)
{
+ struct file *exe_file;
+ const char *cp;
struct mm_struct *mm = current->mm;
- const char *cp = NULL;
if (!mm)
return NULL;
- down_read(&mm->mmap_sem);
- if (mm->exe_file)
- cp = tomoyo_realpath_from_path(&mm->exe_file->f_path);
- up_read(&mm->mmap_sem);
+ exe_file = get_mm_exe_file(mm);
+ if (!exe_file)
+ return NULL;
+
+ cp = tomoyo_realpath_from_path(&exe_file->f_path);
+ fput(exe_file);
return cp;
}
diff --git a/security/yama/Kconfig b/security/yama/Kconfig
index 20ef5143c0c0..3123e1da2fed 100644
--- a/security/yama/Kconfig
+++ b/security/yama/Kconfig
@@ -1,8 +1,6 @@
config SECURITY_YAMA
bool "Yama support"
depends on SECURITY
- select SECURITYFS
- select SECURITY_PATH
default n
help
This selects Yama, which extends DAC support with additional
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 13c88fbcf037..9ed32502470e 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -12,7 +12,7 @@
*
*/
-#include <linux/security.h>
+#include <linux/lsm_hooks.h>
#include <linux/sysctl.h>
#include <linux/ptrace.h>
#include <linux/prctl.h>
@@ -154,13 +154,9 @@ void yama_task_free(struct task_struct *task)
int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
- int rc;
+ int rc = -ENOSYS;
struct task_struct *myself = current;
- rc = cap_task_prctl(option, arg2, arg3, arg4, arg5);
- if (rc != -ENOSYS)
- return rc;
-
switch (option) {
case PR_SET_PTRACER:
/* Since a thread can call prctl(), find the group leader
@@ -279,17 +275,10 @@ static int ptracer_exception_found(struct task_struct *tracer,
*
* Returns 0 if following the ptrace is allowed, -ve on error.
*/
-int yama_ptrace_access_check(struct task_struct *child,
+static int yama_ptrace_access_check(struct task_struct *child,
unsigned int mode)
{
- int rc;
-
- /* If standard caps disallows it, so does Yama. We should
- * only tighten restrictions further.
- */
- rc = cap_ptrace_access_check(child, mode);
- if (rc)
- return rc;
+ int rc = 0;
/* require ptrace target be a child of ptracer on attach */
if (mode == PTRACE_MODE_ATTACH) {
@@ -335,14 +324,7 @@ int yama_ptrace_access_check(struct task_struct *child,
*/
int yama_ptrace_traceme(struct task_struct *parent)
{
- int rc;
-
- /* If standard caps disallows it, so does Yama. We should
- * only tighten restrictions further.
- */
- rc = cap_ptrace_traceme(parent);
- if (rc)
- return rc;
+ int rc = 0;
/* Only disallow PTRACE_TRACEME on more aggressive settings. */
switch (ptrace_scope) {
@@ -364,35 +346,33 @@ int yama_ptrace_traceme(struct task_struct *parent)
return rc;
}
-#ifndef CONFIG_SECURITY_YAMA_STACKED
-static struct security_operations yama_ops = {
- .name = "yama",
-
- .ptrace_access_check = yama_ptrace_access_check,
- .ptrace_traceme = yama_ptrace_traceme,
- .task_prctl = yama_task_prctl,
- .task_free = yama_task_free,
+static struct security_hook_list yama_hooks[] = {
+ LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
+ LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
+ LSM_HOOK_INIT(task_prctl, yama_task_prctl),
+ LSM_HOOK_INIT(task_free, yama_task_free),
};
-#endif
+
+void __init yama_add_hooks(void)
+{
+ security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks));
+}
#ifdef CONFIG_SYSCTL
static int yama_dointvec_minmax(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
- int rc;
+ struct ctl_table table_copy;
if (write && !capable(CAP_SYS_PTRACE))
return -EPERM;
- rc = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
- if (rc)
- return rc;
-
/* Lock the max value if it ever gets set. */
- if (write && *(int *)table->data == *(int *)table->extra2)
- table->extra1 = table->extra2;
+ table_copy = *table;
+ if (*(int *)table_copy.data == *(int *)table_copy.extra2)
+ table_copy.extra1 = table_copy.extra2;
- return rc;
+ return proc_dointvec_minmax(&table_copy, write, buffer, lenp, ppos);
}
static int zero;
@@ -421,16 +401,13 @@ static struct ctl_table yama_sysctl_table[] = {
static __init int yama_init(void)
{
#ifndef CONFIG_SECURITY_YAMA_STACKED
- if (!security_module_enable(&yama_ops))
+ /*
+ * If yama is being stacked this is already taken care of.
+ */
+ if (!security_module_enable("yama"))
return 0;
#endif
-
- printk(KERN_INFO "Yama: becoming mindful.\n");
-
-#ifndef CONFIG_SECURITY_YAMA_STACKED
- if (register_security(&yama_ops))
- panic("Yama: kernel registration failed.\n");
-#endif
+ pr_info("Yama: becoming mindful.\n");
#ifdef CONFIG_SYSCTL
if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table))