summaryrefslogtreecommitdiff
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c125
1 files changed, 90 insertions, 35 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 13185a6c266a..085057936287 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -507,14 +507,14 @@ static int sb_finish_set_opts(struct super_block *sb)
the root directory. -ENODATA is ok, as this may be
the first boot of the SELinux kernel before we have
assigned xattr values to the filesystem. */
- if (!root_inode->i_op->getxattr) {
+ if (!(root_inode->i_opflags & IOP_XATTR)) {
printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
"xattr support\n", sb->s_id, sb->s_type->name);
rc = -EOPNOTSUPP;
goto out;
}
- rc = root_inode->i_op->getxattr(root, root_inode,
- XATTR_NAME_SELINUX, NULL, 0);
+
+ rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
if (rc < 0 && rc != -ENODATA) {
if (rc == -EOPNOTSUPP)
printk(KERN_WARNING "SELinux: (dev %s, type "
@@ -1410,11 +1410,10 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
case SECURITY_FS_USE_NATIVE:
break;
case SECURITY_FS_USE_XATTR:
- if (!inode->i_op->getxattr) {
+ if (!(inode->i_opflags & IOP_XATTR)) {
isec->sid = sbsec->def_sid;
break;
}
-
/* Need a dentry, since the xattr API requires one.
Life would be simpler if we could just pass the inode. */
if (opt_dentry) {
@@ -1445,14 +1444,12 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out_unlock;
}
context[len] = '\0';
- rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX,
- context, len);
+ rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
if (rc == -ERANGE) {
kfree(context);
/* Need a larger buffer. Query for the right size. */
- rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX,
- NULL, 0);
+ rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
if (rc < 0) {
dput(dentry);
goto out_unlock;
@@ -1465,9 +1462,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out_unlock;
}
context[len] = '\0';
- rc = inode->i_op->getxattr(dentry, inode,
- XATTR_NAME_SELINUX,
- context, len);
+ rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
}
dput(dentry);
if (rc < 0) {
@@ -1761,8 +1756,8 @@ static inline int file_path_has_perm(const struct cred *cred,
{
struct common_audit_data ad;
- ad.type = LSM_AUDIT_DATA_PATH;
- ad.u.path = file->f_path;
+ ad.type = LSM_AUDIT_DATA_FILE;
+ ad.u.file = file;
return inode_has_perm(cred, file_inode(file), av, &ad);
}
@@ -1784,8 +1779,8 @@ static int file_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred);
int rc;
- ad.type = LSM_AUDIT_DATA_PATH;
- ad.u.path = file->f_path;
+ ad.type = LSM_AUDIT_DATA_FILE;
+ ad.u.file = file;
if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid,
@@ -1808,13 +1803,13 @@ out:
/*
* Determine the label for an inode that might be unioned.
*/
-static int selinux_determine_inode_label(struct inode *dir,
- const struct qstr *name,
- u16 tclass,
- u32 *_new_isid)
+static int
+selinux_determine_inode_label(const struct task_security_struct *tsec,
+ struct inode *dir,
+ const struct qstr *name, u16 tclass,
+ u32 *_new_isid)
{
const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
- const struct task_security_struct *tsec = current_security();
if ((sbsec->flags & SE_SBINITIALIZED) &&
(sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
@@ -1857,8 +1852,8 @@ static int may_create(struct inode *dir,
if (rc)
return rc;
- rc = selinux_determine_inode_label(dir, &dentry->d_name, tclass,
- &newsid);
+ rc = selinux_determine_inode_label(current_security(), dir,
+ &dentry->d_name, tclass, &newsid);
if (rc)
return rc;
@@ -2365,8 +2360,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
new_tsec->sid = old_tsec->sid;
}
- ad.type = LSM_AUDIT_DATA_PATH;
- ad.u.path = bprm->file->f_path;
+ ad.type = LSM_AUDIT_DATA_FILE;
+ ad.u.file = bprm->file;
if (new_tsec->sid == old_tsec->sid) {
rc = avc_has_perm(old_tsec->sid, isec->sid,
@@ -2838,7 +2833,8 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
u32 newsid;
int rc;
- rc = selinux_determine_inode_label(d_inode(dentry->d_parent), name,
+ rc = selinux_determine_inode_label(current_security(),
+ d_inode(dentry->d_parent), name,
inode_mode_to_security_class(mode),
&newsid);
if (rc)
@@ -2847,6 +2843,27 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
return security_sid_to_context(newsid, (char **)ctx, ctxlen);
}
+static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
+ struct qstr *name,
+ const struct cred *old,
+ struct cred *new)
+{
+ u32 newsid;
+ int rc;
+ struct task_security_struct *tsec;
+
+ rc = selinux_determine_inode_label(old->security,
+ d_inode(dentry->d_parent), name,
+ inode_mode_to_security_class(mode),
+ &newsid);
+ if (rc)
+ return rc;
+
+ tsec = new->security;
+ tsec->create_sid = newsid;
+ return 0;
+}
+
static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
const char **name,
@@ -2863,7 +2880,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
sid = tsec->sid;
newsid = tsec->create_sid;
- rc = selinux_determine_inode_label(
+ rc = selinux_determine_inode_label(current_security(),
dir, qstr,
inode_mode_to_security_class(inode->i_mode),
&newsid);
@@ -3293,6 +3310,41 @@ static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
*secid = isec->sid;
}
+static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
+{
+ u32 sid;
+ struct task_security_struct *tsec;
+ struct cred *new_creds = *new;
+
+ if (new_creds == NULL) {
+ new_creds = prepare_creds();
+ if (!new_creds)
+ return -ENOMEM;
+ }
+
+ tsec = new_creds->security;
+ /* Get label from overlay inode and set it in create_sid */
+ selinux_inode_getsecid(d_inode(src), &sid);
+ tsec->create_sid = sid;
+ *new = new_creds;
+ return 0;
+}
+
+static int selinux_inode_copy_up_xattr(const char *name)
+{
+ /* The copy_up hook above sets the initial context on an inode, but we
+ * don't then want to overwrite it by blindly copying all the lower
+ * xattrs up. Instead, we have to filter out SELinux-related xattrs.
+ */
+ if (strcmp(name, XATTR_NAME_SELINUX) == 0)
+ return 1; /* Discard */
+ /*
+ * Any other attribute apart from SELINUX is not claimed, supported
+ * by selinux.
+ */
+ return -EOPNOTSUPP;
+}
+
/* file security operations */
static int selinux_revalidate_file_permission(struct file *file, int mask)
@@ -3776,8 +3828,8 @@ static int selinux_kernel_module_from_file(struct file *file)
/* finit_module */
- ad.type = LSM_AUDIT_DATA_PATH;
- ad.u.path = file->f_path;
+ ad.type = LSM_AUDIT_DATA_FILE;
+ ad.u.file = file;
fsec = file->f_security;
if (sid != fsec->sid) {
@@ -3984,7 +4036,7 @@ out:
return ret;
}
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
/* Returns error only if unable to parse addresses */
static int selinux_parse_skb_ipv6(struct sk_buff *skb,
@@ -4075,7 +4127,7 @@ static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
&ad->u.net->v4info.daddr);
goto okay;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
case PF_INET6:
ret = selinux_parse_skb_ipv6(skb, ad, proto);
if (ret)
@@ -5029,7 +5081,7 @@ static unsigned int selinux_ipv4_forward(void *priv,
return selinux_ip_forward(skb, state->in, PF_INET);
}
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
static unsigned int selinux_ipv6_forward(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -5087,7 +5139,7 @@ static unsigned int selinux_ipv4_output(void *priv,
return selinux_ip_output(skb, PF_INET);
}
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
static unsigned int selinux_ipv6_output(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -5273,7 +5325,7 @@ static unsigned int selinux_ipv4_postroute(void *priv,
return selinux_ip_postroute(skb, state->out, PF_INET);
}
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
static unsigned int selinux_ipv6_postroute(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -6062,6 +6114,7 @@ static struct security_hook_list selinux_hooks[] = {
LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str),
LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
+ LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as),
LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
@@ -6088,6 +6141,8 @@ static struct security_hook_list selinux_hooks[] = {
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(inode_copy_up, selinux_inode_copy_up),
+ LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
LSM_HOOK_INIT(file_permission, selinux_file_permission),
LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
@@ -6317,7 +6372,7 @@ static struct nf_hook_ops selinux_nf_ops[] = {
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_SELINUX_FIRST,
},
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#if IS_ENABLED(CONFIG_IPV6)
{
.hook = selinux_ipv6_postroute,
.pf = NFPROTO_IPV6,