[v4,07/11] smack: abstraction layer for 2 common Smack operations
diff mbox

Message ID 1444826525-9758-8-git-send-email-l.pawelczyk@samsung.com
State New
Headers show

Commit Message

Lukasz Pawelczyk Oct. 14, 2015, 12:42 p.m. UTC
This patch adds two new functions that provide an abstraction layer for
two common internal Smack operations:

smk_find_label_name() - returns a label name (char*) from a struct
                        smack_known pointer
smk_get_label()       - either finds or imports a label from a raw label
                        name (char*) and returns struct smack_known
                        pointer

This patch also simplifies some pieces of code due to addition of those
2 functions (e.g. smack_inode_post_setxattr, smk_fill_rule,
smk_write_revoke_subj).

It is meant as a preparation for namespaces patches. Those 2 functions
will serve as entry points for namespace operations.

This patch should not change the Smack behaviour in any way.

Signed-off-by: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>
---
 security/smack/smack.h        |   2 +
 security/smack/smack_access.c |  41 ++++++++++++
 security/smack/smack_lsm.c    |  78 +++++++++++-----------
 security/smack/smackfs.c      | 147 +++++++++++++++++++++++-------------------
 4 files changed, 166 insertions(+), 102 deletions(-)

Comments

Casey Schaufler Oct. 29, 2015, 10:51 p.m. UTC | #1
On 10/14/2015 5:42 AM, Lukasz Pawelczyk wrote:
> This patch adds two new functions that provide an abstraction layer for
> two common internal Smack operations:
>
> smk_find_label_name() - returns a label name (char*) from a struct
>                         smack_known pointer
> smk_get_label()       - either finds or imports a label from a raw label
>                         name (char*) and returns struct smack_known
>                         pointer
>
> This patch also simplifies some pieces of code due to addition of those
> 2 functions (e.g. smack_inode_post_setxattr, smk_fill_rule,
> smk_write_revoke_subj).
>
> It is meant as a preparation for namespaces patches. Those 2 functions
> will serve as entry points for namespace operations.
>
> This patch should not change the Smack behaviour in any way.
>
> Signed-off-by: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
> Reviewed-by: Casey Schaufler <casey@schaufler-ca.com>

Acked-by: Casey Schaufler <casey@schaufler-ca.com>


> ---
>  security/smack/smack.h        |   2 +
>  security/smack/smack_access.c |  41 ++++++++++++
>  security/smack/smack_lsm.c    |  78 +++++++++++-----------
>  security/smack/smackfs.c      | 147 +++++++++++++++++++++++-------------------
>  4 files changed, 166 insertions(+), 102 deletions(-)
>
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index ca8fb7c..091efc2 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -306,6 +306,8 @@ int smack_has_ns_privilege(struct task_struct *task,
>  int smack_has_privilege(struct task_struct *task, int cap);
>  int smack_ns_privileged(struct user_namespace *user_ns, int cap);
>  int smack_privileged(int cap);
> +char *smk_find_label_name(struct smack_known *skp);
> +struct smack_known *smk_get_label(const char *string, int len, bool import);
>  
>  /*
>   * Shared data.
> diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
> index 72f848e..131c742 100644
> --- a/security/smack/smack_access.c
> +++ b/security/smack/smack_access.c
> @@ -716,3 +716,44 @@ int smack_privileged(int cap)
>  {
>  	return smack_ns_privileged(&init_user_ns, cap);
>  }
> +
> +/**
> + * smk_find_label_name - A helper to get a string value of a label
> + * @skp: a label we want a string value from
> + *
> + * Returns a pointer to a label name or NULL if label name not found.
> + */
> +char *smk_find_label_name(struct smack_known *skp)
> +{
> +	return skp->smk_known;
> +}
> +
> +/**
> + * smk_get_label - A helper to get the smack_known value from a string using
> + *                 either import or find functions if it already exists
> + * @string: a name of a label we look for or want to import
> + * @len: the string size, or zero if it is NULL terminated
> + * @import: whether we should import the label if not found
> + *
> + * Returns a smack_known label that is either imported or found.
> + * NULL if label not found (only when import == false).
> + * Error code otherwise.
> + */
> +struct smack_known *smk_get_label(const char *string, int len, bool import)
> +{
> +	struct smack_known *skp;
> +	char *cp;
> +
> +	if (import) {
> +		skp = smk_import_entry(string, len);
> +	} else {
> +		cp = smk_parse_smack(string, len);
> +		if (IS_ERR(cp))
> +			return ERR_CAST(cp);
> +
> +		skp = smk_find_entry(cp);
> +		kfree(cp);
> +	}
> +
> +	return skp;
> +}
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 198d3d6..7303c37 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -746,31 +746,31 @@ static int smack_set_mnt_opts(struct super_block *sb,
>  	for (i = 0; i < num_opts; i++) {
>  		switch (opts->mnt_opts_flags[i]) {
>  		case FSDEFAULT_MNT:
> -			skp = smk_import_entry(opts->mnt_opts[i], 0);
> +			skp = smk_get_label(opts->mnt_opts[i], 0, true);
>  			if (IS_ERR(skp))
>  				return PTR_ERR(skp);
>  			sp->smk_default = skp;
>  			break;
>  		case FSFLOOR_MNT:
> -			skp = smk_import_entry(opts->mnt_opts[i], 0);
> +			skp = smk_get_label(opts->mnt_opts[i], 0, true);
>  			if (IS_ERR(skp))
>  				return PTR_ERR(skp);
>  			sp->smk_floor = skp;
>  			break;
>  		case FSHAT_MNT:
> -			skp = smk_import_entry(opts->mnt_opts[i], 0);
> +			skp = smk_get_label(opts->mnt_opts[i], 0, true);
>  			if (IS_ERR(skp))
>  				return PTR_ERR(skp);
>  			sp->smk_hat = skp;
>  			break;
>  		case FSROOT_MNT:
> -			skp = smk_import_entry(opts->mnt_opts[i], 0);
> +			skp = smk_get_label(opts->mnt_opts[i], 0, true);
>  			if (IS_ERR(skp))
>  				return PTR_ERR(skp);
>  			sp->smk_root = skp;
>  			break;
>  		case FSTRANS_MNT:
> -			skp = smk_import_entry(opts->mnt_opts[i], 0);
> +			skp = smk_get_label(opts->mnt_opts[i], 0, true);
>  			if (IS_ERR(skp))
>  				return PTR_ERR(skp);
>  			sp->smk_root = skp;
> @@ -1288,7 +1288,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
>  		rc = -EPERM;
>  
>  	if (rc == 0 && check_import) {
> -		skp = size ? smk_import_entry(value, size) : NULL;
> +		skp = size ? smk_get_label(value, size, true) : NULL;
>  		if (IS_ERR(skp))
>  			rc = PTR_ERR(skp);
>  		else if (skp == NULL || (check_star &&
> @@ -1322,6 +1322,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 smack_known **skpp = NULL;
>  	struct inode_smack *isp = d_backing_inode(dentry)->i_security;
>  
>  	if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
> @@ -1329,27 +1330,21 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
>  		return;
>  	}
>  
> -	if (strcmp(name, XATTR_NAME_SMACK) == 0) {
> -		skp = smk_import_entry(value, size);
> -		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 (!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 (strcmp(name, XATTR_NAME_SMACK) == 0)
> +		skpp = &isp->smk_inode;
> +	else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
> +		skpp = &isp->smk_task;
> +	else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
> +		skpp = &isp->smk_mmap;
> +
> +	if (skpp) {
> +		skp = smk_get_label(value, size, true);
> +
>  		if (!IS_ERR(skp))
> -			isp->smk_mmap = skp;
> +			*skpp = skp;
>  		else
> -			isp->smk_mmap = &smack_known_invalid;
> +			*skpp = &smack_known_invalid;
>  	}
> -
> -	return;
>  }
>  
>  /**
> @@ -1443,15 +1438,17 @@ static int smack_inode_getsecurity(const struct inode *inode,
>  	struct socket *sock;
>  	struct super_block *sbp;
>  	struct inode *ip = (struct inode *)inode;
> -	struct smack_known *isp;
> -	int ilen;
> +	struct smack_known *isp = NULL;
>  	int rc = 0;
>  
> -	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
> +	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0)
>  		isp = smk_of_inode(inode);
> -		ilen = strlen(isp->smk_known);
> -		*buffer = isp->smk_known;
> -		return ilen;
> +
> +	if (isp) {
> +		*buffer = smk_find_label_name(isp);
> +		if (*buffer == NULL)
> +			*buffer = smack_known_huh.smk_known;
> +		return strlen(*buffer);
>  	}
>  
>  	/*
> @@ -1474,10 +1471,11 @@ static int smack_inode_getsecurity(const struct inode *inode,
>  	else
>  		return -EOPNOTSUPP;
>  
> -	ilen = strlen(isp->smk_known);
>  	if (rc == 0) {
> -		*buffer = isp->smk_known;
> -		rc = ilen;
> +		*buffer = smk_find_label_name(isp);
> +		if (*buffer == NULL)
> +			*buffer = smack_known_huh.smk_known;
> +		rc = strlen(*buffer);
>  	}
>  
>  	return rc;
> @@ -2658,7 +2656,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
>  	if (value == NULL || size > SMK_LONGLABEL || size == 0)
>  		return -EINVAL;
>  
> -	skp = smk_import_entry(value, size);
> +	skp = smk_get_label(value, size, true);
>  	if (IS_ERR(skp))
>  		return PTR_ERR(skp);
>  
> @@ -3528,7 +3526,10 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
>  	if (strcmp(name, "current") != 0)
>  		return -EINVAL;
>  
> -	cp = kstrdup(skp->smk_known, GFP_KERNEL);
> +	cp = smk_find_label_name(skp);
> +	if (cp == NULL)
> +		cp = smack_known_huh.smk_known;
> +	cp = kstrdup(cp, GFP_KERNEL);
>  	if (cp == NULL)
>  		return -ENOMEM;
>  
> @@ -3572,7 +3573,7 @@ static int smack_setprocattr(struct task_struct *p, const struct cred *f_cred,
>  	if (strcmp(name, "current") != 0)
>  		return -EINVAL;
>  
> -	skp = smk_import_entry(value, size);
> +	skp = smk_get_label(value, size, true);
>  	if (IS_ERR(skp))
>  		return PTR_ERR(skp);
>  
> @@ -4311,7 +4312,10 @@ static int smack_key_getsecurity(struct key *key, char **_buffer)
>  		return 0;
>  	}
>  
> -	copy = kstrdup(skp->smk_known, GFP_KERNEL);
> +	copy = smk_find_label_name(skp);
> +	if (copy == NULL)
> +		copy = smack_known_huh.smk_known;
> +	copy = kstrdup(copy, GFP_KERNEL);
>  	if (copy == NULL)
>  		return -ENOMEM;
>  	length = strlen(copy) + 1;
> diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
> index 05e09ee2..e5fb555 100644
> --- a/security/smack/smackfs.c
> +++ b/security/smack/smackfs.c
> @@ -340,36 +340,17 @@ static int smk_fill_rule(const char *subject, const char *object,
>  				struct smack_parsed_rule *rule, int import,
>  				int len)
>  {
> -	const char *cp;
> -	struct smack_known *skp;
> -
> -	if (import) {
> -		rule->smk_subject = smk_import_entry(subject, len);
> -		if (IS_ERR(rule->smk_subject))
> -			return PTR_ERR(rule->smk_subject);
> -
> -		rule->smk_object = smk_import_entry(object, len);
> -		if (IS_ERR(rule->smk_object))
> -			return PTR_ERR(rule->smk_object);
> -	} else {
> -		cp = smk_parse_smack(subject, len);
> -		if (IS_ERR(cp))
> -			return PTR_ERR(cp);
> -		skp = smk_find_entry(cp);
> -		kfree(cp);
> -		if (skp == NULL)
> -			return -ENOENT;
> -		rule->smk_subject = skp;
> -
> -		cp = smk_parse_smack(object, len);
> -		if (IS_ERR(cp))
> -			return PTR_ERR(cp);
> -		skp = smk_find_entry(cp);
> -		kfree(cp);
> -		if (skp == NULL)
> -			return -ENOENT;
> -		rule->smk_object = skp;
> -	}
> +	rule->smk_subject = smk_get_label(subject, len, import);
> +	if (IS_ERR(rule->smk_subject))
> +		return PTR_ERR(rule->smk_subject);
> +	if (rule->smk_subject == NULL)
> +		return -ENOENT;
> +
> +	rule->smk_object = smk_get_label(object, len, import);
> +	if (IS_ERR(rule->smk_object))
> +		return PTR_ERR(rule->smk_object);
> +	if (rule->smk_object == NULL)
> +		return -ENOENT;
>  
>  	rule->smk_access1 = smk_perm_from_str(access1);
>  	if (access2)
> @@ -592,6 +573,9 @@ static void smk_seq_stop(struct seq_file *s, void *v)
>  
>  static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
>  {
> +	char *sbj;
> +	char *obj;
> +
>  	/*
>  	 * Don't show any rules with label names too long for
>  	 * interface file (/smack/load or /smack/load2)
> @@ -605,9 +589,13 @@ static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
>  	if (srp->smk_access == 0)
>  		return;
>  
> -	seq_printf(s, "%s %s",
> -		   srp->smk_subject->smk_known,
> -		   srp->smk_object->smk_known);
> +	sbj = smk_find_label_name(srp->smk_subject);
> +	obj = smk_find_label_name(srp->smk_object);
> +
> +	if (sbj == NULL || obj == NULL)
> +		return;
> +
> +	seq_printf(s, "%s %s", sbj, obj);
>  
>  	seq_putc(s, ' ');
>  
> @@ -798,6 +786,7 @@ static int cipso_seq_show(struct seq_file *s, void *v)
>  		list_entry_rcu(list, struct smack_known, list);
>  	struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
>  	char sep = '/';
> +	char *cp;
>  	int i;
>  
>  	/*
> @@ -811,7 +800,11 @@ static int cipso_seq_show(struct seq_file *s, void *v)
>  	if (strlen(skp->smk_known) >= SMK_LABELLEN)
>  		return 0;
>  
> -	seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
> +	cp = smk_find_label_name(skp);
> +	if (cp == NULL)
> +		return 0;
> +
> +	seq_printf(s, "%s %3d", cp, skp->smk_netlabel.attr.mls.lvl);
>  
>  	for (i = netlbl_catmap_walk(cmp, 0); i >= 0;
>  	     i = netlbl_catmap_walk(cmp, i + 1)) {
> @@ -900,7 +893,7 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
>  	 */
>  	mutex_lock(&smack_cipso_lock);
>  
> -	skp = smk_import_entry(rule, 0);
> +	skp = smk_get_label(rule, 0, true);
>  	if (IS_ERR(skp)) {
>  		rc = PTR_ERR(skp);
>  		goto out;
> @@ -989,9 +982,14 @@ static int cipso2_seq_show(struct seq_file *s, void *v)
>  		list_entry_rcu(list, struct smack_known, list);
>  	struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
>  	char sep = '/';
> +	char *cp;
>  	int i;
>  
> -	seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
> +	cp = smk_find_label_name(skp);
> +	if (cp == NULL)
> +		return 0;
> +
> +	seq_printf(s, "%s %3d", cp, skp->smk_netlabel.attr.mls.lvl);
>  
>  	for (i = netlbl_catmap_walk(cmp, 0); i >= 0;
>  	     i = netlbl_catmap_walk(cmp, i + 1)) {
> @@ -1072,8 +1070,12 @@ static int net4addr_seq_show(struct seq_file *s, void *v)
>  			list_entry_rcu(list, struct smk_net4addr, list);
>  	char *kp = SMACK_CIPSO_OPTION;
>  
> -	if (skp->smk_label != NULL)
> -		kp = skp->smk_label->smk_known;
> +	if (skp->smk_label != NULL) {
> +		kp = smk_find_label_name(skp->smk_label);
> +		if (kp == NULL)
> +			kp = smack_known_huh.smk_known;
> +	}
> +
>  	seq_printf(s, "%pI4/%d %s\n", &skp->smk_host.s_addr,
>  			skp->smk_masks, kp);
>  
> @@ -1224,7 +1226,7 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
>  	 * If smack begins with '-', it is an option, don't import it
>  	 */
>  	if (smack[0] != '-') {
> -		skp = smk_import_entry(smack, 0);
> +		skp = smk_get_label(smack, 0, true);
>  		if (IS_ERR(skp)) {
>  			rc = PTR_ERR(skp);
>  			goto free_out;
> @@ -1343,10 +1345,16 @@ static int net6addr_seq_show(struct seq_file *s, void *v)
>  	struct list_head *list = v;
>  	struct smk_net6addr *skp =
>  			 list_entry(list, struct smk_net6addr, list);
> +	char *kp;
>  
> -	if (skp->smk_label != NULL)
> -		seq_printf(s, "%pI6/%d %s\n", &skp->smk_host, skp->smk_masks,
> -				skp->smk_label->smk_known);
> +	if (skp->smk_label != NULL) {
> +		kp = smk_find_label_name(skp->smk_label);
> +		if (kp == NULL)
> +			kp = smack_known_huh.smk_known;
> +
> +		seq_printf(s, "%pI6/%d %s\n", &skp->smk_host,
> +				skp->smk_masks, kp);
> +	}
>  
>  	return 0;
>  }
> @@ -1500,7 +1508,7 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
>  	 * If smack begins with '-', it is an option, don't import it
>  	 */
>  	if (smack[0] != '-') {
> -		skp = smk_import_entry(smack, 0);
> +		skp = smk_get_label(smack, 0, true);
>  		if (IS_ERR(skp)) {
>  			rc = PTR_ERR(skp);
>  			goto free_out;
> @@ -1820,6 +1828,7 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
>  				size_t cn, loff_t *ppos)
>  {
>  	ssize_t rc;
> +	char *cp;
>  	int asize;
>  
>  	if (*ppos != 0)
> @@ -1830,12 +1839,14 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
>  	 */
>  	mutex_lock(&smack_ambient_lock);
>  
> -	asize = strlen(smack_net_ambient->smk_known) + 1;
> +	cp = smk_find_label_name(smack_net_ambient);
> +	if (cp == NULL)
> +		cp = smack_known_huh.smk_known;
> +
> +	asize = strlen(cp) + 1;
>  
>  	if (cn >= asize)
> -		rc = simple_read_from_buffer(buf, cn, ppos,
> -					     smack_net_ambient->smk_known,
> -					     asize);
> +		rc = simple_read_from_buffer(buf, cn, ppos, cp, asize);
>  	else
>  		rc = -EINVAL;
>  
> @@ -1873,7 +1884,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
>  		goto out;
>  	}
>  
> -	skp = smk_import_entry(data, count);
> +	skp = smk_get_label(data, count, true);
>  	if (IS_ERR(skp)) {
>  		rc = PTR_ERR(skp);
>  		goto out;
> @@ -1913,11 +1924,16 @@ static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
>  
>  static int onlycap_seq_show(struct seq_file *s, void *v)
>  {
> +	char *smack;
>  	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);
> +	smack = smk_find_label_name(sop->smk_label);
> +	if (smack == NULL)
> +		smack = smack_known_huh.smk_known;
> +
> +	seq_puts(s, smack);
>  	seq_putc(s, ' ');
>  
>  	return 0;
> @@ -2011,7 +2027,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
>  		if (!*tok)
>  			continue;
>  
> -		skp = smk_import_entry(tok, 0);
> +		skp = smk_get_label(tok, 0, true);
>  		if (IS_ERR(skp)) {
>  			rc = PTR_ERR(skp);
>  			break;
> @@ -2081,8 +2097,11 @@ static ssize_t smk_read_unconfined(struct file *filp, char __user *buf,
>  	if (*ppos != 0)
>  		return 0;
>  
> -	if (smack_unconfined != NULL)
> -		smack = smack_unconfined->smk_known;
> +	if (smack_unconfined != NULL) {
> +		smack = smk_find_label_name(smack_unconfined);
> +		if (smack == NULL)
> +			smack = smack_known_huh.smk_known;
> +	}
>  
>  	asize = strlen(smack) + 1;
>  
> @@ -2129,7 +2148,7 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
>  	 *
>  	 * But do so only on invalid label, not on system errors.
>  	 */
> -	skp = smk_import_entry(data, count);
> +	skp = smk_get_label(data, count, true);
>  	if (PTR_ERR(skp) == -EINVAL)
>  		skp = NULL;
>  	else if (IS_ERR(skp)) {
> @@ -2526,7 +2545,6 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
>  				size_t count, loff_t *ppos)
>  {
>  	char *data;
> -	const char *cp;
>  	struct smack_known *skp;
>  	struct smack_rule *sp;
>  	struct list_head *rule_list;
> @@ -2551,15 +2569,13 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
>  		goto out_data;
>  	}
>  
> -	cp = smk_parse_smack(data, count);
> -	if (IS_ERR(cp)) {
> -		rc = PTR_ERR(cp);
> +	skp = smk_get_label(data, count, false);
> +	if (IS_ERR(skp)) {
> +		rc = PTR_ERR(skp);
>  		goto out_data;
>  	}
> -
> -	skp = smk_find_entry(cp);
>  	if (skp == NULL)
> -		goto out_cp;
> +		goto out_data;
>  
>  	rule_list = &skp->smk_rules;
>  	rule_lock = &skp->smk_rules_lock;
> @@ -2571,8 +2587,6 @@ static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
>  
>  	mutex_unlock(rule_lock);
>  
> -out_cp:
> -	kfree(cp);
>  out_data:
>  	kfree(data);
>  
> @@ -2641,8 +2655,11 @@ static ssize_t smk_read_syslog(struct file *filp, char __user *buf,
>  	if (*ppos != 0)
>  		return 0;
>  
> -	if (smack_syslog_label != NULL)
> -		smack = smack_syslog_label->smk_known;
> +	if (smack_syslog_label != NULL) {
> +		smack = smk_find_label_name(smack_syslog_label);
> +		if (smack == NULL)
> +			smack = smack_known_huh.smk_known;
> +	}
>  
>  	asize = strlen(smack) + 1;
>  
> @@ -2689,7 +2706,7 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
>  	 *
>  	 * But do so only on invalid label, not on system errors.
>  	 */
> -	skp = smk_import_entry(data, count);
> +	skp = smk_get_label(data, count, true);
>  	if (PTR_ERR(skp) == -EINVAL)
>  		skp = NULL;
>  	else if (IS_ERR(skp)) {

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Patch
diff mbox

diff --git a/security/smack/smack.h b/security/smack/smack.h
index ca8fb7c..091efc2 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -306,6 +306,8 @@  int smack_has_ns_privilege(struct task_struct *task,
 int smack_has_privilege(struct task_struct *task, int cap);
 int smack_ns_privileged(struct user_namespace *user_ns, int cap);
 int smack_privileged(int cap);
+char *smk_find_label_name(struct smack_known *skp);
+struct smack_known *smk_get_label(const char *string, int len, bool import);
 
 /*
  * Shared data.
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 72f848e..131c742 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -716,3 +716,44 @@  int smack_privileged(int cap)
 {
 	return smack_ns_privileged(&init_user_ns, cap);
 }
+
+/**
+ * smk_find_label_name - A helper to get a string value of a label
+ * @skp: a label we want a string value from
+ *
+ * Returns a pointer to a label name or NULL if label name not found.
+ */
+char *smk_find_label_name(struct smack_known *skp)
+{
+	return skp->smk_known;
+}
+
+/**
+ * smk_get_label - A helper to get the smack_known value from a string using
+ *                 either import or find functions if it already exists
+ * @string: a name of a label we look for or want to import
+ * @len: the string size, or zero if it is NULL terminated
+ * @import: whether we should import the label if not found
+ *
+ * Returns a smack_known label that is either imported or found.
+ * NULL if label not found (only when import == false).
+ * Error code otherwise.
+ */
+struct smack_known *smk_get_label(const char *string, int len, bool import)
+{
+	struct smack_known *skp;
+	char *cp;
+
+	if (import) {
+		skp = smk_import_entry(string, len);
+	} else {
+		cp = smk_parse_smack(string, len);
+		if (IS_ERR(cp))
+			return ERR_CAST(cp);
+
+		skp = smk_find_entry(cp);
+		kfree(cp);
+	}
+
+	return skp;
+}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 198d3d6..7303c37 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -746,31 +746,31 @@  static int smack_set_mnt_opts(struct super_block *sb,
 	for (i = 0; i < num_opts; i++) {
 		switch (opts->mnt_opts_flags[i]) {
 		case FSDEFAULT_MNT:
-			skp = smk_import_entry(opts->mnt_opts[i], 0);
+			skp = smk_get_label(opts->mnt_opts[i], 0, true);
 			if (IS_ERR(skp))
 				return PTR_ERR(skp);
 			sp->smk_default = skp;
 			break;
 		case FSFLOOR_MNT:
-			skp = smk_import_entry(opts->mnt_opts[i], 0);
+			skp = smk_get_label(opts->mnt_opts[i], 0, true);
 			if (IS_ERR(skp))
 				return PTR_ERR(skp);
 			sp->smk_floor = skp;
 			break;
 		case FSHAT_MNT:
-			skp = smk_import_entry(opts->mnt_opts[i], 0);
+			skp = smk_get_label(opts->mnt_opts[i], 0, true);
 			if (IS_ERR(skp))
 				return PTR_ERR(skp);
 			sp->smk_hat = skp;
 			break;
 		case FSROOT_MNT:
-			skp = smk_import_entry(opts->mnt_opts[i], 0);
+			skp = smk_get_label(opts->mnt_opts[i], 0, true);
 			if (IS_ERR(skp))
 				return PTR_ERR(skp);
 			sp->smk_root = skp;
 			break;
 		case FSTRANS_MNT:
-			skp = smk_import_entry(opts->mnt_opts[i], 0);
+			skp = smk_get_label(opts->mnt_opts[i], 0, true);
 			if (IS_ERR(skp))
 				return PTR_ERR(skp);
 			sp->smk_root = skp;
@@ -1288,7 +1288,7 @@  static int smack_inode_setxattr(struct dentry *dentry, const char *name,
 		rc = -EPERM;
 
 	if (rc == 0 && check_import) {
-		skp = size ? smk_import_entry(value, size) : NULL;
+		skp = size ? smk_get_label(value, size, true) : NULL;
 		if (IS_ERR(skp))
 			rc = PTR_ERR(skp);
 		else if (skp == NULL || (check_star &&
@@ -1322,6 +1322,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 smack_known **skpp = NULL;
 	struct inode_smack *isp = d_backing_inode(dentry)->i_security;
 
 	if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
@@ -1329,27 +1330,21 @@  static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
 		return;
 	}
 
-	if (strcmp(name, XATTR_NAME_SMACK) == 0) {
-		skp = smk_import_entry(value, size);
-		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 (!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 (strcmp(name, XATTR_NAME_SMACK) == 0)
+		skpp = &isp->smk_inode;
+	else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
+		skpp = &isp->smk_task;
+	else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
+		skpp = &isp->smk_mmap;
+
+	if (skpp) {
+		skp = smk_get_label(value, size, true);
+
 		if (!IS_ERR(skp))
-			isp->smk_mmap = skp;
+			*skpp = skp;
 		else
-			isp->smk_mmap = &smack_known_invalid;
+			*skpp = &smack_known_invalid;
 	}
-
-	return;
 }
 
 /**
@@ -1443,15 +1438,17 @@  static int smack_inode_getsecurity(const struct inode *inode,
 	struct socket *sock;
 	struct super_block *sbp;
 	struct inode *ip = (struct inode *)inode;
-	struct smack_known *isp;
-	int ilen;
+	struct smack_known *isp = NULL;
 	int rc = 0;
 
-	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) {
+	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0)
 		isp = smk_of_inode(inode);
-		ilen = strlen(isp->smk_known);
-		*buffer = isp->smk_known;
-		return ilen;
+
+	if (isp) {
+		*buffer = smk_find_label_name(isp);
+		if (*buffer == NULL)
+			*buffer = smack_known_huh.smk_known;
+		return strlen(*buffer);
 	}
 
 	/*
@@ -1474,10 +1471,11 @@  static int smack_inode_getsecurity(const struct inode *inode,
 	else
 		return -EOPNOTSUPP;
 
-	ilen = strlen(isp->smk_known);
 	if (rc == 0) {
-		*buffer = isp->smk_known;
-		rc = ilen;
+		*buffer = smk_find_label_name(isp);
+		if (*buffer == NULL)
+			*buffer = smack_known_huh.smk_known;
+		rc = strlen(*buffer);
 	}
 
 	return rc;
@@ -2658,7 +2656,7 @@  static int smack_inode_setsecurity(struct inode *inode, const char *name,
 	if (value == NULL || size > SMK_LONGLABEL || size == 0)
 		return -EINVAL;
 
-	skp = smk_import_entry(value, size);
+	skp = smk_get_label(value, size, true);
 	if (IS_ERR(skp))
 		return PTR_ERR(skp);
 
@@ -3528,7 +3526,10 @@  static int smack_getprocattr(struct task_struct *p, char *name, char **value)
 	if (strcmp(name, "current") != 0)
 		return -EINVAL;
 
-	cp = kstrdup(skp->smk_known, GFP_KERNEL);
+	cp = smk_find_label_name(skp);
+	if (cp == NULL)
+		cp = smack_known_huh.smk_known;
+	cp = kstrdup(cp, GFP_KERNEL);
 	if (cp == NULL)
 		return -ENOMEM;
 
@@ -3572,7 +3573,7 @@  static int smack_setprocattr(struct task_struct *p, const struct cred *f_cred,
 	if (strcmp(name, "current") != 0)
 		return -EINVAL;
 
-	skp = smk_import_entry(value, size);
+	skp = smk_get_label(value, size, true);
 	if (IS_ERR(skp))
 		return PTR_ERR(skp);
 
@@ -4311,7 +4312,10 @@  static int smack_key_getsecurity(struct key *key, char **_buffer)
 		return 0;
 	}
 
-	copy = kstrdup(skp->smk_known, GFP_KERNEL);
+	copy = smk_find_label_name(skp);
+	if (copy == NULL)
+		copy = smack_known_huh.smk_known;
+	copy = kstrdup(copy, GFP_KERNEL);
 	if (copy == NULL)
 		return -ENOMEM;
 	length = strlen(copy) + 1;
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 05e09ee2..e5fb555 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -340,36 +340,17 @@  static int smk_fill_rule(const char *subject, const char *object,
 				struct smack_parsed_rule *rule, int import,
 				int len)
 {
-	const char *cp;
-	struct smack_known *skp;
-
-	if (import) {
-		rule->smk_subject = smk_import_entry(subject, len);
-		if (IS_ERR(rule->smk_subject))
-			return PTR_ERR(rule->smk_subject);
-
-		rule->smk_object = smk_import_entry(object, len);
-		if (IS_ERR(rule->smk_object))
-			return PTR_ERR(rule->smk_object);
-	} else {
-		cp = smk_parse_smack(subject, len);
-		if (IS_ERR(cp))
-			return PTR_ERR(cp);
-		skp = smk_find_entry(cp);
-		kfree(cp);
-		if (skp == NULL)
-			return -ENOENT;
-		rule->smk_subject = skp;
-
-		cp = smk_parse_smack(object, len);
-		if (IS_ERR(cp))
-			return PTR_ERR(cp);
-		skp = smk_find_entry(cp);
-		kfree(cp);
-		if (skp == NULL)
-			return -ENOENT;
-		rule->smk_object = skp;
-	}
+	rule->smk_subject = smk_get_label(subject, len, import);
+	if (IS_ERR(rule->smk_subject))
+		return PTR_ERR(rule->smk_subject);
+	if (rule->smk_subject == NULL)
+		return -ENOENT;
+
+	rule->smk_object = smk_get_label(object, len, import);
+	if (IS_ERR(rule->smk_object))
+		return PTR_ERR(rule->smk_object);
+	if (rule->smk_object == NULL)
+		return -ENOENT;
 
 	rule->smk_access1 = smk_perm_from_str(access1);
 	if (access2)
@@ -592,6 +573,9 @@  static void smk_seq_stop(struct seq_file *s, void *v)
 
 static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
 {
+	char *sbj;
+	char *obj;
+
 	/*
 	 * Don't show any rules with label names too long for
 	 * interface file (/smack/load or /smack/load2)
@@ -605,9 +589,13 @@  static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max)
 	if (srp->smk_access == 0)
 		return;
 
-	seq_printf(s, "%s %s",
-		   srp->smk_subject->smk_known,
-		   srp->smk_object->smk_known);
+	sbj = smk_find_label_name(srp->smk_subject);
+	obj = smk_find_label_name(srp->smk_object);
+
+	if (sbj == NULL || obj == NULL)
+		return;
+
+	seq_printf(s, "%s %s", sbj, obj);
 
 	seq_putc(s, ' ');
 
@@ -798,6 +786,7 @@  static int cipso_seq_show(struct seq_file *s, void *v)
 		list_entry_rcu(list, struct smack_known, list);
 	struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
 	char sep = '/';
+	char *cp;
 	int i;
 
 	/*
@@ -811,7 +800,11 @@  static int cipso_seq_show(struct seq_file *s, void *v)
 	if (strlen(skp->smk_known) >= SMK_LABELLEN)
 		return 0;
 
-	seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
+	cp = smk_find_label_name(skp);
+	if (cp == NULL)
+		return 0;
+
+	seq_printf(s, "%s %3d", cp, skp->smk_netlabel.attr.mls.lvl);
 
 	for (i = netlbl_catmap_walk(cmp, 0); i >= 0;
 	     i = netlbl_catmap_walk(cmp, i + 1)) {
@@ -900,7 +893,7 @@  static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
 	 */
 	mutex_lock(&smack_cipso_lock);
 
-	skp = smk_import_entry(rule, 0);
+	skp = smk_get_label(rule, 0, true);
 	if (IS_ERR(skp)) {
 		rc = PTR_ERR(skp);
 		goto out;
@@ -989,9 +982,14 @@  static int cipso2_seq_show(struct seq_file *s, void *v)
 		list_entry_rcu(list, struct smack_known, list);
 	struct netlbl_lsm_catmap *cmp = skp->smk_netlabel.attr.mls.cat;
 	char sep = '/';
+	char *cp;
 	int i;
 
-	seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl);
+	cp = smk_find_label_name(skp);
+	if (cp == NULL)
+		return 0;
+
+	seq_printf(s, "%s %3d", cp, skp->smk_netlabel.attr.mls.lvl);
 
 	for (i = netlbl_catmap_walk(cmp, 0); i >= 0;
 	     i = netlbl_catmap_walk(cmp, i + 1)) {
@@ -1072,8 +1070,12 @@  static int net4addr_seq_show(struct seq_file *s, void *v)
 			list_entry_rcu(list, struct smk_net4addr, list);
 	char *kp = SMACK_CIPSO_OPTION;
 
-	if (skp->smk_label != NULL)
-		kp = skp->smk_label->smk_known;
+	if (skp->smk_label != NULL) {
+		kp = smk_find_label_name(skp->smk_label);
+		if (kp == NULL)
+			kp = smack_known_huh.smk_known;
+	}
+
 	seq_printf(s, "%pI4/%d %s\n", &skp->smk_host.s_addr,
 			skp->smk_masks, kp);
 
@@ -1224,7 +1226,7 @@  static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
 	 * If smack begins with '-', it is an option, don't import it
 	 */
 	if (smack[0] != '-') {
-		skp = smk_import_entry(smack, 0);
+		skp = smk_get_label(smack, 0, true);
 		if (IS_ERR(skp)) {
 			rc = PTR_ERR(skp);
 			goto free_out;
@@ -1343,10 +1345,16 @@  static int net6addr_seq_show(struct seq_file *s, void *v)
 	struct list_head *list = v;
 	struct smk_net6addr *skp =
 			 list_entry(list, struct smk_net6addr, list);
+	char *kp;
 
-	if (skp->smk_label != NULL)
-		seq_printf(s, "%pI6/%d %s\n", &skp->smk_host, skp->smk_masks,
-				skp->smk_label->smk_known);
+	if (skp->smk_label != NULL) {
+		kp = smk_find_label_name(skp->smk_label);
+		if (kp == NULL)
+			kp = smack_known_huh.smk_known;
+
+		seq_printf(s, "%pI6/%d %s\n", &skp->smk_host,
+				skp->smk_masks, kp);
+	}
 
 	return 0;
 }
@@ -1500,7 +1508,7 @@  static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
 	 * If smack begins with '-', it is an option, don't import it
 	 */
 	if (smack[0] != '-') {
-		skp = smk_import_entry(smack, 0);
+		skp = smk_get_label(smack, 0, true);
 		if (IS_ERR(skp)) {
 			rc = PTR_ERR(skp);
 			goto free_out;
@@ -1820,6 +1828,7 @@  static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
 				size_t cn, loff_t *ppos)
 {
 	ssize_t rc;
+	char *cp;
 	int asize;
 
 	if (*ppos != 0)
@@ -1830,12 +1839,14 @@  static ssize_t smk_read_ambient(struct file *filp, char __user *buf,
 	 */
 	mutex_lock(&smack_ambient_lock);
 
-	asize = strlen(smack_net_ambient->smk_known) + 1;
+	cp = smk_find_label_name(smack_net_ambient);
+	if (cp == NULL)
+		cp = smack_known_huh.smk_known;
+
+	asize = strlen(cp) + 1;
 
 	if (cn >= asize)
-		rc = simple_read_from_buffer(buf, cn, ppos,
-					     smack_net_ambient->smk_known,
-					     asize);
+		rc = simple_read_from_buffer(buf, cn, ppos, cp, asize);
 	else
 		rc = -EINVAL;
 
@@ -1873,7 +1884,7 @@  static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
 		goto out;
 	}
 
-	skp = smk_import_entry(data, count);
+	skp = smk_get_label(data, count, true);
 	if (IS_ERR(skp)) {
 		rc = PTR_ERR(skp);
 		goto out;
@@ -1913,11 +1924,16 @@  static void *onlycap_seq_next(struct seq_file *s, void *v, loff_t *pos)
 
 static int onlycap_seq_show(struct seq_file *s, void *v)
 {
+	char *smack;
 	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);
+	smack = smk_find_label_name(sop->smk_label);
+	if (smack == NULL)
+		smack = smack_known_huh.smk_known;
+
+	seq_puts(s, smack);
 	seq_putc(s, ' ');
 
 	return 0;
@@ -2011,7 +2027,7 @@  static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
 		if (!*tok)
 			continue;
 
-		skp = smk_import_entry(tok, 0);
+		skp = smk_get_label(tok, 0, true);
 		if (IS_ERR(skp)) {
 			rc = PTR_ERR(skp);
 			break;
@@ -2081,8 +2097,11 @@  static ssize_t smk_read_unconfined(struct file *filp, char __user *buf,
 	if (*ppos != 0)
 		return 0;
 
-	if (smack_unconfined != NULL)
-		smack = smack_unconfined->smk_known;
+	if (smack_unconfined != NULL) {
+		smack = smk_find_label_name(smack_unconfined);
+		if (smack == NULL)
+			smack = smack_known_huh.smk_known;
+	}
 
 	asize = strlen(smack) + 1;
 
@@ -2129,7 +2148,7 @@  static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
 	 *
 	 * But do so only on invalid label, not on system errors.
 	 */
-	skp = smk_import_entry(data, count);
+	skp = smk_get_label(data, count, true);
 	if (PTR_ERR(skp) == -EINVAL)
 		skp = NULL;
 	else if (IS_ERR(skp)) {
@@ -2526,7 +2545,6 @@  static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
 				size_t count, loff_t *ppos)
 {
 	char *data;
-	const char *cp;
 	struct smack_known *skp;
 	struct smack_rule *sp;
 	struct list_head *rule_list;
@@ -2551,15 +2569,13 @@  static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
 		goto out_data;
 	}
 
-	cp = smk_parse_smack(data, count);
-	if (IS_ERR(cp)) {
-		rc = PTR_ERR(cp);
+	skp = smk_get_label(data, count, false);
+	if (IS_ERR(skp)) {
+		rc = PTR_ERR(skp);
 		goto out_data;
 	}
-
-	skp = smk_find_entry(cp);
 	if (skp == NULL)
-		goto out_cp;
+		goto out_data;
 
 	rule_list = &skp->smk_rules;
 	rule_lock = &skp->smk_rules_lock;
@@ -2571,8 +2587,6 @@  static ssize_t smk_write_revoke_subj(struct file *file, const char __user *buf,
 
 	mutex_unlock(rule_lock);
 
-out_cp:
-	kfree(cp);
 out_data:
 	kfree(data);
 
@@ -2641,8 +2655,11 @@  static ssize_t smk_read_syslog(struct file *filp, char __user *buf,
 	if (*ppos != 0)
 		return 0;
 
-	if (smack_syslog_label != NULL)
-		smack = smack_syslog_label->smk_known;
+	if (smack_syslog_label != NULL) {
+		smack = smk_find_label_name(smack_syslog_label);
+		if (smack == NULL)
+			smack = smack_known_huh.smk_known;
+	}
 
 	asize = strlen(smack) + 1;
 
@@ -2689,7 +2706,7 @@  static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
 	 *
 	 * But do so only on invalid label, not on system errors.
 	 */
-	skp = smk_import_entry(data, count);
+	skp = smk_get_label(data, count, true);
 	if (PTR_ERR(skp) == -EINVAL)
 		skp = NULL;
 	else if (IS_ERR(skp)) {