diff options
Diffstat (limited to 'security/smack/smack_lsm.c')
| -rw-r--r-- | security/smack/smack_lsm.c | 243 | 
1 files changed, 86 insertions, 157 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 45c32f07416..d583c054580 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -30,7 +30,6 @@  #include <linux/slab.h>  #include <linux/mutex.h>  #include <linux/pipe_fs_i.h> -#include <net/netlabel.h>  #include <net/cipso_ipv4.h>  #include <linux/audit.h>  #include <linux/magic.h> @@ -57,16 +56,23 @@  static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp)  {  	int rc; -	char in[SMK_LABELLEN]; +	char *buffer; +	char *result = NULL;  	if (ip->i_op->getxattr == NULL)  		return NULL; -	rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN); -	if (rc < 0) +	buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); +	if (buffer == NULL)  		return NULL; -	return smk_import(in, rc); +	rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); +	if (rc > 0) +		result = smk_import(buffer, rc); + +	kfree(buffer); + +	return result;  }  /** @@ -79,7 +85,7 @@ struct inode_smack *new_inode_smack(char *smack)  {  	struct inode_smack *isp; -	isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL); +	isp = kzalloc(sizeof(struct inode_smack), GFP_NOFS);  	if (isp == NULL)  		return NULL; @@ -556,13 +562,14 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,  				     void **value, size_t *len)  {  	struct smack_known *skp; +	struct inode_smack *issp = inode->i_security;  	char *csp = smk_of_current();  	char *isp = smk_of_inode(inode);  	char *dsp = smk_of_inode(dir);  	int may;  	if (name) { -		*name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); +		*name = kstrdup(XATTR_SMACK_SUFFIX, GFP_NOFS);  		if (*name == NULL)  			return -ENOMEM;  	} @@ -577,12 +584,15 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,  		 * If the access rule allows transmutation and  		 * the directory requests transmutation then  		 * by all means transmute. +		 * Mark the inode as changed.  		 */  		if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && -		    smk_inode_transmutable(dir)) +		    smk_inode_transmutable(dir)) {  			isp = dsp; +			issp->smk_flags |= SMK_INODE_CHANGED; +		} -		*value = kstrdup(isp, GFP_KERNEL); +		*value = kstrdup(isp, GFP_NOFS);  		if (*value == NULL)  			return -ENOMEM;  	} @@ -821,7 +831,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,  		 * check label validity here so import wont fail on  		 * post_setxattr  		 */ -		if (size == 0 || size >= SMK_LABELLEN || +		if (size == 0 || size >= SMK_LONGLABEL ||  		    smk_import(value, size) == NULL)  			rc = -EINVAL;  	} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { @@ -1349,7 +1359,7 @@ static int smack_file_receive(struct file *file)  }  /** - * smack_dentry_open - Smack dentry open processing + * smack_file_open - Smack dentry open processing   * @file: the object   * @cred: unused   * @@ -1357,7 +1367,7 @@ static int smack_file_receive(struct file *file)   *   * Returns 0   */ -static int smack_dentry_open(struct file *file, const struct cred *cred) +static int smack_file_open(struct file *file, const struct cred *cred)  {  	struct inode_smack *isp = file->f_path.dentry->d_inode->i_security; @@ -1820,65 +1830,6 @@ static char *smack_host_label(struct sockaddr_in *sip)  }  /** - * smack_set_catset - convert a capset to netlabel mls categories - * @catset: the Smack categories - * @sap: where to put the netlabel categories - * - * Allocates and fills attr.mls.cat - */ -static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap) -{ -	unsigned char *cp; -	unsigned char m; -	int cat; -	int rc; -	int byte; - -	if (!catset) -		return; - -	sap->flags |= NETLBL_SECATTR_MLS_CAT; -	sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); -	sap->attr.mls.cat->startbit = 0; - -	for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++) -		for (m = 0x80; m != 0; m >>= 1, cat++) { -			if ((m & *cp) == 0) -				continue; -			rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, -							  cat, GFP_ATOMIC); -		} -} - -/** - * smack_to_secattr - fill a secattr from a smack value - * @smack: the smack value - * @nlsp: where the result goes - * - * Casey says that CIPSO is good enough for now. - * It can be used to effect. - * It can also be abused to effect when necessary. - * Apologies to the TSIG group in general and GW in particular. - */ -static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) -{ -	struct smack_cipso cipso; -	int rc; - -	nlsp->domain = smack; -	nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; - -	rc = smack_to_cipso(smack, &cipso); -	if (rc == 0) { -		nlsp->attr.mls.lvl = cipso.smk_level; -		smack_set_catset(cipso.smk_catset, nlsp); -	} else { -		nlsp->attr.mls.lvl = smack_cipso_direct; -		smack_set_catset(smack, nlsp); -	} -} - -/**   * smack_netlabel - Set the secattr on a socket   * @sk: the socket   * @labeled: socket label scheme @@ -1890,8 +1841,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp)   */  static int smack_netlabel(struct sock *sk, int labeled)  { +	struct smack_known *skp;  	struct socket_smack *ssp = sk->sk_security; -	struct netlbl_lsm_secattr secattr;  	int rc = 0;  	/* @@ -1909,10 +1860,8 @@ static int smack_netlabel(struct sock *sk, int labeled)  	    labeled == SMACK_UNLABELED_SOCKET)  		netlbl_sock_delattr(sk);  	else { -		netlbl_secattr_init(&secattr); -		smack_to_secattr(ssp->smk_out, &secattr); -		rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr); -		netlbl_secattr_destroy(&secattr); +		skp = smk_find_entry(ssp->smk_out); +		rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel);  	}  	bh_unlock_sock(sk); @@ -1985,7 +1934,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,  	struct socket *sock;  	int rc = 0; -	if (value == NULL || size > SMK_LABELLEN || size == 0) +	if (value == NULL || size > SMK_LONGLABEL || size == 0)  		return -EACCES;  	sp = smk_import(value, size); @@ -2552,6 +2501,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  	char *final;  	char trattr[TRANS_TRUE_SIZE];  	int transflag = 0; +	int rc;  	struct dentry *dp;  	if (inode == NULL) @@ -2670,17 +2620,38 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  		 */  		dp = dget(opt_dentry);  		fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); -		if (fetched != NULL) { +		if (fetched != NULL)  			final = fetched; -			if (S_ISDIR(inode->i_mode)) { -				trattr[0] = '\0'; -				inode->i_op->getxattr(dp, + +		/* +		 * Transmuting directory +		 */ +		if (S_ISDIR(inode->i_mode)) { +			/* +			 * If this is a new directory and the label was +			 * transmuted when the inode was initialized +			 * set the transmute attribute on the directory +			 * and mark the inode. +			 * +			 * If there is a transmute attribute on the +			 * directory mark the inode. +			 */ +			if (isp->smk_flags & SMK_INODE_CHANGED) { +				isp->smk_flags &= ~SMK_INODE_CHANGED; +				rc = inode->i_op->setxattr(dp,  					XATTR_NAME_SMACKTRANSMUTE, -					trattr, TRANS_TRUE_SIZE); -				if (strncmp(trattr, TRANS_TRUE, -					    TRANS_TRUE_SIZE) == 0) -					transflag = SMK_INODE_TRANSMUTE; +					TRANS_TRUE, TRANS_TRUE_SIZE, +					0); +			} else { +				rc = inode->i_op->getxattr(dp, +					XATTR_NAME_SMACKTRANSMUTE, trattr, +					TRANS_TRUE_SIZE); +				if (rc >= 0 && strncmp(trattr, TRANS_TRUE, +						       TRANS_TRUE_SIZE) != 0) +					rc = -EINVAL;  			} +			if (rc >= 0) +				transflag = SMK_INODE_TRANSMUTE;  		}  		isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);  		isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); @@ -2759,7 +2730,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,  	if (!capable(CAP_MAC_ADMIN))  		return -EPERM; -	if (value == NULL || size == 0 || size >= SMK_LABELLEN) +	if (value == NULL || size == 0 || size >= SMK_LONGLABEL)  		return -EINVAL;  	if (strcmp(name, "current") != 0) @@ -2895,10 +2866,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,  static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,  				struct socket_smack *ssp)  { -	struct smack_known *skp; -	char smack[SMK_LABELLEN]; +	struct smack_known *kp;  	char *sp; -	int pcat; +	int found = 0;  	if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {  		/* @@ -2906,59 +2876,27 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap,  		 * If there are flags but no level netlabel isn't  		 * behaving the way we expect it to.  		 * -		 * Get the categories, if any +		 * Look it up in the label table  		 * Without guidance regarding the smack value  		 * for the packet fall back on the network  		 * ambient value.  		 */ -		memset(smack, '\0', SMK_LABELLEN); -		if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) -			for (pcat = -1;;) { -				pcat = netlbl_secattr_catmap_walk( -					sap->attr.mls.cat, pcat + 1); -				if (pcat < 0) -					break; -				smack_catset_bit(pcat, smack); -			} -		/* -		 * If it is CIPSO using smack direct mapping -		 * we are already done. WeeHee. -		 */ -		if (sap->attr.mls.lvl == smack_cipso_direct) { -			/* -			 * The label sent is usually on the label list. -			 * -			 * If it is not we may still want to allow the -			 * delivery. -			 * -			 * If the recipient is accepting all packets -			 * because it is using the star ("*") label -			 * for SMACK64IPIN provide the web ("@") label -			 * so that a directed response will succeed. -			 * This is not very correct from a MAC point -			 * of view, but gets around the problem that -			 * locking prevents adding the newly discovered -			 * label to the list. -			 * The case where the recipient is not using -			 * the star label should obviously fail. -			 * The easy way to do this is to provide the -			 * star label as the subject label. -			 */ -			skp = smk_find_entry(smack); -			if (skp != NULL) -				return skp->smk_known; -			if (ssp != NULL && -			    ssp->smk_in == smack_known_star.smk_known) -				return smack_known_web.smk_known; -			return smack_known_star.smk_known; +		rcu_read_lock(); +		list_for_each_entry(kp, &smack_known_list, list) { +			if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl) +				continue; +			if (memcmp(sap->attr.mls.cat, +				kp->smk_netlabel.attr.mls.cat, +				SMK_CIPSOLEN) != 0) +				continue; +			found = 1; +			break;  		} -		/* -		 * Look it up in the supplied table if it is not -		 * a direct mapping. -		 */ -		sp = smack_from_cipso(sap->attr.mls.lvl, smack); -		if (sp != NULL) -			return sp; +		rcu_read_unlock(); + +		if (found) +			return kp->smk_known; +  		if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known)  			return smack_known_web.smk_known;  		return smack_known_star.smk_known; @@ -3158,11 +3096,13 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,  				   struct request_sock *req)  {  	u16 family = sk->sk_family; +	struct smack_known *skp;  	struct socket_smack *ssp = sk->sk_security;  	struct netlbl_lsm_secattr secattr;  	struct sockaddr_in addr;  	struct iphdr *hdr;  	char *sp; +	char *hsp;  	int rc;  	struct smk_audit_info ad;  #ifdef CONFIG_AUDIT @@ -3209,16 +3149,14 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,  	hdr = ip_hdr(skb);  	addr.sin_addr.s_addr = hdr->saddr;  	rcu_read_lock(); -	if (smack_host_label(&addr) == NULL) { -		rcu_read_unlock(); -		netlbl_secattr_init(&secattr); -		smack_to_secattr(sp, &secattr); -		rc = netlbl_req_setattr(req, &secattr); -		netlbl_secattr_destroy(&secattr); -	} else { -		rcu_read_unlock(); +	hsp = smack_host_label(&addr); +	rcu_read_unlock(); + +	if (hsp == NULL) { +		skp = smk_find_entry(sp); +		rc = netlbl_req_setattr(req, &skp->smk_netlabel); +	} else  		netlbl_req_delattr(req); -	}  	return rc;  } @@ -3400,7 +3338,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,  	char *rule = vrule;  	if (!rule) { -		audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR, +		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,  			  "Smack: missing rule\n");  		return -ENOENT;  	} @@ -3549,7 +3487,7 @@ struct security_operations smack_ops = {  	.file_send_sigiotask = 		smack_file_send_sigiotask,  	.file_receive = 		smack_file_receive, -	.dentry_open =			smack_dentry_open, +	.file_open =			smack_file_open,  	.cred_alloc_blank =		smack_cred_alloc_blank,  	.cred_free =			smack_cred_free, @@ -3643,15 +3581,6 @@ struct security_operations smack_ops = {  static __init void init_smack_known_list(void)  {  	/* -	 * Initialize CIPSO locks -	 */ -	spin_lock_init(&smack_known_huh.smk_cipsolock); -	spin_lock_init(&smack_known_hat.smk_cipsolock); -	spin_lock_init(&smack_known_star.smk_cipsolock); -	spin_lock_init(&smack_known_floor.smk_cipsolock); -	spin_lock_init(&smack_known_invalid.smk_cipsolock); -	spin_lock_init(&smack_known_web.smk_cipsolock); -	/*  	 * Initialize rule list locks  	 */  	mutex_init(&smack_known_huh.smk_rules_lock);  |