diff options
Diffstat (limited to 'security/smack/smack_lsm.c')
| -rw-r--r-- | security/smack/smack_lsm.c | 1872 | 
1 files changed, 1346 insertions, 526 deletions
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index bc39f4067af..f2c30801ce4 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3,12 +3,15 @@   *   *  This file contains the smack hook function implementations.   * - *  Author: + *  Authors:   *	Casey Schaufler <casey@schaufler-ca.com> + *	Jarkko Sakkinen <jarkko.sakkinen@intel.com>   *   *  Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>   *  Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - *                Paul Moore <paul.moore@hp.com> + *                Paul Moore <paul@paul-moore.com> + *  Copyright (C) 2010 Nokia Corporation + *  Copyright (C) 2011 Intel Corporation.   *   *	This program is free software; you can redistribute it and/or modify   *	it under the terms of the GNU General Public License version 2, @@ -24,17 +27,33 @@  #include <linux/ip.h>  #include <linux/tcp.h>  #include <linux/udp.h> +#include <linux/dccp.h>  #include <linux/slab.h>  #include <linux/mutex.h>  #include <linux/pipe_fs_i.h> -#include <net/netlabel.h>  #include <net/cipso_ipv4.h> +#include <net/ip.h> +#include <net/ipv6.h>  #include <linux/audit.h>  #include <linux/magic.h> +#include <linux/dcache.h> +#include <linux/personality.h> +#include <linux/msg.h> +#include <linux/shm.h> +#include <linux/binfmts.h>  #include "smack.h"  #define task_security(task)	(task_cred_xxx((task), security)) +#define TRANS_TRUE	"TRUE" +#define TRANS_TRUE_SIZE	4 + +#define SMK_CONNECTING	0 +#define SMK_RECEIVING	1 +#define SMK_SENDING	2 + +LIST_HEAD(smk_ipv6_port_list); +  /**   * smk_fetch - Fetch the smack label from a file.   * @ip: a pointer to the inode @@ -43,19 +62,27 @@   * Returns a pointer to the master list entry for the Smack label   * or NULL if there was no label to fetch.   */ -static char *smk_fetch(struct inode *ip, struct dentry *dp) +static struct smack_known *smk_fetch(const char *name, struct inode *ip, +					struct dentry *dp)  {  	int rc; -	char in[SMK_LABELLEN]; +	char *buffer; +	struct smack_known *skp = NULL;  	if (ip->i_op->getxattr == NULL)  		return NULL; -	rc = ip->i_op->getxattr(dp, XATTR_NAME_SMACK, 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) +		skp = smk_import_entry(buffer, rc); + +	kfree(buffer); + +	return skp;  }  /** @@ -68,7 +95,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; @@ -79,6 +106,125 @@ struct inode_smack *new_inode_smack(char *smack)  	return isp;  } +/** + * new_task_smack - allocate a task security blob + * @smack: a pointer to the Smack label to use in the blob + * + * Returns the new blob or NULL if there's no memory available + */ +static struct task_smack *new_task_smack(struct smack_known *task, +					struct smack_known *forked, gfp_t gfp) +{ +	struct task_smack *tsp; + +	tsp = kzalloc(sizeof(struct task_smack), gfp); +	if (tsp == NULL) +		return NULL; + +	tsp->smk_task = task; +	tsp->smk_forked = forked; +	INIT_LIST_HEAD(&tsp->smk_rules); +	mutex_init(&tsp->smk_rules_lock); + +	return tsp; +} + +/** + * smk_copy_rules - copy a rule set + * @nhead - new rules header pointer + * @ohead - old rules header pointer + * + * Returns 0 on success, -ENOMEM on error + */ +static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, +				gfp_t gfp) +{ +	struct smack_rule *nrp; +	struct smack_rule *orp; +	int rc = 0; + +	INIT_LIST_HEAD(nhead); + +	list_for_each_entry_rcu(orp, ohead, list) { +		nrp = kzalloc(sizeof(struct smack_rule), gfp); +		if (nrp == NULL) { +			rc = -ENOMEM; +			break; +		} +		*nrp = *orp; +		list_add_rcu(&nrp->list, nhead); +	} +	return rc; +} + +/** + * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_* + * @mode - input mode in form of PTRACE_MODE_* + * + * Returns a converted MAY_* mode usable by smack rules + */ +static inline unsigned int smk_ptrace_mode(unsigned int mode) +{ +	switch (mode) { +	case PTRACE_MODE_READ: +		return MAY_READ; +	case PTRACE_MODE_ATTACH: +		return MAY_READWRITE; +	} + +	return 0; +} + +/** + * smk_ptrace_rule_check - helper for ptrace access + * @tracer: tracer process + * @tracee_label: label of the process that's about to be traced, + *                the pointer must originate from smack structures + * @mode: ptrace attachment mode (PTRACE_MODE_*) + * @func: name of the function that called us, used for audit + * + * Returns 0 on access granted, -error on error + */ +static int smk_ptrace_rule_check(struct task_struct *tracer, char *tracee_label, +				 unsigned int mode, const char *func) +{ +	int rc; +	struct smk_audit_info ad, *saip = NULL; +	struct task_smack *tsp; +	struct smack_known *skp; + +	if ((mode & PTRACE_MODE_NOAUDIT) == 0) { +		smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK); +		smk_ad_setfield_u_tsk(&ad, tracer); +		saip = &ad; +	} + +	tsp = task_security(tracer); +	skp = smk_of_task(tsp); + +	if ((mode & PTRACE_MODE_ATTACH) && +	    (smack_ptrace_rule == SMACK_PTRACE_EXACT || +	     smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) { +		if (skp->smk_known == tracee_label) +			rc = 0; +		else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN) +			rc = -EACCES; +		else if (capable(CAP_SYS_PTRACE)) +			rc = 0; +		else +			rc = -EACCES; + +		if (saip) +			smack_log(skp->smk_known, tracee_label, 0, rc, saip); + +		return rc; +	} + +	/* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ +	rc = smk_tskacc(tsp, tracee_label, smk_ptrace_mode(mode), saip); +	return rc; +} +  /*   * LSM hooks.   * We he, that is fun! @@ -87,33 +233,24 @@ struct inode_smack *new_inode_smack(char *smack)  /**   * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH   * @ctp: child task pointer - * @mode: ptrace attachment mode + * @mode: ptrace attachment mode (PTRACE_MODE_*)   *   * Returns 0 if access is OK, an error code otherwise   * - * Do the capability checks, and require read and write. + * Do the capability checks.   */  static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)  {  	int rc; -	struct smk_audit_info ad; -	char *sp, *tsp; +	struct smack_known *skp;  	rc = cap_ptrace_access_check(ctp, mode);  	if (rc != 0)  		return rc; -	sp = current_security(); -	tsp = task_security(ctp); -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); -	smk_ad_setfield_u_tsk(&ad, ctp); +	skp = smk_of_task(task_security(ctp)); -	/* we won't log here, because rc can be overriden */ -	rc = smk_access(sp, tsp, MAY_READWRITE, NULL); -	if (rc != 0 && capable(CAP_MAC_OVERRIDE)) -		rc = 0; - -	smack_log(sp, tsp, MAY_READWRITE, rc, &ad); +	rc = smk_ptrace_rule_check(current, skp->smk_known, mode, __func__);  	return rc;  } @@ -123,29 +260,21 @@ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode)   *   * Returns 0 if access is OK, an error code otherwise   * - * Do the capability checks, and require read and write. + * Do the capability checks, and require PTRACE_MODE_ATTACH.   */  static int smack_ptrace_traceme(struct task_struct *ptp)  {  	int rc; -	struct smk_audit_info ad; -	char *sp, *tsp; +	struct smack_known *skp;  	rc = cap_ptrace_traceme(ptp);  	if (rc != 0)  		return rc; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); -	smk_ad_setfield_u_tsk(&ad, ptp); - -	sp = current_security(); -	tsp = task_security(ptp); -	/* we won't log here, because rc can be overriden */ -	rc = smk_access(tsp, sp, MAY_READWRITE, NULL); -	if (rc != 0 && has_capability(ptp, CAP_MAC_OVERRIDE)) -		rc = 0; +	skp = smk_of_task(current_security()); -	smack_log(tsp, sp, MAY_READWRITE, rc, &ad); +	rc = smk_ptrace_rule_check(ptp, skp->smk_known, +				   PTRACE_MODE_ATTACH, __func__);  	return rc;  } @@ -153,23 +282,17 @@ static int smack_ptrace_traceme(struct task_struct *ptp)   * smack_syslog - Smack approval on syslog   * @type: message type   * - * Require that the task has the floor label - *   * Returns 0 on success, error code otherwise.   */ -static int smack_syslog(int type, bool from_file) +static int smack_syslog(int typefrom_file)  { -	int rc; -	char *sp = current_security(); - -	rc = cap_syslog(type, from_file); -	if (rc != 0) -		return rc; +	int rc = 0; +	struct smack_known *skp = smk_of_current(); -	if (capable(CAP_MAC_OVERRIDE)) +	if (smack_privileged(CAP_MAC_OVERRIDE))  		return 0; -	 if (sp != smack_known_floor.smk_known) +	if (smack_syslog_label != NULL && smack_syslog_label != skp)  		rc = -EACCES;  	return rc; @@ -199,9 +322,9 @@ static int smack_sb_alloc_security(struct super_block *sb)  	sbsp->smk_default = smack_known_floor.smk_known;  	sbsp->smk_floor = smack_known_floor.smk_known;  	sbsp->smk_hat = smack_known_hat.smk_known; -	sbsp->smk_initialized = 0; -	spin_lock_init(&sbsp->smk_sblock); - +	/* +	 * smk_initialized will be zero from kzalloc. +	 */  	sb->s_security = sbsp;  	return 0; @@ -245,6 +368,8 @@ static int smack_sb_copy_data(char *orig, char *smackopts)  			dp = smackopts;  		else if (strstr(cp, SMK_FSROOT) == cp)  			dp = smackopts; +		else if (strstr(cp, SMK_FSTRANS) == cp) +			dp = smackopts;  		else  			dp = otheropts; @@ -277,17 +402,17 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)  	struct inode *inode = root->d_inode;  	struct superblock_smack *sp = sb->s_security;  	struct inode_smack *isp; +	struct smack_known *skp;  	char *op;  	char *commap;  	char *nsp; +	int transmute = 0; +	int specified = 0; -	spin_lock(&sp->smk_sblock); -	if (sp->smk_initialized != 0) { -		spin_unlock(&sp->smk_sblock); +	if (sp->smk_initialized)  		return 0; -	} +  	sp->smk_initialized = 1; -	spin_unlock(&sp->smk_sblock);  	for (op = data; op != NULL; op = commap) {  		commap = strchr(op, ','); @@ -297,36 +422,71 @@ 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);  			nsp = smk_import(op, 0); -			if (nsp != NULL) +			if (nsp != NULL) {  				sp->smk_hat = nsp; +				specified = 1; +			}  		} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {  			op += strlen(SMK_FSFLOOR);  			nsp = smk_import(op, 0); -			if (nsp != NULL) +			if (nsp != NULL) {  				sp->smk_floor = nsp; +				specified = 1; +			}  		} else if (strncmp(op, SMK_FSDEFAULT,  				   strlen(SMK_FSDEFAULT)) == 0) {  			op += strlen(SMK_FSDEFAULT);  			nsp = smk_import(op, 0); -			if (nsp != NULL) +			if (nsp != NULL) {  				sp->smk_default = nsp; +				specified = 1; +			}  		} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {  			op += strlen(SMK_FSROOT);  			nsp = smk_import(op, 0); -			if (nsp != NULL) +			if (nsp != NULL) {  				sp->smk_root = nsp; +				specified = 1; +			} +		} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { +			op += strlen(SMK_FSTRANS); +			nsp = smk_import(op, 0); +			if (nsp != NULL) { +				sp->smk_root = nsp; +				transmute = 1; +				specified = 1; +			}  		}  	} +	if (!smack_privileged(CAP_MAC_ADMIN)) { +		/* +		 * Unprivileged mounts don't get to specify Smack values. +		 */ +		if (specified) +			return -EPERM; +		/* +		 * Unprivileged mounts get root and default from the caller. +		 */ +		skp = smk_of_current(); +		sp->smk_root = skp->smk_known; +		sp->smk_default = skp->smk_known; +	}  	/*  	 * Initialize the root inode.  	 */  	isp = inode->i_security; -	if (isp == NULL) -		inode->i_security = new_inode_smack(sp->smk_root); -	else +	if (isp == NULL) { +		isp = new_inode_smack(sp->smk_root); +		if (isp == NULL) +			return -ENOMEM; +		inode->i_security = isp; +	} else  		isp->smk_inode = sp->smk_root; +	if (transmute) +		isp->smk_flags |= SMK_INODE_TRANSMUTE; +  	return 0;  } @@ -343,55 +503,94 @@ static int smack_sb_statfs(struct dentry *dentry)  	int rc;  	struct smk_audit_info ad; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);  	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);  	rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad);  	return rc;  } +/* + * BPRM hooks + */ +  /** - * smack_sb_mount - Smack check for mounting - * @dev_name: unused - * @path: mount point - * @type: unused - * @flags: unused - * @data: unused + * smack_bprm_set_creds - set creds for exec + * @bprm: the exec information   * - * Returns 0 if current can write the floor of the filesystem - * being mounted on, an error code otherwise. + * Returns 0 if it gets a blob, -EPERM if exec forbidden and -ENOMEM otherwise   */ -static int smack_sb_mount(char *dev_name, struct path *path, -			  char *type, unsigned long flags, void *data) +static int smack_bprm_set_creds(struct linux_binprm *bprm)  { -	struct superblock_smack *sbp = path->mnt->mnt_sb->s_security; -	struct smk_audit_info ad; +	struct inode *inode = file_inode(bprm->file); +	struct task_smack *bsp = bprm->cred->security; +	struct inode_smack *isp; +	int rc; + +	rc = cap_bprm_set_creds(bprm); +	if (rc != 0) +		return rc; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); -	smk_ad_setfield_u_fs_path(&ad, *path); +	if (bprm->cred_prepared) +		return 0; -	return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); +	isp = inode->i_security; +	if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) +		return 0; + +	if (bprm->unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { +		struct task_struct *tracer; +		rc = 0; + +		rcu_read_lock(); +		tracer = ptrace_parent(current); +		if (likely(tracer != NULL)) +			rc = smk_ptrace_rule_check(tracer, +						   isp->smk_task->smk_known, +						   PTRACE_MODE_ATTACH, +						   __func__); +		rcu_read_unlock(); + +		if (rc != 0) +			return rc; +	} else if (bprm->unsafe) +		return -EPERM; + +	bsp->smk_task = isp->smk_task; +	bprm->per_clear |= PER_CLEAR_ON_SETID; + +	return 0;  }  /** - * smack_sb_umount - Smack check for unmounting - * @mnt: file system to unmount - * @flags: unused + * smack_bprm_committing_creds - Prepare to install the new credentials + * from bprm.   * - * Returns 0 if current can write the floor of the filesystem - * being unmounted, an error code otherwise. + * @bprm: binprm for exec   */ -static int smack_sb_umount(struct vfsmount *mnt, int flags) +static void smack_bprm_committing_creds(struct linux_binprm *bprm)  { -	struct superblock_smack *sbp; -	struct smk_audit_info ad; +	struct task_smack *bsp = bprm->cred->security; + +	if (bsp->smk_task != bsp->smk_forked) +		current->pdeath_signal = 0; +} -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); -	smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root); -	smk_ad_setfield_u_fs_path_mnt(&ad, mnt); +/** + * smack_bprm_secureexec - Return the decision to use secureexec. + * @bprm: binprm for exec + * + * Returns 0 on success. + */ +static int smack_bprm_secureexec(struct linux_binprm *bprm) +{ +	struct task_smack *tsp = current_security(); +	int ret = cap_bprm_secureexec(bprm); -	sbp = mnt->mnt_sb->s_security; -	return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad); +	if (!ret && (tsp->smk_task != tsp->smk_forked)) +		ret = 1; + +	return ret;  }  /* @@ -406,7 +605,9 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)   */  static int smack_inode_alloc_security(struct inode *inode)  { -	inode->i_security = new_inode_smack(current_security()); +	struct smack_known *skp = smk_of_current(); + +	inode->i_security = new_inode_smack(skp->smk_known);  	if (inode->i_security == NULL)  		return -ENOMEM;  	return 0; @@ -428,6 +629,7 @@ static void smack_inode_free_security(struct inode *inode)   * smack_inode_init_security - copy out the smack from an inode   * @inode: the inode   * @dir: unused + * @qstr: unused   * @name: where to put the attribute name   * @value: where to put the attribute value   * @len: where to put the length of the attribute @@ -435,18 +637,36 @@ static void smack_inode_free_security(struct inode *inode)   * Returns 0 if it all works out, -ENOMEM if there's no memory   */  static int smack_inode_init_security(struct inode *inode, struct inode *dir, -				     char **name, void **value, size_t *len) +				     const struct qstr *qstr, const char **name, +				     void **value, size_t *len)  { +	struct inode_smack *issp = inode->i_security; +	struct smack_known *skp = 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); -		if (*name == NULL) -			return -ENOMEM; -	} +	if (name) +		*name = XATTR_SMACK_SUFFIX;  	if (value) { -		*value = kstrdup(isp, GFP_KERNEL); +		rcu_read_lock(); +		may = smk_access_entry(skp->smk_known, dsp, &skp->smk_rules); +		rcu_read_unlock(); + +		/* +		 * 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)) { +			isp = dsp; +			issp->smk_flags |= SMK_INODE_CHANGED; +		} + +		*value = kstrdup(isp, GFP_NOFS);  		if (*value == NULL)  			return -ENOMEM;  	} @@ -472,7 +692,7 @@ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir,  	struct smk_audit_info ad;  	int rc; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	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); @@ -501,7 +721,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)  	struct smk_audit_info ad;  	int rc; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);  	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);  	/* @@ -512,7 +732,7 @@ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry)  		/*  		 * You also need write access to the containing directory  		 */ -		smk_ad_setfield_u_fs_path_dentry(&ad, NULL); +		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);  		smk_ad_setfield_u_fs_inode(&ad, dir);  		rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);  	} @@ -532,7 +752,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)  	struct smk_audit_info ad;  	int rc; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);  	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);  	/* @@ -543,7 +763,7 @@ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry)  		/*  		 * You also need write access to the containing directory  		 */ -		smk_ad_setfield_u_fs_path_dentry(&ad, NULL); +		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);  		smk_ad_setfield_u_fs_inode(&ad, dir);  		rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad);  	} @@ -572,7 +792,7 @@ static int smack_inode_rename(struct inode *old_inode,  	char *isp;  	struct smk_audit_info ad; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	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); @@ -598,6 +818,7 @@ static int smack_inode_rename(struct inode *old_inode,  static int smack_inode_permission(struct inode *inode, int mask)  {  	struct smk_audit_info ad; +	int no_block = mask & MAY_NOT_BLOCK;  	mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);  	/* @@ -605,7 +826,11 @@ static int smack_inode_permission(struct inode *inode, int mask)  	 */  	if (mask == 0)  		return 0; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); + +	/* May be droppable after audit */ +	if (no_block) +		return -ECHILD; +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE);  	smk_ad_setfield_u_fs_inode(&ad, inode);  	return smk_curacc(smk_of_inode(inode), mask, &ad);  } @@ -625,7 +850,7 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)  	 */  	if (iattr->ia_valid & ATTR_FORCE)  		return 0; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);  	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);  	return smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); @@ -641,10 +866,13 @@ static int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr)  static int smack_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)  {  	struct smk_audit_info ad; +	struct path path; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); -	smk_ad_setfield_u_fs_path_dentry(&ad, dentry); -	smk_ad_setfield_u_fs_path_mnt(&ad, mnt); +	path.dentry = dentry; +	path.mnt = mnt; + +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); +	smk_ad_setfield_u_fs_path(&ad, path);  	return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);  } @@ -664,24 +892,44 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,  				const void *value, size_t size, int flags)  {  	struct smk_audit_info ad; +	struct smack_known *skp; +	int check_priv = 0; +	int check_import = 0; +	int check_star = 0;  	int rc = 0; +	/* +	 * Check label validity here so import won't fail in post_setxattr +	 */  	if (strcmp(name, XATTR_NAME_SMACK) == 0 ||  	    strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||  	    strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { -		if (!capable(CAP_MAC_ADMIN)) -			rc = -EPERM; -		/* -		 * check label validity here so import wont fail on -		 * post_setxattr -		 */ -		if (size == 0 || size >= SMK_LABELLEN || -		    smk_import(value, size) == NULL) +		check_priv = 1; +		check_import = 1; +	} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || +		   strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { +		check_priv = 1; +		check_import = 1; +		check_star = 1; +	} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { +		check_priv = 1; +		if (size != TRANS_TRUE_SIZE || +		    strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)  			rc = -EINVAL;  	} else  		rc = cap_inode_setxattr(dentry, name, value, size, flags); -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	if (check_priv && !smack_privileged(CAP_MAC_ADMIN)) +		rc = -EPERM; + +	if (rc == 0 && check_import) { +		skp = smk_import_entry(value, size); +		if (skp == NULL || (check_star && +		    (skp == &smack_known_star || skp == &smack_known_web))) +			rc = -EINVAL; +	} + +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);  	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);  	if (rc == 0) @@ -704,31 +952,38 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,  static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,  				      const void *value, size_t size, int flags)  { -	struct inode_smack *isp; -	char *nsp; +	struct smack_known *skp; +	struct inode_smack *isp = dentry->d_inode->i_security; -	/* -	 * Not SMACK -	 */ -	if (strcmp(name, XATTR_NAME_SMACK)) +	if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { +		isp->smk_flags |= SMK_INODE_TRANSMUTE;  		return; +	} -	isp = dentry->d_inode->i_security; - -	/* -	 * No locking is done here. This is a pointer -	 * assignment. -	 */ -	nsp = smk_import(value, size); -	if (nsp != NULL) -		isp->smk_inode = nsp; -	else -		isp->smk_inode = smack_known_invalid.smk_known; +	if (strcmp(name, XATTR_NAME_SMACK) == 0) { +		skp = smk_import_entry(value, size); +		if (skp != NULL) +			isp->smk_inode = skp->smk_known; +		else +			isp->smk_inode = smack_known_invalid.smk_known; +	} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { +		skp = smk_import_entry(value, size); +		if (skp != NULL) +			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) +			isp->smk_mmap = skp; +		else +			isp->smk_mmap = &smack_known_invalid; +	}  	return;  } -/* +/**   * smack_inode_getxattr - Smack check on getxattr   * @dentry: the object   * @name: unused @@ -739,13 +994,13 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)  {  	struct smk_audit_info ad; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);  	smk_ad_setfield_u_fs_path_dentry(&ad, dentry);  	return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ, &ad);  } -/* +/**   * smack_inode_removexattr - Smack check on removexattr   * @dentry: the object   * @name: name of the attribute @@ -756,23 +1011,46 @@ static int smack_inode_getxattr(struct dentry *dentry, const char *name)   */  static int smack_inode_removexattr(struct dentry *dentry, const char *name)  { +	struct inode_smack *isp;  	struct smk_audit_info ad;  	int rc = 0;  	if (strcmp(name, XATTR_NAME_SMACK) == 0 ||  	    strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || -	    strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { -		if (!capable(CAP_MAC_ADMIN)) +	    strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || +	    strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || +	    strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || +	    strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { +		if (!smack_privileged(CAP_MAC_ADMIN))  			rc = -EPERM;  	} else  		rc = cap_inode_removexattr(dentry, name); -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	if (rc != 0) +		return rc; + +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);  	smk_ad_setfield_u_fs_path_dentry(&ad, dentry); -	if (rc == 0) -		rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); -	return rc; +	rc = smk_curacc(smk_of_inode(dentry->d_inode), MAY_WRITE, &ad); +	if (rc != 0) +		return rc; + +	isp = dentry->d_inode->i_security; +	/* +	 * Don't do anything special for these. +	 *	XATTR_NAME_SMACKIPIN +	 *	XATTR_NAME_SMACKIPOUT +	 *	XATTR_NAME_SMACKEXEC +	 */ +	if (strcmp(name, XATTR_NAME_SMACK) == 0) +		isp->smk_task = NULL; +	else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) +		isp->smk_mmap = NULL; +	else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) +		isp->smk_flags &= ~SMK_INODE_TRANSMUTE; + +	return 0;  }  /** @@ -817,9 +1095,9 @@ static int smack_inode_getsecurity(const struct inode *inode,  	ssp = sock->sk->sk_security;  	if (strcmp(name, XATTR_SMACK_IPIN) == 0) -		isp = ssp->smk_in; +		isp = ssp->smk_in->smk_known;  	else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) -		isp = ssp->smk_out; +		isp = ssp->smk_out->smk_known;  	else  		return -EOPNOTSUPP; @@ -899,7 +1177,9 @@ static int smack_file_permission(struct file *file, int mask)   */  static int smack_file_alloc_security(struct file *file)  { -	file->f_security = current_security(); +	struct smack_known *skp = smk_of_current(); + +	file->f_security = skp->smk_known;  	return 0;  } @@ -931,7 +1211,7 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,  	int rc = 0;  	struct smk_audit_info ad; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);  	smk_ad_setfield_u_fs_path(&ad, file->f_path);  	if (_IOC_DIR(cmd) & _IOC_WRITE) @@ -948,15 +1228,15 @@ static int smack_file_ioctl(struct file *file, unsigned int cmd,   * @file: the object   * @cmd: unused   * - * Returns 0 if current has write access, error code otherwise + * Returns 0 if current has lock access, error code otherwise   */  static int smack_file_lock(struct file *file, unsigned int cmd)  {  	struct smk_audit_info ad; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); -	smk_ad_setfield_u_fs_path_dentry(&ad, file->f_path.dentry); -	return smk_curacc(file->f_security, MAY_WRITE, &ad); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); +	smk_ad_setfield_u_fs_path(&ad, file->f_path); +	return smk_curacc(file->f_security, MAY_LOCK, &ad);  }  /** @@ -965,38 +1245,141 @@ static int smack_file_lock(struct file *file, unsigned int cmd)   * @cmd: what action to check   * @arg: unused   * + * Generally these operations are harmless. + * File locking operations present an obvious mechanism + * for passing information, so they require write access. + *   * Returns 0 if current has access, error code otherwise   */  static int smack_file_fcntl(struct file *file, unsigned int cmd,  			    unsigned long arg)  {  	struct smk_audit_info ad; -	int rc; +	int rc = 0; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); -	smk_ad_setfield_u_fs_path(&ad, file->f_path);  	switch (cmd) { -	case F_DUPFD: -	case F_GETFD: -	case F_GETFL:  	case F_GETLK: -	case F_GETOWN: -	case F_GETSIG: -		rc = smk_curacc(file->f_security, MAY_READ, &ad);  		break; -	case F_SETFD: -	case F_SETFL:  	case F_SETLK:  	case F_SETLKW: +		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); +		smk_ad_setfield_u_fs_path(&ad, file->f_path); +		rc = smk_curacc(file->f_security, MAY_LOCK, &ad); +		break;  	case F_SETOWN:  	case F_SETSIG: +		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); +		smk_ad_setfield_u_fs_path(&ad, file->f_path);  		rc = smk_curacc(file->f_security, MAY_WRITE, &ad);  		break;  	default: -		rc = smk_curacc(file->f_security, MAY_READWRITE, &ad); +		break; +	} + +	return rc; +} + +/** + * smack_mmap_file : + * Check permissions for a mmap operation.  The @file may be NULL, e.g. + * if mapping anonymous memory. + * @file contains the file structure for file to map (may be NULL). + * @reqprot contains the protection requested by the application. + * @prot contains the protection that will be applied by the kernel. + * @flags contains the operational flags. + * Return 0 if permission is granted. + */ +static int smack_mmap_file(struct file *file, +			   unsigned long reqprot, unsigned long prot, +			   unsigned long flags) +{ +	struct smack_known *skp; +	struct smack_known *mkp; +	struct smack_rule *srp; +	struct task_smack *tsp; +	char *osmack; +	struct inode_smack *isp; +	int may; +	int mmay; +	int tmay; +	int rc; + +	if (file == NULL) +		return 0; + +	isp = file_inode(file)->i_security; +	if (isp->smk_mmap == NULL) +		return 0; +	mkp = isp->smk_mmap; + +	tsp = current_security(); +	skp = smk_of_current(); +	rc = 0; + +	rcu_read_lock(); +	/* +	 * For each Smack rule associated with the subject +	 * label verify that the SMACK64MMAP also has access +	 * to that rule's object label. +	 */ +	list_for_each_entry_rcu(srp, &skp->smk_rules, list) { +		osmack = srp->smk_object; +		/* +		 * Matching labels always allows access. +		 */ +		if (mkp->smk_known == osmack) +			continue; +		/* +		 * If there is a matching local rule take +		 * that into account as well. +		 */ +		may = smk_access_entry(srp->smk_subject->smk_known, osmack, +					&tsp->smk_rules); +		if (may == -ENOENT) +			may = srp->smk_access; +		else +			may &= srp->smk_access; +		/* +		 * If may is zero the SMACK64MMAP subject can't +		 * possibly have less access. +		 */ +		if (may == 0) +			continue; + +		/* +		 * Fetch the global list entry. +		 * If there isn't one a SMACK64MMAP subject +		 * can't have as much access as current. +		 */ +		mmay = smk_access_entry(mkp->smk_known, osmack, +						&mkp->smk_rules); +		if (mmay == -ENOENT) { +			rc = -EACCES; +			break; +		} +		/* +		 * If there is a local entry it modifies the +		 * potential access, too. +		 */ +		tmay = smk_access_entry(mkp->smk_known, osmack, +						&tsp->smk_rules); +		if (tmay != -ENOENT) +			mmay &= tmay; + +		/* +		 * If there is any access available to current that is +		 * not available to a SMACK64MMAP subject +		 * deny access. +		 */ +		if ((may | mmay) != mmay) { +			rc = -EACCES; +			break; +		}  	} +	rcu_read_unlock(); +  	return rc;  } @@ -1009,7 +1392,9 @@ static int smack_file_fcntl(struct file *file, unsigned int cmd,   */  static int smack_file_set_fowner(struct file *file)  { -	file->f_security = current_security(); +	struct smack_known *skp = smk_of_current(); + +	file->f_security = skp->smk_known;  	return 0;  } @@ -1027,23 +1412,26 @@ static int smack_file_set_fowner(struct file *file)  static int smack_file_send_sigiotask(struct task_struct *tsk,  				     struct fown_struct *fown, int signum)  { +	struct smack_known *skp; +	struct smack_known *tkp = smk_of_task(tsk->cred->security);  	struct file *file;  	int rc; -	char *tsp = tsk->cred->security;  	struct smk_audit_info ad;  	/*  	 * struct fown_struct is never outside the context of a struct file  	 */  	file = container_of(fown, struct file, f_owner); +  	/* we don't log here as rc can be overriden */ -	rc = smk_access(file->f_security, tsp, MAY_WRITE, NULL); +	skp = smk_find_entry(file->f_security); +	rc = smk_access(skp, tkp->smk_known, MAY_WRITE, NULL);  	if (rc != 0 && has_capability(tsk, CAP_MAC_OVERRIDE))  		rc = 0;  	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);  	smk_ad_setfield_u_tsk(&ad, tsk); -	smack_log(file->f_security, tsp, MAY_WRITE, rc, &ad); +	smack_log(file->f_security, tkp->smk_known, MAY_WRITE, rc, &ad);  	return rc;  } @@ -1058,7 +1446,7 @@ static int smack_file_receive(struct file *file)  	int may = 0;  	struct smk_audit_info ad; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);  	smk_ad_setfield_u_fs_path(&ad, file->f_path);  	/*  	 * This code relies on bitmasks. @@ -1071,6 +1459,37 @@ static int smack_file_receive(struct file *file)  	return smk_curacc(file->f_security, may, &ad);  } +/** + * smack_file_open - Smack dentry open processing + * @file: the object + * @cred: task credential + * + * Set the security blob in the file structure. + * Allow the open only if the task has read access. There are + * many read operations (e.g. fstat) that you can do with an + * fd even if you have the file open write-only. + * + * Returns 0 + */ +static int smack_file_open(struct file *file, const struct cred *cred) +{ +	struct task_smack *tsp = cred->security; +	struct inode_smack *isp = file_inode(file)->i_security; +	struct smk_audit_info ad; +	int rc; + +	if (smack_privileged(CAP_MAC_OVERRIDE)) +		return 0; + +	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); +	smk_ad_setfield_u_fs_path(&ad, file->f_path); +	rc = smk_access(tsp->smk_task, isp->smk_inode, MAY_READ, &ad); +	if (rc == 0) +		file->f_security = isp->smk_inode; + +	return rc; +} +  /*   * Task hooks   */ @@ -1086,7 +1505,14 @@ static int smack_file_receive(struct file *file)   */  static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)  { -	cred->security = NULL; +	struct task_smack *tsp; + +	tsp = new_task_smack(NULL, NULL, gfp); +	if (tsp == NULL) +		return -ENOMEM; + +	cred->security = tsp; +  	return 0;  } @@ -1095,13 +1521,24 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)   * smack_cred_free - "free" task-level security credentials   * @cred: the credentials in question   * - * Smack isn't using copies of blobs. Everyone - * points to an immutable list. The blobs never go away. - * There is no leak here.   */  static void smack_cred_free(struct cred *cred)  { +	struct task_smack *tsp = cred->security; +	struct smack_rule *rp; +	struct list_head *l; +	struct list_head *n; + +	if (tsp == NULL) +		return;  	cred->security = NULL; + +	list_for_each_safe(l, n, &tsp->smk_rules) { +		rp = list_entry(l, struct smack_rule, list); +		list_del(&rp->list); +		kfree(rp); +	} +	kfree(tsp);  }  /** @@ -1115,7 +1552,19 @@ static void smack_cred_free(struct cred *cred)  static int smack_cred_prepare(struct cred *new, const struct cred *old,  			      gfp_t gfp)  { -	new->security = old->security; +	struct task_smack *old_tsp = old->security; +	struct task_smack *new_tsp; +	int rc; + +	new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp); +	if (new_tsp == NULL) +		return -ENOMEM; + +	rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp); +	if (rc != 0) +		return rc; + +	new->security = new_tsp;  	return 0;  } @@ -1128,7 +1577,16 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,   */  static void smack_cred_transfer(struct cred *new, const struct cred *old)  { -	new->security = old->security; +	struct task_smack *old_tsp = old->security; +	struct task_smack *new_tsp = new->security; + +	new_tsp->smk_task = old_tsp->smk_task; +	new_tsp->smk_forked = old_tsp->smk_task; +	mutex_init(&new_tsp->smk_rules_lock); +	INIT_LIST_HEAD(&new_tsp->smk_rules); + + +	/* cbs copy rule list */  }  /** @@ -1140,12 +1598,13 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)   */  static int smack_kernel_act_as(struct cred *new, u32 secid)  { -	char *smack = smack_from_secid(secid); +	struct task_smack *new_tsp = new->security; +	struct smack_known *skp = smack_from_secid(secid); -	if (smack == NULL) +	if (skp == NULL)  		return -EINVAL; -	new->security = smack; +	new_tsp->smk_task = skp;  	return 0;  } @@ -1161,25 +1620,30 @@ static int smack_kernel_create_files_as(struct cred *new,  					struct inode *inode)  {  	struct inode_smack *isp = inode->i_security; +	struct task_smack *tsp = new->security; -	new->security = isp->smk_inode; +	tsp->smk_forked = smk_find_entry(isp->smk_inode); +	tsp->smk_task = tsp->smk_forked;  	return 0;  }  /**   * smk_curacc_on_task - helper to log task related access   * @p: the task object - * @access : the access requested + * @access: the access requested + * @caller: name of the calling function for audit   *   * Return 0 if access is permitted   */ -static int smk_curacc_on_task(struct task_struct *p, int access) +static int smk_curacc_on_task(struct task_struct *p, int access, +				const char *caller)  {  	struct smk_audit_info ad; +	struct smack_known *skp = smk_of_task(task_security(p)); -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); +	smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK);  	smk_ad_setfield_u_tsk(&ad, p); -	return smk_curacc(task_security(p), access, &ad); +	return smk_curacc(skp->smk_known, access, &ad);  }  /** @@ -1191,7 +1655,7 @@ static int smk_curacc_on_task(struct task_struct *p, int access)   */  static int smack_task_setpgid(struct task_struct *p, pid_t pgid)  { -	return smk_curacc_on_task(p, MAY_WRITE); +	return smk_curacc_on_task(p, MAY_WRITE, __func__);  }  /** @@ -1202,7 +1666,7 @@ static int smack_task_setpgid(struct task_struct *p, pid_t pgid)   */  static int smack_task_getpgid(struct task_struct *p)  { -	return smk_curacc_on_task(p, MAY_READ); +	return smk_curacc_on_task(p, MAY_READ, __func__);  }  /** @@ -1213,7 +1677,7 @@ static int smack_task_getpgid(struct task_struct *p)   */  static int smack_task_getsid(struct task_struct *p)  { -	return smk_curacc_on_task(p, MAY_READ); +	return smk_curacc_on_task(p, MAY_READ, __func__);  }  /** @@ -1225,7 +1689,9 @@ static int smack_task_getsid(struct task_struct *p)   */  static void smack_task_getsecid(struct task_struct *p, u32 *secid)  { -	*secid = smack_to_secid(task_security(p)); +	struct smack_known *skp = smk_of_task(task_security(p)); + +	*secid = skp->smk_secid;  }  /** @@ -1241,7 +1707,7 @@ static int smack_task_setnice(struct task_struct *p, int nice)  	rc = cap_task_setnice(p, nice);  	if (rc == 0) -		rc = smk_curacc_on_task(p, MAY_WRITE); +		rc = smk_curacc_on_task(p, MAY_WRITE, __func__);  	return rc;  } @@ -1258,7 +1724,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)  	rc = cap_task_setioprio(p, ioprio);  	if (rc == 0) -		rc = smk_curacc_on_task(p, MAY_WRITE); +		rc = smk_curacc_on_task(p, MAY_WRITE, __func__);  	return rc;  } @@ -1270,7 +1736,7 @@ static int smack_task_setioprio(struct task_struct *p, int ioprio)   */  static int smack_task_getioprio(struct task_struct *p)  { -	return smk_curacc_on_task(p, MAY_READ); +	return smk_curacc_on_task(p, MAY_READ, __func__);  }  /** @@ -1287,7 +1753,7 @@ static int smack_task_setscheduler(struct task_struct *p)  	rc = cap_task_setscheduler(p);  	if (rc == 0) -		rc = smk_curacc_on_task(p, MAY_WRITE); +		rc = smk_curacc_on_task(p, MAY_WRITE, __func__);  	return rc;  } @@ -1299,7 +1765,7 @@ static int smack_task_setscheduler(struct task_struct *p)   */  static int smack_task_getscheduler(struct task_struct *p)  { -	return smk_curacc_on_task(p, MAY_READ); +	return smk_curacc_on_task(p, MAY_READ, __func__);  }  /** @@ -1310,7 +1776,7 @@ static int smack_task_getscheduler(struct task_struct *p)   */  static int smack_task_movememory(struct task_struct *p)  { -	return smk_curacc_on_task(p, MAY_WRITE); +	return smk_curacc_on_task(p, MAY_WRITE, __func__);  }  /** @@ -1329,6 +1795,8 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,  			   int sig, u32 secid)  {  	struct smk_audit_info ad; +	struct smack_known *skp; +	struct smack_known *tkp = smk_of_task(task_security(p));  	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);  	smk_ad_setfield_u_tsk(&ad, p); @@ -1337,53 +1805,33 @@ static int smack_task_kill(struct task_struct *p, struct siginfo *info,  	 * can write the receiver.  	 */  	if (secid == 0) -		return smk_curacc(task_security(p), MAY_WRITE, &ad); +		return smk_curacc(tkp->smk_known, MAY_WRITE, &ad);  	/*  	 * If the secid isn't 0 we're dealing with some USB IO  	 * specific behavior. This is not clean. For one thing  	 * we can't take privilege into account.  	 */ -	return smk_access(smack_from_secid(secid), task_security(p), -			  MAY_WRITE, &ad); +	skp = smack_from_secid(secid); +	return smk_access(skp, tkp->smk_known, MAY_WRITE, &ad);  }  /**   * smack_task_wait - Smack access check for waiting   * @p: task to wait for   * - * Returns 0 if current can wait for p, error code otherwise + * Returns 0   */  static int smack_task_wait(struct task_struct *p)  { -	struct smk_audit_info ad; -	char *sp = current_security(); -	char *tsp = task_security(p); -	int rc; - -	/* we don't log here, we can be overriden */ -	rc = smk_access(sp, tsp, MAY_WRITE, NULL); -	if (rc == 0) -		goto out_log; -  	/* -	 * Allow the operation to succeed if either task -	 * has privilege to perform operations that might -	 * account for the smack labels having gotten to -	 * be different in the first place. -	 * -	 * This breaks the strict subject/object access -	 * control ideal, taking the object's privilege -	 * state into account in the decision as well as -	 * the smack value. +	 * Allow the operation to succeed. +	 * Zombies are bad. +	 * In userless environments (e.g. phones) programs +	 * get marked with SMACK64EXEC and even if the parent +	 * and child shouldn't be talking the parent still +	 * may expect to know when the child exits.  	 */ -	if (capable(CAP_MAC_OVERRIDE) || has_capability(p, CAP_MAC_OVERRIDE)) -		rc = 0; -	/* we log only if we didn't get overriden */ - out_log: -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); -	smk_ad_setfield_u_tsk(&ad, p); -	smack_log(sp, tsp, MAY_WRITE, rc, &ad); -	return rc; +	return 0;  }  /** @@ -1396,7 +1844,9 @@ static int smack_task_wait(struct task_struct *p)  static void smack_task_to_inode(struct task_struct *p, struct inode *inode)  {  	struct inode_smack *isp = inode->i_security; -	isp->smk_inode = task_security(p); +	struct smack_known *skp = smk_of_task(task_security(p)); + +	isp->smk_inode = skp->smk_known;  }  /* @@ -1415,16 +1865,16 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)   */  static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)  { -	char *csp = current_security(); +	struct smack_known *skp = smk_of_current();  	struct socket_smack *ssp;  	ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);  	if (ssp == NULL)  		return -ENOMEM; -	ssp->smk_in = csp; -	ssp->smk_out = csp; -	ssp->smk_packet[0] = '\0'; +	ssp->smk_in = skp; +	ssp->smk_out = skp; +	ssp->smk_packet = NULL;  	sk->sk_security = ssp; @@ -1480,65 +1930,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. - * Appologies 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 @@ -1550,8 +1941,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;  	/* @@ -1569,10 +1960,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 = ssp->smk_out; +		rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel);  	}  	bh_unlock_sock(sk); @@ -1594,6 +1983,7 @@ static int smack_netlabel(struct sock *sk, int labeled)   */  static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)  { +	struct smack_known *skp;  	int rc;  	int sk_lbl;  	char *hostsp; @@ -1603,14 +1993,17 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)  	rcu_read_lock();  	hostsp = smack_host_label(sap);  	if (hostsp != NULL) { -		sk_lbl = SMACK_UNLABELED_SOCKET;  #ifdef CONFIG_AUDIT -		smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); -		ad.a.u.net.family = sap->sin_family; -		ad.a.u.net.dport = sap->sin_port; -		ad.a.u.net.v4info.daddr = sap->sin_addr.s_addr; +		struct lsm_network_audit net; + +		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); +		ad.a.u.net->family = sap->sin_family; +		ad.a.u.net->dport = sap->sin_port; +		ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr;  #endif -		rc = smk_access(ssp->smk_out, hostsp, MAY_WRITE, &ad); +		sk_lbl = SMACK_UNLABELED_SOCKET; +		skp = ssp->smk_out; +		rc = smk_access(skp, hostsp, MAY_WRITE, &ad);  	} else {  		sk_lbl = SMACK_CIPSO_SOCKET;  		rc = 0; @@ -1623,6 +2016,153 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)  }  /** + * smk_ipv6_port_label - Smack port access table management + * @sock: socket + * @address: address + * + * Create or update the port list entry + */ +static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) +{ +	struct sock *sk = sock->sk; +	struct sockaddr_in6 *addr6; +	struct socket_smack *ssp = sock->sk->sk_security; +	struct smk_port_label *spp; +	unsigned short port = 0; + +	if (address == NULL) { +		/* +		 * This operation is changing the Smack information +		 * on the bound socket. Take the changes to the port +		 * as well. +		 */ +		list_for_each_entry(spp, &smk_ipv6_port_list, list) { +			if (sk != spp->smk_sock) +				continue; +			spp->smk_in = ssp->smk_in; +			spp->smk_out = ssp->smk_out; +			return; +		} +		/* +		 * A NULL address is only used for updating existing +		 * bound entries. If there isn't one, it's OK. +		 */ +		return; +	} + +	addr6 = (struct sockaddr_in6 *)address; +	port = ntohs(addr6->sin6_port); +	/* +	 * This is a special case that is safely ignored. +	 */ +	if (port == 0) +		return; + +	/* +	 * Look for an existing port list entry. +	 * This is an indication that a port is getting reused. +	 */ +	list_for_each_entry(spp, &smk_ipv6_port_list, list) { +		if (spp->smk_port != port) +			continue; +		spp->smk_port = port; +		spp->smk_sock = sk; +		spp->smk_in = ssp->smk_in; +		spp->smk_out = ssp->smk_out; +		return; +	} + +	/* +	 * A new port entry is required. +	 */ +	spp = kzalloc(sizeof(*spp), GFP_KERNEL); +	if (spp == NULL) +		return; + +	spp->smk_port = port; +	spp->smk_sock = sk; +	spp->smk_in = ssp->smk_in; +	spp->smk_out = ssp->smk_out; + +	list_add(&spp->list, &smk_ipv6_port_list); +	return; +} + +/** + * smk_ipv6_port_check - check Smack port access + * @sock: socket + * @address: address + * + * Create or update the port list entry + */ +static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, +				int act) +{ +	__be16 *bep; +	__be32 *be32p; +	struct smk_port_label *spp; +	struct socket_smack *ssp = sk->sk_security; +	struct smack_known *skp; +	unsigned short port = 0; +	char *object; +	struct smk_audit_info ad; +#ifdef CONFIG_AUDIT +	struct lsm_network_audit net; +#endif + +	if (act == SMK_RECEIVING) { +		skp = smack_net_ambient; +		object = ssp->smk_in->smk_known; +	} else { +		skp = ssp->smk_out; +		object = smack_net_ambient->smk_known; +	} + +	/* +	 * Get the IP address and port from the address. +	 */ +	port = ntohs(address->sin6_port); +	bep = (__be16 *)(&address->sin6_addr); +	be32p = (__be32 *)(&address->sin6_addr); + +	/* +	 * It's remote, so port lookup does no good. +	 */ +	if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1) +		goto auditout; + +	/* +	 * It's local so the send check has to have passed. +	 */ +	if (act == SMK_RECEIVING) { +		skp = &smack_known_web; +		goto auditout; +	} + +	list_for_each_entry(spp, &smk_ipv6_port_list, list) { +		if (spp->smk_port != port) +			continue; +		object = spp->smk_in->smk_known; +		if (act == SMK_CONNECTING) +			ssp->smk_packet = spp->smk_out; +		break; +	} + +auditout: + +#ifdef CONFIG_AUDIT +	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); +	ad.a.u.net->family = sk->sk_family; +	ad.a.u.net->dport = port; +	if (act == SMK_RECEIVING) +		ad.a.u.net->v6info.saddr = address->sin6_addr; +	else +		ad.a.u.net->v6info.daddr = address->sin6_addr; +#endif +	return smk_access(skp, object, MAY_WRITE, &ad); +} + +/**   * smack_inode_setsecurity - set smack xattrs   * @inode: the object   * @name: attribute name @@ -1637,21 +2177,21 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)  static int smack_inode_setsecurity(struct inode *inode, const char *name,  				   const void *value, size_t size, int flags)  { -	char *sp; +	struct smack_known *skp;  	struct inode_smack *nsp = inode->i_security;  	struct socket_smack *ssp;  	struct socket *sock;  	int rc = 0; -	if (value == NULL || size > SMK_LABELLEN || size == 0) -		return -EACCES; +	if (value == NULL || size > SMK_LONGLABEL || size == 0) +		return -EINVAL; -	sp = smk_import(value, size); -	if (sp == NULL) +	skp = smk_import_entry(value, size); +	if (skp == NULL)  		return -EINVAL;  	if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { -		nsp->smk_inode = sp; +		nsp->smk_inode = skp->smk_known;  		nsp->smk_flags |= SMK_INODE_INSTANT;  		return 0;  	} @@ -1668,16 +2208,22 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,  	ssp = sock->sk->sk_security;  	if (strcmp(name, XATTR_SMACK_IPIN) == 0) -		ssp->smk_in = sp; +		ssp->smk_in = skp;  	else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { -		ssp->smk_out = sp; -		rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); -		if (rc != 0) -			printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", -			       __func__, -rc); +		ssp->smk_out = skp; +		if (sock->sk->sk_family == PF_INET) { +			rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); +			if (rc != 0) +				printk(KERN_WARNING +					"Smack: \"%s\" netlbl error %d.\n", +					__func__, -rc); +		}  	} else  		return -EOPNOTSUPP; +	if (sock->sk->sk_family == PF_INET6) +		smk_ipv6_port_label(sock, NULL); +  	return 0;  } @@ -1705,6 +2251,25 @@ static int smack_socket_post_create(struct socket *sock, int family,  }  /** + * smack_socket_bind - record port binding information. + * @sock: the socket + * @address: the port address + * @addrlen: size of the address + * + * Records the label bound to a port. + * + * Returns 0 + */ +static int smack_socket_bind(struct socket *sock, struct sockaddr *address, +				int addrlen) +{ +	if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) +		smk_ipv6_port_label(sock, address); + +	return 0; +} + +/**   * smack_socket_connect - connect access check   * @sock: the socket   * @sap: the other end @@ -1717,12 +2282,25 @@ static int smack_socket_post_create(struct socket *sock, int family,  static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,  				int addrlen)  { -	if (sock->sk == NULL || sock->sk->sk_family != PF_INET) +	int rc = 0; + +	if (sock->sk == NULL)  		return 0; -	if (addrlen < sizeof(struct sockaddr_in)) -		return -EINVAL; -	return smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); +	switch (sock->sk->sk_family) { +	case PF_INET: +		if (addrlen < sizeof(struct sockaddr_in)) +			return -EINVAL; +		rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); +		break; +	case PF_INET6: +		if (addrlen < sizeof(struct sockaddr_in6)) +			return -EINVAL; +		rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap, +						SMK_CONNECTING); +		break; +	} +	return rc;  }  /** @@ -1753,7 +2331,9 @@ static int smack_flags_to_may(int flags)   */  static int smack_msg_msg_alloc_security(struct msg_msg *msg)  { -	msg->security = current_security(); +	struct smack_known *skp = smk_of_current(); + +	msg->security = skp->smk_known;  	return 0;  } @@ -1788,8 +2368,9 @@ static char *smack_of_shm(struct shmid_kernel *shp)  static int smack_shm_alloc_security(struct shmid_kernel *shp)  {  	struct kern_ipc_perm *isp = &shp->shm_perm; +	struct smack_known *skp = smk_of_current(); -	isp->security = current_security(); +	isp->security = skp->smk_known;  	return 0;  } @@ -1911,8 +2492,9 @@ static char *smack_of_sem(struct sem_array *sma)  static int smack_sem_alloc_security(struct sem_array *sma)  {  	struct kern_ipc_perm *isp = &sma->sem_perm; +	struct smack_known *skp = smk_of_current(); -	isp->security = current_security(); +	isp->security = skp->smk_known;  	return 0;  } @@ -2029,8 +2611,9 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,  static int smack_msg_queue_alloc_security(struct msg_queue *msq)  {  	struct kern_ipc_perm *kisp = &msq->q_perm; +	struct smack_known *skp = smk_of_current(); -	kisp->security = current_security(); +	kisp->security = skp->smk_known;  	return 0;  } @@ -2202,9 +2785,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  	struct super_block *sbp;  	struct superblock_smack *sbsp;  	struct inode_smack *isp; -	char *csp = current_security(); -	char *fetched; +	struct smack_known *skp; +	struct smack_known *ckp = smk_of_current();  	char *final; +	char trattr[TRANS_TRUE_SIZE]; +	int transflag = 0; +	int rc;  	struct dentry *dp;  	if (inode == NULL) @@ -2235,6 +2821,15 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  	 * of the superblock.  	 */  	if (opt_dentry->d_parent == opt_dentry) { +		if (sbp->s_magic == CGROUP_SUPER_MAGIC) { +			/* +			 * The cgroup filesystem is never mounted, +			 * so there's no opportunity to set the mount +			 * options. +			 */ +			sbsp->smk_root = smack_known_star.smk_known; +			sbsp->smk_default = smack_known_star.smk_known; +		}  		isp->smk_inode = sbsp->smk_root;  		isp->smk_flags |= SMK_INODE_INSTANT;  		goto unlockandout; @@ -2248,16 +2843,20 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  	 */  	switch (sbp->s_magic) {  	case SMACK_MAGIC: +	case PIPEFS_MAGIC: +	case SOCKFS_MAGIC: +	case CGROUP_SUPER_MAGIC:  		/* -		 * Casey says that it's a little embarassing +		 * Casey says that it's a little embarrassing  		 * that the smack file system doesn't do  		 * extended attributes. -		 */ -		final = smack_known_star.smk_known; -		break; -	case PIPEFS_MAGIC: -		/* +		 *  		 * Casey says pipes are easy (?) +		 * +		 * Socket access is controlled by the socket +		 * structures associated with the task involved. +		 * +		 * Cgroupfs is special  		 */  		final = smack_known_star.smk_known;  		break; @@ -2267,13 +2866,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  		 * Programs that change smack have to treat the  		 * pty with respect.  		 */ -		final = csp; -		break; -	case SOCKFS_MAGIC: -		/* -		 * Casey says sockets get the smack of the task. -		 */ -		final = csp; +		final = ckp->smk_known;  		break;  	case PROC_SUPER_MAGIC:  		/* @@ -2300,7 +2893,16 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  		/*  		 * This isn't an understood special case.  		 * Get the value from the xattr. -		 * +		 */ + +		/* +		 * UNIX domain sockets use lower level socket data. +		 */ +		if (S_ISSOCK(inode->i_mode)) { +			final = smack_known_star.smk_known; +			break; +		} +		/*  		 * No xattr support means, alas, no SMACK label.  		 * Use the aforeapplied default.  		 * It would be curious if the label of the task @@ -2312,19 +2914,62 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)  		 * Get the dentry for xattr.  		 */  		dp = dget(opt_dentry); -		fetched = smk_fetch(inode, dp); -		if (fetched != NULL) -			final = fetched; +		skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); +		if (skp != NULL) +			final = skp->smk_known; + +		/* +		 * 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, +					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; +		} +		/* +		 * 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) +			skp = NULL; +		isp->smk_task = skp; +		skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); +		if (skp == &smack_known_star || skp == &smack_known_web) +			skp = NULL; +		isp->smk_mmap = skp; +  		dput(dp);  		break;  	}  	if (final == NULL) -		isp->smk_inode = csp; +		isp->smk_inode = ckp->smk_known;  	else  		isp->smk_inode = final; -	isp->smk_flags |= SMK_INODE_INSTANT; +	isp->smk_flags |= (SMK_INODE_INSTANT | transflag);  unlockandout:  	mutex_unlock(&isp->smk_lock); @@ -2343,13 +2988,14 @@ unlockandout:   */  static int smack_getprocattr(struct task_struct *p, char *name, char **value)  { +	struct smack_known *skp = smk_of_task(task_security(p));  	char *cp;  	int slen;  	if (strcmp(name, "current") != 0)  		return -EINVAL; -	cp = kstrdup(task_security(p), GFP_KERNEL); +	cp = kstrdup(skp->smk_known, GFP_KERNEL);  	if (cp == NULL)  		return -ENOMEM; @@ -2373,8 +3019,9 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)  static int smack_setprocattr(struct task_struct *p, char *name,  			     void *value, size_t size)  { +	struct task_smack *tsp;  	struct cred *new; -	char *newsmack; +	struct smack_known *skp;  	/*  	 * Changing another process' Smack value is too dangerous @@ -2383,53 +3030,80 @@ static int smack_setprocattr(struct task_struct *p, char *name,  	if (p != current)  		return -EPERM; -	if (!capable(CAP_MAC_ADMIN)) +	if (!smack_privileged(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)  		return -EINVAL; -	newsmack = smk_import(value, size); -	if (newsmack == NULL) +	skp = smk_import_entry(value, size); +	if (skp == NULL)  		return -EINVAL;  	/*  	 * No process is ever allowed the web ("@") label.  	 */ -	if (newsmack == smack_known_web.smk_known) +	if (skp == &smack_known_web)  		return -EPERM;  	new = prepare_creds();  	if (new == NULL)  		return -ENOMEM; -	new->security = newsmack; + +	tsp = new->security; +	tsp->smk_task = skp; +  	commit_creds(new);  	return size;  }  /**   * smack_unix_stream_connect - Smack access on UDS - * @sock: one socket - * @other: the other socket + * @sock: one sock + * @other: the other sock   * @newsk: unused   *   * Return 0 if a subject with the smack of sock could access   * an object with the smack of other, otherwise an error code   */ -static int smack_unix_stream_connect(struct socket *sock, -				     struct socket *other, struct sock *newsk) +static int smack_unix_stream_connect(struct sock *sock, +				     struct sock *other, struct sock *newsk)  { -	struct inode *sp = SOCK_INODE(sock); -	struct inode *op = SOCK_INODE(other); +	struct smack_known *skp; +	struct smack_known *okp; +	struct socket_smack *ssp = sock->sk_security; +	struct socket_smack *osp = other->sk_security; +	struct socket_smack *nsp = newsk->sk_security;  	struct smk_audit_info ad; +	int rc = 0; +#ifdef CONFIG_AUDIT +	struct lsm_network_audit net; +#endif -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); -	smk_ad_setfield_u_net_sk(&ad, other->sk); -	return smk_access(smk_of_inode(sp), smk_of_inode(op), -				 MAY_READWRITE, &ad); +	if (!smack_privileged(CAP_MAC_OVERRIDE)) { +		skp = ssp->smk_out; +		okp = osp->smk_out; +#ifdef CONFIG_AUDIT +		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); +		smk_ad_setfield_u_net_sk(&ad, other); +#endif +		rc = smk_access(skp, okp->smk_known, MAY_WRITE, &ad); +		if (rc == 0) +			rc = smk_access(okp, okp->smk_known, MAY_WRITE, NULL); +	} + +	/* +	 * Cross reference the peer labels for SO_PEERSEC. +	 */ +	if (rc == 0) { +		nsp->smk_packet = ssp->smk_out; +		ssp->smk_packet = osp->smk_out; +	} + +	return rc;  }  /** @@ -2442,13 +3116,23 @@ static int smack_unix_stream_connect(struct socket *sock,   */  static int smack_unix_may_send(struct socket *sock, struct socket *other)  { -	struct inode *sp = SOCK_INODE(sock); -	struct inode *op = SOCK_INODE(other); +	struct socket_smack *ssp = sock->sk->sk_security; +	struct socket_smack *osp = other->sk->sk_security; +	struct smack_known *skp;  	struct smk_audit_info ad; -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); +#ifdef CONFIG_AUDIT +	struct lsm_network_audit net; + +	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);  	smk_ad_setfield_u_net_sk(&ad, other->sk); -	return smk_access(smk_of_inode(sp), smk_of_inode(op), MAY_WRITE, &ad); +#endif + +	if (smack_privileged(CAP_MAC_OVERRIDE)) +		return 0; + +	skp = ssp->smk_out; +	return smk_access(skp, osp->smk_in->smk_known, MAY_WRITE, &ad);  }  /** @@ -2457,37 +3141,48 @@ static int smack_unix_may_send(struct socket *sock, struct socket *other)   * @msg: the message   * @size: the size of the message   * - * Return 0 if the current subject can write to the destination - * host. This is only a question if the destination is a single - * label host. + * Return 0 if the current subject can write to the destination host. + * For IPv4 this is only a question if the destination is a single label host. + * For IPv6 this is a check against the label of the port.   */  static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,  				int size)  {  	struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; +	struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; +	int rc = 0;  	/*  	 * Perfectly reasonable for this to be NULL  	 */ -	if (sip == NULL || sip->sin_family != AF_INET) +	if (sip == NULL)  		return 0; -	return smack_netlabel_send(sock->sk, sip); +	switch (sip->sin_family) { +	case AF_INET: +		rc = smack_netlabel_send(sock->sk, sip); +		break; +	case AF_INET6: +		rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); +		break; +	} +	return rc;  } -  /**   * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack   * @sap: netlabel secattr - * @sip: where to put the result + * @ssp: socket security information   * - * Copies a smack label into sip + * Returns a pointer to a Smack label entry found on the label list.   */ -static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip) +static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, +						struct socket_smack *ssp)  { -	char smack[SMK_LABELLEN]; -	char *sp; -	int pcat; +	struct smack_known *skp; +	int found = 0; +	int acat; +	int kcat;  	if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) {  		/* @@ -2495,40 +3190,52 @@ static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)  		 * 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) +		rcu_read_lock(); +		list_for_each_entry(skp, &smack_known_list, list) { +			if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) +				continue; +			/* +			 * Compare the catsets. Use the netlbl APIs. +			 */ +			if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) { +				if ((skp->smk_netlabel.flags & +				     NETLBL_SECATTR_MLS_CAT) == 0) +					found = 1; +				break; +			} +			for (acat = -1, kcat = -1; acat == kcat; ) { +				acat = netlbl_secattr_catmap_walk( +					sap->attr.mls.cat, acat + 1); +				kcat = netlbl_secattr_catmap_walk( +					skp->smk_netlabel.attr.mls.cat, +					kcat + 1); +				if (acat < 0 || kcat < 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) { -			memcpy(sip, smack, SMK_MAXLEN); -			return; +			if (acat == kcat) { +				found = 1; +				break; +			}  		} -		/* -		 * Look it up in the supplied table if it is not -		 * a direct mapping. -		 */ -		smack_from_cipso(sap->attr.mls.lvl, smack, sip); -		return; +		rcu_read_unlock(); + +		if (found) +			return skp; + +		if (ssp != NULL && ssp->smk_in == &smack_known_star) +			return &smack_known_web; +		return &smack_known_star;  	}  	if ((sap->flags & NETLBL_SECATTR_SECID) != 0) {  		/*  		 * Looks like a fallback, which gives us a secid.  		 */ -		sp = smack_from_secid(sap->attr.secid); +		skp = smack_from_secid(sap->attr.secid);  		/*  		 * This has got to be a bug because it is  		 * impossible to specify a fallback without @@ -2536,17 +3243,62 @@ static void smack_from_secattr(struct netlbl_lsm_secattr *sap, char *sip)  		 * it has a secid, and the only way to get a  		 * secid is from a fallback.  		 */ -		BUG_ON(sp == NULL); -		strncpy(sip, sp, SMK_MAXLEN); -		return; +		BUG_ON(skp == NULL); +		return skp;  	}  	/*  	 * Without guidance regarding the smack value  	 * for the packet fall back on the network  	 * ambient value.  	 */ -	strncpy(sip, smack_net_ambient, SMK_MAXLEN); -	return; +	return smack_net_ambient; +} + +static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) +{ +	u8 nexthdr; +	int offset; +	int proto = -EINVAL; +	struct ipv6hdr _ipv6h; +	struct ipv6hdr *ip6; +	__be16 frag_off; +	struct tcphdr _tcph, *th; +	struct udphdr _udph, *uh; +	struct dccp_hdr _dccph, *dh; + +	sip->sin6_port = 0; + +	offset = skb_network_offset(skb); +	ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); +	if (ip6 == NULL) +		return -EINVAL; +	sip->sin6_addr = ip6->saddr; + +	nexthdr = ip6->nexthdr; +	offset += sizeof(_ipv6h); +	offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); +	if (offset < 0) +		return -EINVAL; + +	proto = nexthdr; +	switch (proto) { +	case IPPROTO_TCP: +		th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); +		if (th != NULL) +			sip->sin6_port = th->source; +		break; +	case IPPROTO_UDP: +		uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); +		if (uh != NULL) +			sip->sin6_port = uh->source; +		break; +	case IPPROTO_DCCP: +		dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); +		if (dh != NULL) +			sip->sin6_port = dh->dccph_sport; +		break; +	} +	return proto;  }  /** @@ -2560,42 +3312,52 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)  {  	struct netlbl_lsm_secattr secattr;  	struct socket_smack *ssp = sk->sk_security; -	char smack[SMK_LABELLEN]; -	char *csp; -	int rc; +	struct smack_known *skp; +	struct sockaddr_in6 sadd; +	int rc = 0;  	struct smk_audit_info ad; -	if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) -		return 0; - -	/* -	 * Translate what netlabel gave us. -	 */ -	netlbl_secattr_init(&secattr); +#ifdef CONFIG_AUDIT +	struct lsm_network_audit net; +#endif +	switch (sk->sk_family) { +	case PF_INET: +		/* +		 * Translate what netlabel gave us. +		 */ +		netlbl_secattr_init(&secattr); -	rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); -	if (rc == 0) { -		smack_from_secattr(&secattr, smack); -		csp = smack; -	} else -		csp = smack_net_ambient; +		rc = netlbl_skbuff_getattr(skb, sk->sk_family, &secattr); +		if (rc == 0) +			skp = smack_from_secattr(&secattr, ssp); +		else +			skp = smack_net_ambient; -	netlbl_secattr_destroy(&secattr); +		netlbl_secattr_destroy(&secattr);  #ifdef CONFIG_AUDIT -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); -	ad.a.u.net.family = sk->sk_family; -	ad.a.u.net.netif = skb->skb_iif; -	ipv4_skb_to_auditdata(skb, &ad.a, NULL); +		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); +		ad.a.u.net->family = sk->sk_family; +		ad.a.u.net->netif = skb->skb_iif; +		ipv4_skb_to_auditdata(skb, &ad.a, NULL);  #endif -	/* -	 * Receiving a packet requires that the other end -	 * be able to write here. Read access is not required. -	 * This is the simplist possible security model -	 * for networking. -	 */ -	rc = smk_access(csp, ssp->smk_in, MAY_WRITE, &ad); -	if (rc != 0) -		netlbl_skbuff_err(skb, rc, 0); +		/* +		 * Receiving a packet requires that the other end +		 * be able to write here. Read access is not required. +		 * This is the simplist possible security model +		 * for networking. +		 */ +		rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad); +		if (rc != 0) +			netlbl_skbuff_err(skb, rc, 0); +		break; +	case PF_INET6: +		rc = smk_skb_to_addr_ipv6(skb, &sadd); +		if (rc == IPPROTO_UDP || rc == IPPROTO_TCP) +			rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); +		else +			rc = 0; +		break; +	}  	return rc;  } @@ -2613,15 +3375,19 @@ static int smack_socket_getpeersec_stream(struct socket *sock,  					  int __user *optlen, unsigned len)  {  	struct socket_smack *ssp; -	int slen; +	char *rcp = ""; +	int slen = 1;  	int rc = 0;  	ssp = sock->sk->sk_security; -	slen = strlen(ssp->smk_packet) + 1; +	if (ssp->smk_packet != NULL) { +		rcp = ssp->smk_packet->smk_known; +		slen = strlen(rcp) + 1; +	}  	if (slen > len)  		rc = -ERANGE; -	else if (copy_to_user(optval, ssp->smk_packet, slen) != 0) +	else if (copy_to_user(optval, rcp, slen) != 0)  		rc = -EFAULT;  	if (put_user(slen, optlen) != 0) @@ -2633,7 +3399,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,  /**   * smack_socket_getpeersec_dgram - pull in packet label - * @sock: the socket + * @sock: the peer socket   * @skb: packet data   * @secid: pointer to where to put the secid of the packet   * @@ -2644,41 +3410,41 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,  {  	struct netlbl_lsm_secattr secattr; -	struct sock *sk; -	char smack[SMK_LABELLEN]; -	int family = PF_INET; -	u32 s; +	struct socket_smack *ssp = NULL; +	struct smack_known *skp; +	int family = PF_UNSPEC; +	u32 s = 0;	/* 0 is the invalid secid */  	int rc; -	/* -	 * Only works for families with packets. -	 */ -	if (sock != NULL) { -		sk = sock->sk; -		if (sk->sk_family != PF_INET && sk->sk_family != PF_INET6) -			return 0; -		family = sk->sk_family; +	if (skb != NULL) { +		if (skb->protocol == htons(ETH_P_IP)) +			family = PF_INET; +		else if (skb->protocol == htons(ETH_P_IPV6)) +			family = PF_INET6;  	} -	/* -	 * Translate what netlabel gave us. -	 */ -	netlbl_secattr_init(&secattr); -	rc = netlbl_skbuff_getattr(skb, family, &secattr); -	if (rc == 0) -		smack_from_secattr(&secattr, smack); -	netlbl_secattr_destroy(&secattr); - -	/* -	 * Give up if we couldn't get anything -	 */ -	if (rc != 0) -		return rc; +	if (family == PF_UNSPEC && sock != NULL) +		family = sock->sk->sk_family; -	s = smack_to_secid(smack); +	if (family == PF_UNIX) { +		ssp = sock->sk->sk_security; +		s = ssp->smk_out->smk_secid; +	} else if (family == PF_INET || family == PF_INET6) { +		/* +		 * Translate what netlabel gave us. +		 */ +		if (sock != NULL && sock->sk != NULL) +			ssp = sock->sk->sk_security; +		netlbl_secattr_init(&secattr); +		rc = netlbl_skbuff_getattr(skb, family, &secattr); +		if (rc == 0) { +			skp = smack_from_secattr(&secattr, ssp); +			s = skp->smk_secid; +		} +		netlbl_secattr_destroy(&secattr); +	} +	*secid = s;  	if (s == 0)  		return -EINVAL; - -	*secid = s;  	return 0;  } @@ -2693,13 +3459,15 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,  static void smack_sock_graft(struct sock *sk, struct socket *parent)  {  	struct socket_smack *ssp; +	struct smack_known *skp = smk_of_current();  	if (sk == NULL ||  	    (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))  		return;  	ssp = sk->sk_security; -	ssp->smk_in = ssp->smk_out = current_security(); +	ssp->smk_in = skp; +	ssp->smk_out = skp;  	/* cssp->smk_packet is already set in smack_inet_csk_clone() */  } @@ -2716,37 +3484,49 @@ 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 smack[SMK_LABELLEN]; +	char *hsp;  	int rc;  	struct smk_audit_info ad; +#ifdef CONFIG_AUDIT +	struct lsm_network_audit net; +#endif -	/* handle mapped IPv4 packets arriving via IPv6 sockets */ -	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) -		family = PF_INET; +	if (family == PF_INET6) { +		/* +		 * Handle mapped IPv4 packets arriving +		 * via IPv6 sockets. Don't set up netlabel +		 * processing on IPv6. +		 */ +		if (skb->protocol == htons(ETH_P_IP)) +			family = PF_INET; +		else +			return 0; +	}  	netlbl_secattr_init(&secattr);  	rc = netlbl_skbuff_getattr(skb, family, &secattr);  	if (rc == 0) -		smack_from_secattr(&secattr, smack); +		skp = smack_from_secattr(&secattr, ssp);  	else -		strncpy(smack, smack_known_huh.smk_known, SMK_MAXLEN); +		skp = &smack_known_huh;  	netlbl_secattr_destroy(&secattr);  #ifdef CONFIG_AUDIT -	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NET); -	ad.a.u.net.family = family; -	ad.a.u.net.netif = skb->skb_iif; +	smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); +	ad.a.u.net->family = family; +	ad.a.u.net->netif = skb->skb_iif;  	ipv4_skb_to_auditdata(skb, &ad.a, NULL);  #endif  	/*  	 * Receiving a packet requires that the other end be able to write  	 * here. Read access is not required.  	 */ -	rc = smk_access(smack, ssp->smk_in, MAY_WRITE, &ad); +	rc = smk_access(skp, ssp->smk_in->smk_known, MAY_WRITE, &ad);  	if (rc != 0)  		return rc; @@ -2754,26 +3534,23 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,  	 * Save the peer's label in the request_sock so we can later setup  	 * smk_packet in the child socket so that SO_PEERCRED can report it.  	 */ -	req->peer_secid = smack_to_secid(smack); +	req->peer_secid = skp->smk_secid;  	/*  	 * We need to decide if we want to label the incoming connection here  	 * if we do we only need to label the request_sock and the stack will -	 * propogate the wire-label to the sock when it is created. +	 * propagate the wire-label to the sock when it is created.  	 */  	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(smack, &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) +		rc = netlbl_req_setattr(req, &skp->smk_netlabel); +	else  		netlbl_req_delattr(req); -	}  	return rc;  } @@ -2789,13 +3566,13 @@ static void smack_inet_csk_clone(struct sock *sk,  				 const struct request_sock *req)  {  	struct socket_smack *ssp = sk->sk_security; -	char *smack; +	struct smack_known *skp;  	if (req->peer_secid != 0) { -		smack = smack_from_secid(req->peer_secid); -		strncpy(ssp->smk_packet, smack, SMK_MAXLEN); +		skp = smack_from_secid(req->peer_secid); +		ssp->smk_packet = skp;  	} else -		ssp->smk_packet[0] = '\0'; +		ssp->smk_packet = NULL;  }  /* @@ -2820,7 +3597,9 @@ static void smack_inet_csk_clone(struct sock *sk,  static int smack_key_alloc(struct key *key, const struct cred *cred,  			   unsigned long flags)  { -	key->security = cred->security; +	struct smack_known *skp = smk_of_task(cred->security); + +	key->security = skp->smk_known;  	return 0;  } @@ -2845,10 +3624,12 @@ static void smack_key_free(struct key *key)   * an error code otherwise   */  static int smack_key_permission(key_ref_t key_ref, -				const struct cred *cred, key_perm_t perm) +				const struct cred *cred, unsigned perm)  {  	struct key *keyp;  	struct smk_audit_info ad; +	struct smack_known *tkp = smk_of_task(cred->security); +	int request = 0;  	keyp = key_ref_to_ptr(key_ref);  	if (keyp == NULL) @@ -2862,15 +3643,18 @@ static int smack_key_permission(key_ref_t key_ref,  	/*  	 * This should not occur  	 */ -	if (cred->security == NULL) +	if (tkp == NULL)  		return -EACCES;  #ifdef CONFIG_AUDIT  	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);  	ad.a.u.key_struct.key = keyp->serial;  	ad.a.u.key_struct.key_desc = keyp->description;  #endif -	return smk_access(cred->security, keyp->security, -				 MAY_READWRITE, &ad); +	if (perm & KEY_NEED_READ) +		request = MAY_READ; +	if (perm & (KEY_NEED_WRITE | KEY_NEED_LINK | KEY_NEED_SETATTR)) +		request = MAY_WRITE; +	return smk_access(tkp, keyp->security, request, &ad);  }  #endif /* CONFIG_KEYS */ @@ -2952,19 +3736,18 @@ static int smack_audit_rule_known(struct audit_krule *krule)  static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,  				  struct audit_context *actx)  { -	char *smack; +	struct smack_known *skp;  	char *rule = vrule; -	if (!rule) { -		audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR, -			  "Smack: missing rule\n"); +	if (unlikely(!rule)) { +		WARN_ONCE(1, "Smack: missing rule\n");  		return -ENOENT;  	}  	if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)  		return 0; -	smack = smack_from_secid(secid); +	skp = smack_from_secid(secid);  	/*  	 * No need to do string comparisons. If a match occurs, @@ -2972,9 +3755,9 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,  	 * label.  	 */  	if (op == Audit_equal) -		return (rule == smack); +		return (rule == skp->smk_known);  	if (op == Audit_not_equal) -		return (rule != smack); +		return (rule != skp->smk_known);  	return 0;  } @@ -2993,6 +3776,16 @@ static void smack_audit_rule_free(void *vrule)  #endif /* CONFIG_AUDIT */  /** + * smack_ismaclabel - check if xattr @name references a smack MAC label + * @name: Full xattr name to check. + */ +static int smack_ismaclabel(const char *name) +{ +	return (strcmp(name, XATTR_SMACK_SUFFIX) == 0); +} + + +/**   * smack_secid_to_secctx - return the smack label for a secid   * @secid: incoming integer   * @secdata: destination @@ -3002,11 +3795,11 @@ static void smack_audit_rule_free(void *vrule)   */  static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)  { -	char *sp = smack_from_secid(secid); +	struct smack_known *skp = smack_from_secid(secid);  	if (secdata) -		*secdata = sp; -	*seclen = strlen(sp); +		*secdata = skp->smk_known; +	*seclen = strlen(skp->smk_known);  	return 0;  } @@ -3068,8 +3861,10 @@ struct security_operations smack_ops = {  	.sb_copy_data = 		smack_sb_copy_data,  	.sb_kern_mount = 		smack_sb_kern_mount,  	.sb_statfs = 			smack_sb_statfs, -	.sb_mount = 			smack_sb_mount, -	.sb_umount = 			smack_sb_umount, + +	.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, @@ -3096,10 +3891,14 @@ struct security_operations smack_ops = {  	.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, @@ -3154,6 +3953,7 @@ struct security_operations smack_ops = {  	.unix_may_send = 		smack_unix_may_send,  	.socket_post_create = 		smack_socket_post_create, +	.socket_bind =			smack_socket_bind,  	.socket_connect =		smack_socket_connect,  	.socket_sendmsg =		smack_socket_sendmsg,  	.socket_sock_rcv_skb = 		smack_socket_sock_rcv_skb, @@ -3180,6 +3980,7 @@ struct security_operations smack_ops = {  	.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, @@ -3189,14 +3990,35 @@ struct security_operations smack_ops = {  }; -static __init void init_smack_know_list(void) +static __init void init_smack_known_list(void)  { -	list_add(&smack_known_huh.list, &smack_known_list); -	list_add(&smack_known_hat.list, &smack_known_list); -	list_add(&smack_known_star.list, &smack_known_list); -	list_add(&smack_known_floor.list, &smack_known_list); -	list_add(&smack_known_invalid.list, &smack_known_list); -	list_add(&smack_known_web.list, &smack_known_list); +	/* +	 * Initialize rule list locks +	 */ +	mutex_init(&smack_known_huh.smk_rules_lock); +	mutex_init(&smack_known_hat.smk_rules_lock); +	mutex_init(&smack_known_floor.smk_rules_lock); +	mutex_init(&smack_known_star.smk_rules_lock); +	mutex_init(&smack_known_invalid.smk_rules_lock); +	mutex_init(&smack_known_web.smk_rules_lock); +	/* +	 * Initialize rule lists +	 */ +	INIT_LIST_HEAD(&smack_known_huh.smk_rules); +	INIT_LIST_HEAD(&smack_known_hat.smk_rules); +	INIT_LIST_HEAD(&smack_known_star.smk_rules); +	INIT_LIST_HEAD(&smack_known_floor.smk_rules); +	INIT_LIST_HEAD(&smack_known_invalid.smk_rules); +	INIT_LIST_HEAD(&smack_known_web.smk_rules); +	/* +	 * Create the known labels list +	 */ +	smk_insert_entry(&smack_known_huh); +	smk_insert_entry(&smack_known_hat); +	smk_insert_entry(&smack_known_star); +	smk_insert_entry(&smack_known_floor); +	smk_insert_entry(&smack_known_invalid); +	smk_insert_entry(&smack_known_web);  }  /** @@ -3207,28 +4029,26 @@ static __init void init_smack_know_list(void)  static __init int smack_init(void)  {  	struct cred *cred; +	struct task_smack *tsp;  	if (!security_module_enable(&smack_ops))  		return 0; +	tsp = new_task_smack(&smack_known_floor, &smack_known_floor, +				GFP_KERNEL); +	if (tsp == NULL) +		return -ENOMEM; +  	printk(KERN_INFO "Smack:  Initializing.\n");  	/*  	 * Set the security state for the initial task.  	 */  	cred = (struct cred *) current->cred; -	cred->security = &smack_known_floor.smk_known; +	cred->security = tsp; -	/* initialize the smack_know_list */ -	init_smack_know_list(); -	/* -	 * Initialize 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); +	/* initialize the smack_known_list */ +	init_smack_known_list();  	/*  	 * Register with LSM  | 
