diff options
Diffstat (limited to 'security/selinux/hooks.c')
| -rw-r--r-- | security/selinux/hooks.c | 92 | 
1 files changed, 81 insertions, 11 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index db1fca990a24..c956390a9136 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -81,6 +81,7 @@  #include <linux/syslog.h>  #include <linux/user_namespace.h>  #include <linux/export.h> +#include <linux/security.h>  #include <linux/msg.h>  #include <linux/shm.h> @@ -284,13 +285,14 @@ static void superblock_free_security(struct super_block *sb)  /* The file system's label must be initialized prior to use. */ -static const char *labeling_behaviors[6] = { +static const char *labeling_behaviors[7] = {  	"uses xattr",  	"uses transition SIDs",  	"uses task SIDs",  	"uses genfs_contexts",  	"not configured for labeling",  	"uses mountpoint labeling", +	"uses native labeling",  };  static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry); @@ -552,7 +554,9 @@ static int bad_option(struct superblock_security_struct *sbsec, char flag,   * labeling information.   */  static int selinux_set_mnt_opts(struct super_block *sb, -				struct security_mnt_opts *opts) +				struct security_mnt_opts *opts, +				unsigned long kern_flags, +				unsigned long *set_kern_flags)  {  	const struct cred *cred = current_cred();  	int rc = 0, i; @@ -580,6 +584,12 @@ static int selinux_set_mnt_opts(struct super_block *sb,  			"before the security server is initialized\n");  		goto out;  	} +	if (kern_flags && !set_kern_flags) { +		/* Specifying internal flags without providing a place to +		 * place the results is not allowed */ +		rc = -EINVAL; +		goto out; +	}  	/*  	 * Binary mount data FS will come through this function twice.  Once @@ -670,14 +680,21 @@ static int selinux_set_mnt_opts(struct super_block *sb,  	if (strcmp(sb->s_type->name, "proc") == 0)  		sbsec->flags |= SE_SBPROC; -	/* Determine the labeling behavior to use for this filesystem type. */ -	rc = security_fs_use((sbsec->flags & SE_SBPROC) ? "proc" : sb->s_type->name, &sbsec->behavior, &sbsec->sid); -	if (rc) { -		printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", -		       __func__, sb->s_type->name, rc); -		goto out; +	if (!sbsec->behavior) { +		/* +		 * Determine the labeling behavior to use for this +		 * filesystem type. +		 */ +		rc = security_fs_use((sbsec->flags & SE_SBPROC) ? +					"proc" : sb->s_type->name, +					&sbsec->behavior, &sbsec->sid); +		if (rc) { +			printk(KERN_WARNING +				"%s: security_fs_use(%s) returned %d\n", +					__func__, sb->s_type->name, rc); +			goto out; +		}  	} -  	/* sets the context of the superblock for the fs being mounted. */  	if (fscontext_sid) {  		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); @@ -692,6 +709,11 @@ static int selinux_set_mnt_opts(struct super_block *sb,  	 * sets the label used on all file below the mountpoint, and will set  	 * the superblock context if not already set.  	 */ +	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) { +		sbsec->behavior = SECURITY_FS_USE_NATIVE; +		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; +	} +  	if (context_sid) {  		if (!fscontext_sid) {  			rc = may_context_mount_sb_relabel(context_sid, sbsec, @@ -723,7 +745,8 @@ static int selinux_set_mnt_opts(struct super_block *sb,  	}  	if (defcontext_sid) { -		if (sbsec->behavior != SECURITY_FS_USE_XATTR) { +		if (sbsec->behavior != SECURITY_FS_USE_XATTR && +			sbsec->behavior != SECURITY_FS_USE_NATIVE) {  			rc = -EINVAL;  			printk(KERN_WARNING "SELinux: defcontext option is "  			       "invalid for this filesystem type\n"); @@ -980,7 +1003,7 @@ static int superblock_doinit(struct super_block *sb, void *data)  		goto out_err;  out: -	rc = selinux_set_mnt_opts(sb, &opts); +	rc = selinux_set_mnt_opts(sb, &opts, 0, NULL);  out_err:  	security_free_mnt_opts(&opts); @@ -1222,6 +1245,8 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent  	}  	switch (sbsec->behavior) { +	case SECURITY_FS_USE_NATIVE: +		break;  	case SECURITY_FS_USE_XATTR:  		if (!inode->i_op->getxattr) {  			isec->sid = sbsec->def_sid; @@ -2527,6 +2552,40 @@ static void selinux_inode_free_security(struct inode *inode)  	inode_free_security(inode);  } +static int selinux_dentry_init_security(struct dentry *dentry, int mode, +					struct qstr *name, void **ctx, +					u32 *ctxlen) +{ +	const struct cred *cred = current_cred(); +	struct task_security_struct *tsec; +	struct inode_security_struct *dsec; +	struct superblock_security_struct *sbsec; +	struct inode *dir = dentry->d_parent->d_inode; +	u32 newsid; +	int rc; + +	tsec = cred->security; +	dsec = dir->i_security; +	sbsec = dir->i_sb->s_security; + +	if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { +		newsid = tsec->create_sid; +	} else { +		rc = security_transition_sid(tsec->sid, dsec->sid, +					     inode_mode_to_security_class(mode), +					     name, +					     &newsid); +		if (rc) { +			printk(KERN_WARNING +				"%s: security_transition_sid failed, rc=%d\n", +			       __func__, -rc); +			return rc; +		} +	} + +	return security_sid_to_context(newsid, (char **)ctx, ctxlen); +} +  static int selinux_inode_init_security(struct inode *inode, struct inode *dir,  				       const struct qstr *qstr, char **name,  				       void **value, size_t *len) @@ -2861,7 +2920,10 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,  		return;  	} +	isec->sclass = inode_mode_to_security_class(inode->i_mode);  	isec->sid = newsid; +	isec->initialized = 1; +  	return;  } @@ -2949,6 +3011,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,  	if (rc)  		return rc; +	isec->sclass = inode_mode_to_security_class(inode->i_mode);  	isec->sid = newsid;  	isec->initialized = 1;  	return 0; @@ -5432,6 +5495,11 @@ abort_change:  	return error;  } +static int selinux_ismaclabel(const char *name) +{ +	return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0); +} +  static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)  {  	return security_sid_to_context(secid, secdata, seclen); @@ -5574,6 +5642,7 @@ static struct security_operations selinux_ops = {  	.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, @@ -5669,6 +5738,7 @@ static struct security_operations selinux_ops = {  	.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,  | 
