diff options
Diffstat (limited to 'security')
32 files changed, 501 insertions, 215 deletions
| diff --git a/security/Kconfig b/security/Kconfig index b0cb9a5f9448..c4302067a3ad 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -154,6 +154,7 @@ config HARDENED_USERCOPY  	bool "Harden memory copies between kernel and userspace"  	depends on HAVE_HARDENED_USERCOPY_ALLOCATOR  	select BUG +	imply STRICT_DEVMEM  	help  	  This option checks for obviously wrong memory regions when  	  copying memory to/from the kernel (via copy_to_user() and @@ -163,6 +164,20 @@ config HARDENED_USERCOPY  	  or are part of the kernel text. This kills entire classes  	  of heap overflow exploits and similar kernel memory exposures. +config HARDENED_USERCOPY_FALLBACK +	bool "Allow usercopy whitelist violations to fallback to object size" +	depends on HARDENED_USERCOPY +	default y +	help +	  This is a temporary option that allows missing usercopy whitelists +	  to be discovered via a WARN() to the kernel log, instead of +	  rejecting the copy, falling back to non-whitelisted hardened +	  usercopy that checks the slab allocation size instead of the +	  whitelist size. This option will be removed once it seems like +	  all missing usercopy whitelists have been identified and fixed. +	  Booting with "slab_common.usercopy_fallback=Y/N" can change +	  this setting. +  config HARDENED_USERCOPY_PAGESPAN  	bool "Refuse to copy allocations that span multiple pages"  	depends on HARDENED_USERCOPY diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index d4fa04d91439..a9428daa69f3 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -571,16 +571,16 @@ static int ns_revision_open(struct inode *inode, struct file *file)  	return 0;  } -static unsigned int ns_revision_poll(struct file *file, poll_table *pt) +static __poll_t ns_revision_poll(struct file *file, poll_table *pt)  {  	struct aa_revision *rev = file->private_data; -	unsigned int mask = 0; +	__poll_t mask = 0;  	if (rev) {  		mutex_lock_nested(&rev->ns->lock, rev->ns->level);  		poll_wait(file, &rev->ns->wait, pt);  		if (rev->last_read < rev->ns->revision) -			mask |= POLLIN | POLLRDNORM; +			mask |= EPOLLIN | EPOLLRDNORM;  		mutex_unlock(&rev->ns->lock);  	} diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 6f9e4ce568cd..9bb0a7f2863e 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c @@ -18,6 +18,7 @@  #include <linux/cred.h>  #include <linux/key-type.h>  #include <linux/digsig.h> +#include <linux/vmalloc.h>  #include <crypto/public_key.h>  #include <keys/system_keyring.h> diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index 241aca315b0c..04825393facb 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h @@ -23,9 +23,12 @@  #define EVM_INIT_HMAC	0x0001  #define EVM_INIT_X509	0x0002 -#define EVM_SETUP       0x80000000 /* userland has signaled key load */ +#define EVM_ALLOW_METADATA_WRITES	0x0004 +#define EVM_SETUP_COMPLETE 0x80000000 /* userland has signaled key load */ -#define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP) +#define EVM_KEY_MASK (EVM_INIT_HMAC | EVM_INIT_X509) +#define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP_COMPLETE | \ +		       EVM_ALLOW_METADATA_WRITES)  extern int evm_initialized;  extern char *evm_hmac; @@ -51,7 +54,7 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,  		  size_t req_xattr_value_len, char *digest);  int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,  		  const char *req_xattr_value, -		  size_t req_xattr_value_len, char *digest); +		  size_t req_xattr_value_len, char type, char *digest);  int evm_init_hmac(struct inode *inode, const struct xattr *xattr,  		  char *hmac_val);  int evm_init_secfs(void); diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index bcd64baf8788..691f3e09154c 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c @@ -138,7 +138,7 @@ out:   * protection.)   */  static void hmac_add_misc(struct shash_desc *desc, struct inode *inode, -			  char *digest) +			  char type, char *digest)  {  	struct h_misc {  		unsigned long ino; @@ -149,8 +149,13 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,  	} hmac_misc;  	memset(&hmac_misc, 0, sizeof(hmac_misc)); -	hmac_misc.ino = inode->i_ino; -	hmac_misc.generation = inode->i_generation; +	/* Don't include the inode or generation number in portable +	 * signatures +	 */ +	if (type != EVM_XATTR_PORTABLE_DIGSIG) { +		hmac_misc.ino = inode->i_ino; +		hmac_misc.generation = inode->i_generation; +	}  	/* The hmac uid and gid must be encoded in the initial user  	 * namespace (not the filesystems user namespace) as encoding  	 * them in the filesystems user namespace allows an attack @@ -163,7 +168,8 @@ static void hmac_add_misc(struct shash_desc *desc, struct inode *inode,  	hmac_misc.gid = from_kgid(&init_user_ns, inode->i_gid);  	hmac_misc.mode = inode->i_mode;  	crypto_shash_update(desc, (const u8 *)&hmac_misc, sizeof(hmac_misc)); -	if (evm_hmac_attrs & EVM_ATTR_FSUUID) +	if ((evm_hmac_attrs & EVM_ATTR_FSUUID) && +	    type != EVM_XATTR_PORTABLE_DIGSIG)  		crypto_shash_update(desc, &inode->i_sb->s_uuid.b[0],  				    sizeof(inode->i_sb->s_uuid));  	crypto_shash_final(desc, digest); @@ -189,6 +195,7 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,  	char *xattr_value = NULL;  	int error;  	int size; +	bool ima_present = false;  	if (!(inode->i_opflags & IOP_XATTR))  		return -EOPNOTSUPP; @@ -199,11 +206,18 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,  	error = -ENODATA;  	for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) { +		bool is_ima = false; + +		if (strcmp(*xattrname, XATTR_NAME_IMA) == 0) +			is_ima = true; +  		if ((req_xattr_name && req_xattr_value)  		    && !strcmp(*xattrname, req_xattr_name)) {  			error = 0;  			crypto_shash_update(desc, (const u8 *)req_xattr_value,  					     req_xattr_value_len); +			if (is_ima) +				ima_present = true;  			continue;  		}  		size = vfs_getxattr_alloc(dentry, *xattrname, @@ -218,9 +232,14 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,  		error = 0;  		xattr_size = size;  		crypto_shash_update(desc, (const u8 *)xattr_value, xattr_size); +		if (is_ima) +			ima_present = true;  	} -	hmac_add_misc(desc, inode, digest); +	hmac_add_misc(desc, inode, type, digest); +	/* Portable EVM signatures must include an IMA hash */ +	if (type == EVM_XATTR_PORTABLE_DIGSIG && !ima_present) +		return -EPERM;  out:  	kfree(xattr_value);  	kfree(desc); @@ -232,17 +251,45 @@ int evm_calc_hmac(struct dentry *dentry, const char *req_xattr_name,  		  char *digest)  {  	return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, -				req_xattr_value_len, EVM_XATTR_HMAC, digest); +			       req_xattr_value_len, EVM_XATTR_HMAC, digest);  }  int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,  		  const char *req_xattr_value, size_t req_xattr_value_len, -		  char *digest) +		  char type, char *digest)  {  	return evm_calc_hmac_or_hash(dentry, req_xattr_name, req_xattr_value, -				req_xattr_value_len, IMA_XATTR_DIGEST, digest); +				     req_xattr_value_len, type, digest); +} + +static int evm_is_immutable(struct dentry *dentry, struct inode *inode) +{ +	const struct evm_ima_xattr_data *xattr_data = NULL; +	struct integrity_iint_cache *iint; +	int rc = 0; + +	iint = integrity_iint_find(inode); +	if (iint && (iint->flags & EVM_IMMUTABLE_DIGSIG)) +		return 1; + +	/* Do this the hard way */ +	rc = vfs_getxattr_alloc(dentry, XATTR_NAME_EVM, (char **)&xattr_data, 0, +				GFP_NOFS); +	if (rc <= 0) { +		if (rc == -ENODATA) +			return 0; +		return rc; +	} +	if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) +		rc = 1; +	else +		rc = 0; + +	kfree(xattr_data); +	return rc;  } +  /*   * Calculate the hmac and update security.evm xattr   * @@ -255,6 +302,16 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,  	struct evm_ima_xattr_data xattr_data;  	int rc = 0; +	/* +	 * Don't permit any transformation of the EVM xattr if the signature +	 * is of an immutable type +	 */ +	rc = evm_is_immutable(dentry, inode); +	if (rc < 0) +		return rc; +	if (rc) +		return -EPERM; +  	rc = evm_calc_hmac(dentry, xattr_name, xattr_value,  			   xattr_value_len, xattr_data.digest);  	if (rc == 0) { @@ -280,7 +337,7 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,  	}  	crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len); -	hmac_add_misc(desc, inode, hmac_val); +	hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);  	kfree(desc);  	return 0;  } diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 9826c02e2db8..a8d502827270 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c @@ -31,7 +31,7 @@  int evm_initialized;  static char *integrity_status_msg[] = { -	"pass", "fail", "no_label", "no_xattrs", "unknown" +	"pass", "pass_immutable", "fail", "no_label", "no_xattrs", "unknown"  };  char *evm_hmac = "hmac(sha1)";  char *evm_hash = "sha1"; @@ -76,6 +76,11 @@ static void __init evm_init_config(void)  	pr_info("HMAC attrs: 0x%x\n", evm_hmac_attrs);  } +static bool evm_key_loaded(void) +{ +	return (bool)(evm_initialized & EVM_KEY_MASK); +} +  static int evm_find_protected_xattrs(struct dentry *dentry)  {  	struct inode *inode = d_backing_inode(dentry); @@ -123,7 +128,8 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,  	enum integrity_status evm_status = INTEGRITY_PASS;  	int rc, xattr_len; -	if (iint && iint->evm_status == INTEGRITY_PASS) +	if (iint && (iint->evm_status == INTEGRITY_PASS || +		     iint->evm_status == INTEGRITY_PASS_IMMUTABLE))  		return iint->evm_status;  	/* if status is not PASS, try to check again - against -ENOMEM */ @@ -164,22 +170,26 @@ static enum integrity_status evm_verify_hmac(struct dentry *dentry,  			rc = -EINVAL;  		break;  	case EVM_IMA_XATTR_DIGSIG: +	case EVM_XATTR_PORTABLE_DIGSIG:  		rc = evm_calc_hash(dentry, xattr_name, xattr_value, -				xattr_value_len, calc.digest); +				   xattr_value_len, xattr_data->type, +				   calc.digest);  		if (rc)  			break;  		rc = integrity_digsig_verify(INTEGRITY_KEYRING_EVM,  					(const char *)xattr_data, xattr_len,  					calc.digest, sizeof(calc.digest));  		if (!rc) { -			/* Replace RSA with HMAC if not mounted readonly and -			 * not immutable -			 */ -			if (!IS_RDONLY(d_backing_inode(dentry)) && -			    !IS_IMMUTABLE(d_backing_inode(dentry))) +			if (xattr_data->type == EVM_XATTR_PORTABLE_DIGSIG) { +				if (iint) +					iint->flags |= EVM_IMMUTABLE_DIGSIG; +				evm_status = INTEGRITY_PASS_IMMUTABLE; +			} else if (!IS_RDONLY(d_backing_inode(dentry)) && +				   !IS_IMMUTABLE(d_backing_inode(dentry))) {  				evm_update_evmxattr(dentry, xattr_name,  						    xattr_value,  						    xattr_value_len); +			}  		}  		break;  	default: @@ -241,7 +251,7 @@ enum integrity_status evm_verifyxattr(struct dentry *dentry,  				      void *xattr_value, size_t xattr_value_len,  				      struct integrity_iint_cache *iint)  { -	if (!evm_initialized || !evm_protected_xattr(xattr_name)) +	if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))  		return INTEGRITY_UNKNOWN;  	if (!iint) { @@ -265,7 +275,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)  {  	struct inode *inode = d_backing_inode(dentry); -	if (!evm_initialized || !S_ISREG(inode->i_mode) || evm_fixmode) +	if (!evm_key_loaded() || !S_ISREG(inode->i_mode) || evm_fixmode)  		return 0;  	return evm_verify_hmac(dentry, NULL, NULL, 0, NULL);  } @@ -280,7 +290,7 @@ static enum integrity_status evm_verify_current_integrity(struct dentry *dentry)   * affect security.evm.  An interesting side affect of writing posix xattr   * acls is their modifying of the i_mode, which is included in security.evm.   * For posix xattr acls only, permit security.evm, even if it currently - * doesn't exist, to be updated. + * doesn't exist, to be updated unless the EVM signature is immutable.   */  static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,  			     const void *xattr_value, size_t xattr_value_len) @@ -299,6 +309,7 @@ static int evm_protect_xattr(struct dentry *dentry, const char *xattr_name,  			return 0;  		goto out;  	} +  	evm_status = evm_verify_current_integrity(dentry);  	if (evm_status == INTEGRITY_NOXATTRS) {  		struct integrity_iint_cache *iint; @@ -345,10 +356,17 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,  {  	const struct evm_ima_xattr_data *xattr_data = xattr_value; +	/* Policy permits modification of the protected xattrs even though +	 * there's no HMAC key loaded +	 */ +	if (evm_initialized & EVM_ALLOW_METADATA_WRITES) +		return 0; +  	if (strcmp(xattr_name, XATTR_NAME_EVM) == 0) {  		if (!xattr_value_len)  			return -EINVAL; -		if (xattr_data->type != EVM_IMA_XATTR_DIGSIG) +		if (xattr_data->type != EVM_IMA_XATTR_DIGSIG && +		    xattr_data->type != EVM_XATTR_PORTABLE_DIGSIG)  			return -EPERM;  	}  	return evm_protect_xattr(dentry, xattr_name, xattr_value, @@ -365,6 +383,12 @@ int evm_inode_setxattr(struct dentry *dentry, const char *xattr_name,   */  int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name)  { +	/* Policy permits modification of the protected xattrs even though +	 * there's no HMAC key loaded +	 */ +	if (evm_initialized & EVM_ALLOW_METADATA_WRITES) +		return 0; +  	return evm_protect_xattr(dentry, xattr_name, NULL, 0);  } @@ -393,8 +417,8 @@ static void evm_reset_status(struct inode *inode)  void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,  			     const void *xattr_value, size_t xattr_value_len)  { -	if (!evm_initialized || (!evm_protected_xattr(xattr_name) -				 && !posix_xattr_acl(xattr_name))) +	if (!evm_key_loaded() || (!evm_protected_xattr(xattr_name) +				  && !posix_xattr_acl(xattr_name)))  		return;  	evm_reset_status(dentry->d_inode); @@ -414,7 +438,7 @@ void evm_inode_post_setxattr(struct dentry *dentry, const char *xattr_name,   */  void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)  { -	if (!evm_initialized || !evm_protected_xattr(xattr_name)) +	if (!evm_key_loaded() || !evm_protected_xattr(xattr_name))  		return;  	evm_reset_status(dentry->d_inode); @@ -425,12 +449,21 @@ void evm_inode_post_removexattr(struct dentry *dentry, const char *xattr_name)  /**   * evm_inode_setattr - prevent updating an invalid EVM extended attribute   * @dentry: pointer to the affected dentry + * + * Permit update of file attributes when files have a valid EVM signature, + * except in the case of them having an immutable portable signature.   */  int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)  {  	unsigned int ia_valid = attr->ia_valid;  	enum integrity_status evm_status; +	/* Policy permits modification of the protected attrs even though +	 * there's no HMAC key loaded +	 */ +	if (evm_initialized & EVM_ALLOW_METADATA_WRITES) +		return 0; +  	if (!(ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))  		return 0;  	evm_status = evm_verify_current_integrity(dentry); @@ -456,7 +489,7 @@ int evm_inode_setattr(struct dentry *dentry, struct iattr *attr)   */  void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)  { -	if (!evm_initialized) +	if (!evm_key_loaded())  		return;  	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) @@ -473,7 +506,7 @@ int evm_inode_init_security(struct inode *inode,  	struct evm_ima_xattr_data *xattr_data;  	int rc; -	if (!evm_initialized || !evm_protected_xattr(lsm_xattr->name)) +	if (!evm_key_loaded() || !evm_protected_xattr(lsm_xattr->name))  		return 0;  	xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS); diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index 319cf16d6603..feba03bbedae 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c @@ -40,7 +40,7 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf,  	if (*ppos != 0)  		return 0; -	sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP)); +	sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP_COMPLETE));  	rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp));  	return rc; @@ -63,7 +63,7 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,  {  	int i, ret; -	if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP)) +	if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP_COMPLETE))  		return -EPERM;  	ret = kstrtoint_from_user(buf, count, 0, &i); @@ -75,16 +75,30 @@ static ssize_t evm_write_key(struct file *file, const char __user *buf,  	if (!i || (i & ~EVM_INIT_MASK) != 0)  		return -EINVAL; +	/* Don't allow a request to freshly enable metadata writes if +	 * keys are loaded. +	 */ +	if ((i & EVM_ALLOW_METADATA_WRITES) && +	    ((evm_initialized & EVM_KEY_MASK) != 0) && +	    !(evm_initialized & EVM_ALLOW_METADATA_WRITES)) +		return -EPERM; +  	if (i & EVM_INIT_HMAC) {  		ret = evm_init_key();  		if (ret != 0)  			return ret;  		/* Forbid further writes after the symmetric key is loaded */ -		i |= EVM_SETUP; +		i |= EVM_SETUP_COMPLETE;  	}  	evm_initialized |= i; +	/* Don't allow protected metadata modification if a symmetric key +	 * is loaded +	 */ +	if (evm_initialized & EVM_INIT_HMAC) +		evm_initialized &= ~(EVM_ALLOW_METADATA_WRITES); +  	return count;  } diff --git a/security/integrity/iint.c b/security/integrity/iint.c index c84e05866052..9700e96ab0f0 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c @@ -74,6 +74,7 @@ static void iint_free(struct integrity_iint_cache *iint)  	iint->ima_hash = NULL;  	iint->version = 0;  	iint->flags = 0UL; +	iint->atomic_flags = 0UL;  	iint->ima_file_status = INTEGRITY_UNKNOWN;  	iint->ima_mmap_status = INTEGRITY_UNKNOWN;  	iint->ima_bprm_status = INTEGRITY_UNKNOWN; @@ -153,14 +154,12 @@ static void init_once(void *foo)  	struct integrity_iint_cache *iint = foo;  	memset(iint, 0, sizeof(*iint)); -	iint->version = 0; -	iint->flags = 0UL;  	iint->ima_file_status = INTEGRITY_UNKNOWN;  	iint->ima_mmap_status = INTEGRITY_UNKNOWN;  	iint->ima_bprm_status = INTEGRITY_UNKNOWN;  	iint->ima_read_status = INTEGRITY_UNKNOWN;  	iint->evm_status = INTEGRITY_UNKNOWN; -	iint->measured_pcrs = 0; +	mutex_init(&iint->mutex);  }  static int __init integrity_iintcache_init(void) diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c7e8db0ea4c0..08fe405338e1 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -18,6 +18,7 @@  #include <linux/fs.h>  #include <linux/xattr.h>  #include <linux/evm.h> +#include <linux/iversion.h>  #include "ima.h" @@ -174,7 +175,7 @@ err_out:   */  int ima_get_action(struct inode *inode, int mask, enum ima_hooks func, int *pcr)  { -	int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE; +	int flags = IMA_MEASURE | IMA_AUDIT | IMA_APPRAISE | IMA_HASH;  	flags &= ima_policy_flag; @@ -215,7 +216,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,  	 * which do not support i_version, support is limited to an initial  	 * measurement/appraisal/audit.  	 */ -	i_version = file_inode(file)->i_version; +	i_version = inode_query_iversion(inode);  	hash.hdr.algo = algo;  	/* Initialize hash digest to 0's in case of failure */ diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 65fbcf3c32c7..f2803a40ff82 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -46,14 +46,15 @@ bool is_ima_appraise_enabled(void)  /*   * ima_must_appraise - set appraise flag   * - * Return 1 to appraise + * Return 1 to appraise or hash   */  int ima_must_appraise(struct inode *inode, int mask, enum ima_hooks func)  {  	if (!ima_appraise)  		return 0; -	return ima_match_policy(inode, func, mask, IMA_APPRAISE, NULL); +	return ima_match_policy(inode, func, mask, IMA_APPRAISE | IMA_HASH, +				NULL);  }  static int ima_fix_xattr(struct dentry *dentry, @@ -223,13 +224,16 @@ int ima_appraise_measurement(enum ima_hooks func,  		if (opened & FILE_CREATED)  			iint->flags |= IMA_NEW_FILE;  		if ((iint->flags & IMA_NEW_FILE) && -		    !(iint->flags & IMA_DIGSIG_REQUIRED)) +		    (!(iint->flags & IMA_DIGSIG_REQUIRED) || +		     (inode->i_size == 0)))  			status = INTEGRITY_PASS;  		goto out;  	}  	status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint); -	if ((status != INTEGRITY_PASS) && (status != INTEGRITY_UNKNOWN)) { +	if ((status != INTEGRITY_PASS) && +	    (status != INTEGRITY_PASS_IMMUTABLE) && +	    (status != INTEGRITY_UNKNOWN)) {  		if ((status == INTEGRITY_NOLABEL)  		    || (status == INTEGRITY_NOXATTRS))  			cause = "missing-HMAC"; @@ -248,6 +252,7 @@ int ima_appraise_measurement(enum ima_hooks func,  			status = INTEGRITY_FAIL;  			break;  		} +		clear_bit(IMA_DIGSIG, &iint->atomic_flags);  		if (xattr_len - sizeof(xattr_value->type) - hash_start >=  				iint->ima_hash->length)  			/* xattr length may be longer. md5 hash in previous @@ -266,7 +271,7 @@ int ima_appraise_measurement(enum ima_hooks func,  		status = INTEGRITY_PASS;  		break;  	case EVM_IMA_XATTR_DIGSIG: -		iint->flags |= IMA_DIGSIG; +		set_bit(IMA_DIGSIG, &iint->atomic_flags);  		rc = integrity_digsig_verify(INTEGRITY_KEYRING_IMA,  					     (const char *)xattr_value, rc,  					     iint->ima_hash->digest, @@ -317,17 +322,20 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)  	int rc = 0;  	/* do not collect and update hash for digital signatures */ -	if (iint->flags & IMA_DIGSIG) +	if (test_bit(IMA_DIGSIG, &iint->atomic_flags))  		return; -	if (iint->ima_file_status != INTEGRITY_PASS) +	if ((iint->ima_file_status != INTEGRITY_PASS) && +	    !(iint->flags & IMA_HASH))  		return;  	rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo);  	if (rc < 0)  		return; +	inode_lock(file_inode(file));  	ima_fix_xattr(dentry, iint); +	inode_unlock(file_inode(file));  }  /** @@ -343,23 +351,21 @@ void ima_inode_post_setattr(struct dentry *dentry)  {  	struct inode *inode = d_backing_inode(dentry);  	struct integrity_iint_cache *iint; -	int must_appraise; +	int action;  	if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)  	    || !(inode->i_opflags & IOP_XATTR))  		return; -	must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); +	action = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); +	if (!action) +		__vfs_removexattr(dentry, XATTR_NAME_IMA);  	iint = integrity_iint_find(inode);  	if (iint) { -		iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | -				 IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | -				 IMA_ACTION_RULE_FLAGS); -		if (must_appraise) -			iint->flags |= IMA_APPRAISE; +		set_bit(IMA_CHANGE_ATTR, &iint->atomic_flags); +		if (!action) +			clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags);  	} -	if (!must_appraise) -		__vfs_removexattr(dentry, XATTR_NAME_IMA);  }  /* @@ -388,12 +394,12 @@ static void ima_reset_appraise_flags(struct inode *inode, int digsig)  	iint = integrity_iint_find(inode);  	if (!iint)  		return; - -	iint->flags &= ~IMA_DONE_MASK;  	iint->measured_pcrs = 0; +	set_bit(IMA_CHANGE_XATTR, &iint->atomic_flags);  	if (digsig) -		iint->flags |= IMA_DIGSIG; -	return; +		set_bit(IMA_DIGSIG, &iint->atomic_flags); +	else +		clear_bit(IMA_DIGSIG, &iint->atomic_flags);  }  int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 9057b163c378..205bc69361ea 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c @@ -632,7 +632,7 @@ static void __init ima_pcrread(int idx, u8 *pcr)  	if (!ima_used_chip)  		return; -	if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) +	if (tpm_pcr_read(NULL, idx, pcr) != 0)  		pr_err("Error Communicating to TPM chip\n");  } diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c index 2967d497a665..29b72cd2502e 100644 --- a/security/integrity/ima/ima_init.c +++ b/security/integrity/ima/ima_init.c @@ -110,7 +110,7 @@ int __init ima_init(void)  	int rc;  	ima_used_chip = 0; -	rc = tpm_pcr_read(TPM_ANY_NUM, 0, pcr_i); +	rc = tpm_pcr_read(NULL, 0, pcr_i);  	if (rc == 0)  		ima_used_chip = 1; diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 770654694efc..2cfb0c714967 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c @@ -24,6 +24,7 @@  #include <linux/slab.h>  #include <linux/xattr.h>  #include <linux/ima.h> +#include <linux/iversion.h>  #include "ima.h" @@ -84,10 +85,10 @@ static void ima_rdwr_violation_check(struct file *file,  				     struct integrity_iint_cache *iint,  				     int must_measure,  				     char **pathbuf, -				     const char **pathname) +				     const char **pathname, +				     char *filename)  {  	struct inode *inode = file_inode(file); -	char filename[NAME_MAX];  	fmode_t mode = file->f_mode;  	bool send_tomtou = false, send_writers = false; @@ -96,10 +97,13 @@ static void ima_rdwr_violation_check(struct file *file,  			if (!iint)  				iint = integrity_iint_find(inode);  			/* IMA_MEASURE is set from reader side */ -			if (iint && (iint->flags & IMA_MEASURE)) +			if (iint && test_bit(IMA_MUST_MEASURE, +						&iint->atomic_flags))  				send_tomtou = true;  		}  	} else { +		if (must_measure) +			set_bit(IMA_MUST_MEASURE, &iint->atomic_flags);  		if ((atomic_read(&inode->i_writecount) > 0) && must_measure)  			send_writers = true;  	} @@ -121,21 +125,25 @@ static void ima_check_last_writer(struct integrity_iint_cache *iint,  				  struct inode *inode, struct file *file)  {  	fmode_t mode = file->f_mode; +	bool update;  	if (!(mode & FMODE_WRITE))  		return; -	inode_lock(inode); +	mutex_lock(&iint->mutex);  	if (atomic_read(&inode->i_writecount) == 1) { -		if ((iint->version != inode->i_version) || +		update = test_and_clear_bit(IMA_UPDATE_XATTR, +					    &iint->atomic_flags); +		if (!IS_I_VERSION(inode) || +		    !inode_eq_iversion(inode, iint->version) ||  		    (iint->flags & IMA_NEW_FILE)) {  			iint->flags &= ~(IMA_DONE_MASK | IMA_NEW_FILE);  			iint->measured_pcrs = 0; -			if (iint->flags & IMA_APPRAISE) +			if (update)  				ima_update_xattr(iint, file);  		}  	} -	inode_unlock(inode); +	mutex_unlock(&iint->mutex);  }  /** @@ -168,7 +176,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,  	char *pathbuf = NULL;  	char filename[NAME_MAX];  	const char *pathname = NULL; -	int rc = -ENOMEM, action, must_appraise; +	int rc = 0, action, must_appraise = 0;  	int pcr = CONFIG_IMA_MEASURE_PCR_IDX;  	struct evm_ima_xattr_data *xattr_value = NULL;  	int xattr_len = 0; @@ -199,17 +207,31 @@ static int process_measurement(struct file *file, char *buf, loff_t size,  	if (action) {  		iint = integrity_inode_get(inode);  		if (!iint) -			goto out; +			rc = -ENOMEM;  	} -	if (violation_check) { +	if (!rc && violation_check)  		ima_rdwr_violation_check(file, iint, action & IMA_MEASURE, -					 &pathbuf, &pathname); -		if (!action) { -			rc = 0; -			goto out_free; -		} -	} +					 &pathbuf, &pathname, filename); + +	inode_unlock(inode); + +	if (rc) +		goto out; +	if (!action) +		goto out; + +	mutex_lock(&iint->mutex); + +	if (test_and_clear_bit(IMA_CHANGE_ATTR, &iint->atomic_flags)) +		/* reset appraisal flags if ima_inode_post_setattr was called */ +		iint->flags &= ~(IMA_APPRAISE | IMA_APPRAISED | +				 IMA_APPRAISE_SUBMASK | IMA_APPRAISED_SUBMASK | +				 IMA_ACTION_FLAGS); + +	if (test_and_clear_bit(IMA_CHANGE_XATTR, &iint->atomic_flags)) +		/* reset all flags if ima_inode_setxattr was called */ +		iint->flags &= ~IMA_DONE_MASK;  	/* Determine if already appraised/measured based on bitmask  	 * (IMA_MEASURE, IMA_MEASURED, IMA_XXXX_APPRAISE, IMA_XXXX_APPRAISED, @@ -223,11 +245,23 @@ static int process_measurement(struct file *file, char *buf, loff_t size,  	if ((action & IMA_MEASURE) && (iint->measured_pcrs & (0x1 << pcr)))  		action ^= IMA_MEASURE; +	/* HASH sets the digital signature and update flags, nothing else */ +	if ((action & IMA_HASH) && +	    !(test_bit(IMA_DIGSIG, &iint->atomic_flags))) { +		xattr_len = ima_read_xattr(file_dentry(file), &xattr_value); +		if ((xattr_value && xattr_len > 2) && +		    (xattr_value->type == EVM_IMA_XATTR_DIGSIG)) +			set_bit(IMA_DIGSIG, &iint->atomic_flags); +		iint->flags |= IMA_HASHED; +		action ^= IMA_HASH; +		set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); +	} +  	/* Nothing to do, just return existing appraised status */  	if (!action) {  		if (must_appraise)  			rc = ima_get_cache_status(iint, func); -		goto out_digsig; +		goto out_locked;  	}  	template_desc = ima_template_desc_current(); @@ -240,7 +274,7 @@ static int process_measurement(struct file *file, char *buf, loff_t size,  	rc = ima_collect_measurement(iint, file, buf, size, hash_algo);  	if (rc != 0 && rc != -EBADF && rc != -EINVAL) -		goto out_digsig; +		goto out_locked;  	if (!pathbuf)	/* ima_rdwr_violation possibly pre-fetched */  		pathname = ima_d_path(&file->f_path, &pathbuf, filename); @@ -248,26 +282,32 @@ static int process_measurement(struct file *file, char *buf, loff_t size,  	if (action & IMA_MEASURE)  		ima_store_measurement(iint, file, pathname,  				      xattr_value, xattr_len, pcr); -	if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) +	if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) { +		inode_lock(inode);  		rc = ima_appraise_measurement(func, iint, file, pathname,  					      xattr_value, xattr_len, opened); +		inode_unlock(inode); +	}  	if (action & IMA_AUDIT)  		ima_audit_measurement(iint, pathname);  	if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO))  		rc = 0; -out_digsig: -	if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) && +out_locked: +	if ((mask & MAY_WRITE) && test_bit(IMA_DIGSIG, &iint->atomic_flags) &&  	     !(iint->flags & IMA_NEW_FILE))  		rc = -EACCES; +	mutex_unlock(&iint->mutex);  	kfree(xattr_value); -out_free: +out:  	if (pathbuf)  		__putname(pathbuf); -out: -	inode_unlock(inode); -	if ((rc && must_appraise) && (ima_appraise & IMA_APPRAISE_ENFORCE)) -		return -EACCES; +	if (must_appraise) { +		if (rc && (ima_appraise & IMA_APPRAISE_ENFORCE)) +			return -EACCES; +		if (file->f_mode & FMODE_WRITE) +			set_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); +	}  	return 0;  } @@ -366,8 +406,10 @@ int ima_read_file(struct file *file, enum kernel_read_file_id read_id)  	if (!file && read_id == READING_MODULE) {  		if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES) && -		    (ima_appraise & IMA_APPRAISE_ENFORCE)) +		    (ima_appraise & IMA_APPRAISE_ENFORCE)) { +			pr_err("impossible to appraise a module without a file descriptor. sig_enforce kernel parameter might help\n");  			return -EACCES;	/* INTEGRITY_UNKNOWN */ +		}  		return 0;	/* We rely on module signature checking */  	}  	return 0; diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index ee4613fa5840..915f5572c6ff 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -40,6 +40,8 @@  #define APPRAISE	0x0004	/* same as IMA_APPRAISE */  #define DONT_APPRAISE	0x0008  #define AUDIT		0x0040 +#define HASH		0x0100 +#define DONT_HASH	0x0200  #define INVALID_PCR(a) (((a) < 0) || \  	(a) >= (FIELD_SIZEOF(struct integrity_iint_cache, measured_pcrs) * 8)) @@ -380,8 +382,10 @@ int ima_match_policy(struct inode *inode, enum ima_hooks func, int mask,  		action |= entry->flags & IMA_ACTION_FLAGS;  		action |= entry->action & IMA_DO_MASK; -		if (entry->action & IMA_APPRAISE) +		if (entry->action & IMA_APPRAISE) {  			action |= get_subaction(entry, func); +			action ^= IMA_HASH; +		}  		if (entry->action & IMA_DO_MASK)  			actmask &= ~(entry->action | entry->action << 1); @@ -521,7 +525,7 @@ enum {  	Opt_err = -1,  	Opt_measure = 1, Opt_dont_measure,  	Opt_appraise, Opt_dont_appraise, -	Opt_audit, +	Opt_audit, Opt_hash, Opt_dont_hash,  	Opt_obj_user, Opt_obj_role, Opt_obj_type,  	Opt_subj_user, Opt_subj_role, Opt_subj_type,  	Opt_func, Opt_mask, Opt_fsmagic, @@ -538,6 +542,8 @@ static match_table_t policy_tokens = {  	{Opt_appraise, "appraise"},  	{Opt_dont_appraise, "dont_appraise"},  	{Opt_audit, "audit"}, +	{Opt_hash, "hash"}, +	{Opt_dont_hash, "dont_hash"},  	{Opt_obj_user, "obj_user=%s"},  	{Opt_obj_role, "obj_role=%s"},  	{Opt_obj_type, "obj_type=%s"}, @@ -671,6 +677,22 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)  			entry->action = AUDIT;  			break; +		case Opt_hash: +			ima_log_string(ab, "action", "hash"); + +			if (entry->action != UNKNOWN) +				result = -EINVAL; + +			entry->action = HASH; +			break; +		case Opt_dont_hash: +			ima_log_string(ab, "action", "dont_hash"); + +			if (entry->action != UNKNOWN) +				result = -EINVAL; + +			entry->action = DONT_HASH; +			break;  		case Opt_func:  			ima_log_string(ab, "func", args[0].from); @@ -743,7 +765,7 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)  		case Opt_fsuuid:  			ima_log_string(ab, "fsuuid", args[0].from); -			if (uuid_is_null(&entry->fsuuid)) { +			if (!uuid_is_null(&entry->fsuuid)) {  				result = -EINVAL;  				break;  			} @@ -1040,6 +1062,10 @@ int ima_policy_show(struct seq_file *m, void *v)  		seq_puts(m, pt(Opt_dont_appraise));  	if (entry->action & AUDIT)  		seq_puts(m, pt(Opt_audit)); +	if (entry->action & HASH) +		seq_puts(m, pt(Opt_hash)); +	if (entry->action & DONT_HASH) +		seq_puts(m, pt(Opt_dont_hash));  	seq_puts(m, " "); diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index a02a86d51102..418f35e38015 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -145,7 +145,7 @@ static int ima_pcr_extend(const u8 *hash, int pcr)  	if (!ima_used_chip)  		return result; -	result = tpm_pcr_extend(TPM_ANY_NUM, pcr, hash); +	result = tpm_pcr_extend(NULL, pcr, hash);  	if (result != 0)  		pr_err("Error Communicating to TPM chip, result: %d\n", result);  	return result; diff --git a/security/integrity/ima/ima_template.c b/security/integrity/ima/ima_template.c index 7412d0291ab9..30db39b23804 100644 --- a/security/integrity/ima/ima_template.c +++ b/security/integrity/ima/ima_template.c @@ -377,8 +377,7 @@ int ima_restore_measurement_list(loff_t size, void *buf)  			break;  		if (hdr[HDR_TEMPLATE_NAME].len >= MAX_TEMPLATE_NAME_LEN) { -			pr_err("attempting to restore a template name \ -				that is too long\n"); +			pr_err("attempting to restore a template name that is too long\n");  			ret = -EINVAL;  			break;  		} @@ -389,8 +388,8 @@ int ima_restore_measurement_list(loff_t size, void *buf)  		template_name[hdr[HDR_TEMPLATE_NAME].len] = 0;  		if (strcmp(template_name, "ima") == 0) { -			pr_err("attempting to restore an unsupported \ -				template \"%s\" failed\n", template_name); +			pr_err("attempting to restore an unsupported template \"%s\" failed\n", +			       template_name);  			ret = -EINVAL;  			break;  		} @@ -410,8 +409,8 @@ int ima_restore_measurement_list(loff_t size, void *buf)  						&(template_desc->fields),  						&(template_desc->num_fields));  		if (ret < 0) { -			pr_err("attempting to restore the template fmt \"%s\" \ -				failed\n", template_desc->fmt); +			pr_err("attempting to restore the template fmt \"%s\" failed\n", +			       template_desc->fmt);  			ret = -EINVAL;  			break;  		} diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index e1bf040fb110..50a8e3365df7 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h @@ -25,39 +25,50 @@  #define IMA_COLLECTED		0x00000020  #define IMA_AUDIT		0x00000040  #define IMA_AUDITED		0x00000080 +#define IMA_HASH		0x00000100 +#define IMA_HASHED		0x00000200  /* iint cache flags */  #define IMA_ACTION_FLAGS	0xff000000  #define IMA_ACTION_RULE_FLAGS	0x06000000 -#define IMA_DIGSIG		0x01000000 -#define IMA_DIGSIG_REQUIRED	0x02000000 -#define IMA_PERMIT_DIRECTIO	0x04000000 -#define IMA_NEW_FILE		0x08000000 +#define IMA_DIGSIG_REQUIRED	0x01000000 +#define IMA_PERMIT_DIRECTIO	0x02000000 +#define IMA_NEW_FILE		0x04000000 +#define EVM_IMMUTABLE_DIGSIG	0x08000000  #define IMA_DO_MASK		(IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ -				 IMA_APPRAISE_SUBMASK) +				 IMA_HASH | IMA_APPRAISE_SUBMASK)  #define IMA_DONE_MASK		(IMA_MEASURED | IMA_APPRAISED | IMA_AUDITED | \ -				 IMA_COLLECTED | IMA_APPRAISED_SUBMASK) +				 IMA_HASHED | IMA_COLLECTED | \ +				 IMA_APPRAISED_SUBMASK)  /* iint subaction appraise cache flags */ -#define IMA_FILE_APPRAISE	0x00000100 -#define IMA_FILE_APPRAISED	0x00000200 -#define IMA_MMAP_APPRAISE	0x00000400 -#define IMA_MMAP_APPRAISED	0x00000800 -#define IMA_BPRM_APPRAISE	0x00001000 -#define IMA_BPRM_APPRAISED	0x00002000 -#define IMA_READ_APPRAISE	0x00004000 -#define IMA_READ_APPRAISED	0x00008000 +#define IMA_FILE_APPRAISE	0x00001000 +#define IMA_FILE_APPRAISED	0x00002000 +#define IMA_MMAP_APPRAISE	0x00004000 +#define IMA_MMAP_APPRAISED	0x00008000 +#define IMA_BPRM_APPRAISE	0x00010000 +#define IMA_BPRM_APPRAISED	0x00020000 +#define IMA_READ_APPRAISE	0x00040000 +#define IMA_READ_APPRAISED	0x00080000  #define IMA_APPRAISE_SUBMASK	(IMA_FILE_APPRAISE | IMA_MMAP_APPRAISE | \  				 IMA_BPRM_APPRAISE | IMA_READ_APPRAISE)  #define IMA_APPRAISED_SUBMASK	(IMA_FILE_APPRAISED | IMA_MMAP_APPRAISED | \  				 IMA_BPRM_APPRAISED | IMA_READ_APPRAISED) +/* iint cache atomic_flags */ +#define IMA_CHANGE_XATTR	0 +#define IMA_UPDATE_XATTR	1 +#define IMA_CHANGE_ATTR		2 +#define IMA_DIGSIG		3 +#define IMA_MUST_MEASURE	4 +  enum evm_ima_xattr_type {  	IMA_XATTR_DIGEST = 0x01,  	EVM_XATTR_HMAC,  	EVM_IMA_XATTR_DIGSIG,  	IMA_XATTR_DIGEST_NG, +	EVM_XATTR_PORTABLE_DIGSIG,  	IMA_XATTR_LAST  }; @@ -100,10 +111,12 @@ struct signature_v2_hdr {  /* integrity data associated with an inode */  struct integrity_iint_cache {  	struct rb_node rb_node;	/* rooted in integrity_iint_tree */ +	struct mutex mutex;	/* protects: version, flags, digest */  	struct inode *inode;	/* back pointer to inode in question */  	u64 version;		/* track inode changes */  	unsigned long flags;  	unsigned long measured_pcrs; +	unsigned long atomic_flags;  	enum integrity_status ima_file_status:4;  	enum integrity_status ima_mmap_status:4;  	enum integrity_status ima_bprm_status:4; diff --git a/security/keys/big_key.c b/security/keys/big_key.c index 929e14978c42..fa728f662a6f 100644 --- a/security/keys/big_key.c +++ b/security/keys/big_key.c @@ -22,6 +22,13 @@  #include <keys/big_key-type.h>  #include <crypto/aead.h> +struct big_key_buf { +	unsigned int		nr_pages; +	void			*virt; +	struct scatterlist	*sg; +	struct page		*pages[]; +}; +  /*   * Layout of key payload words.   */ @@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock);  /*   * Encrypt/decrypt big_key data   */ -static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key) +static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key)  {  	int ret; -	struct scatterlist sgio;  	struct aead_request *aead_req;  	/* We always use a zero nonce. The reason we can get away with this is  	 * because we're using a different randomly generated key for every @@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)  		return -ENOMEM;  	memset(zero_nonce, 0, sizeof(zero_nonce)); -	sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0)); -	aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce); +	aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce);  	aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);  	aead_request_set_ad(aead_req, 0); @@ -130,21 +135,81 @@ error:  }  /* + * Free up the buffer. + */ +static void big_key_free_buffer(struct big_key_buf *buf) +{ +	unsigned int i; + +	if (buf->virt) { +		memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE); +		vunmap(buf->virt); +	} + +	for (i = 0; i < buf->nr_pages; i++) +		if (buf->pages[i]) +			__free_page(buf->pages[i]); + +	kfree(buf); +} + +/* + * Allocate a buffer consisting of a set of pages with a virtual mapping + * applied over them. + */ +static void *big_key_alloc_buffer(size_t len) +{ +	struct big_key_buf *buf; +	unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; +	unsigned int i, l; + +	buf = kzalloc(sizeof(struct big_key_buf) + +		      sizeof(struct page) * npg + +		      sizeof(struct scatterlist) * npg, +		      GFP_KERNEL); +	if (!buf) +		return NULL; + +	buf->nr_pages = npg; +	buf->sg = (void *)(buf->pages + npg); +	sg_init_table(buf->sg, npg); + +	for (i = 0; i < buf->nr_pages; i++) { +		buf->pages[i] = alloc_page(GFP_KERNEL); +		if (!buf->pages[i]) +			goto nomem; + +		l = min_t(size_t, len, PAGE_SIZE); +		sg_set_page(&buf->sg[i], buf->pages[i], l, 0); +		len -= l; +	} + +	buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL); +	if (!buf->virt) +		goto nomem; + +	return buf; + +nomem: +	big_key_free_buffer(buf); +	return NULL; +} + +/*   * Preparse a big key   */  int big_key_preparse(struct key_preparsed_payload *prep)  { +	struct big_key_buf *buf;  	struct path *path = (struct path *)&prep->payload.data[big_key_path];  	struct file *file;  	u8 *enckey; -	u8 *data = NULL;  	ssize_t written; -	size_t datalen = prep->datalen; +	size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE;  	int ret; -	ret = -EINVAL;  	if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data) -		goto error; +		return -EINVAL;  	/* Set an arbitrary quota */  	prep->quotalen = 16; @@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep)  		 *  		 * File content is stored encrypted with randomly generated key.  		 */ -		size_t enclen = datalen + ENC_AUTHTAG_SIZE;  		loff_t pos = 0; -		data = kmalloc(enclen, GFP_KERNEL); -		if (!data) +		buf = big_key_alloc_buffer(enclen); +		if (!buf)  			return -ENOMEM; -		memcpy(data, prep->data, datalen); +		memcpy(buf->virt, prep->data, datalen);  		/* generate random key */  		enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL); @@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)  			goto err_enckey;  		/* encrypt aligned data */ -		ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey); +		ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey);  		if (ret)  			goto err_enckey; @@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)  			goto err_enckey;  		} -		written = kernel_write(file, data, enclen, &pos); +		written = kernel_write(file, buf->virt, enclen, &pos);  		if (written != enclen) {  			ret = written;  			if (written >= 0) @@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)  		*path = file->f_path;  		path_get(path);  		fput(file); -		kzfree(data); +		big_key_free_buffer(buf);  	} else {  		/* Just store the data in a buffer */  		void *data = kmalloc(datalen, GFP_KERNEL); @@ -220,7 +284,7 @@ err_fput:  err_enckey:  	kzfree(enckey);  error: -	kzfree(data); +	big_key_free_buffer(buf);  	return ret;  } @@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)  		return datalen;  	if (datalen > BIG_KEY_FILE_THRESHOLD) { +		struct big_key_buf *buf;  		struct path *path = (struct path *)&key->payload.data[big_key_path];  		struct file *file; -		u8 *data;  		u8 *enckey = (u8 *)key->payload.data[big_key_data];  		size_t enclen = datalen + ENC_AUTHTAG_SIZE;  		loff_t pos = 0; -		data = kmalloc(enclen, GFP_KERNEL); -		if (!data) +		buf = big_key_alloc_buffer(enclen); +		if (!buf)  			return -ENOMEM;  		file = dentry_open(path, O_RDONLY, current_cred()); @@ -316,26 +380,26 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)  		}  		/* read file to kernel and decrypt */ -		ret = kernel_read(file, data, enclen, &pos); +		ret = kernel_read(file, buf->virt, enclen, &pos);  		if (ret >= 0 && ret != enclen) {  			ret = -EIO;  			goto err_fput;  		} -		ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey); +		ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey);  		if (ret)  			goto err_fput;  		ret = datalen;  		/* copy decrypted data to user */ -		if (copy_to_user(buffer, data, datalen) != 0) +		if (copy_to_user(buffer, buf->virt, datalen) != 0)  			ret = -EFAULT;  err_fput:  		fput(file);  error: -		kzfree(data); +		big_key_free_buffer(buf);  	} else {  		ret = datalen;  		if (copy_to_user(buffer, key->payload.data[big_key_data], diff --git a/security/keys/keyring.c b/security/keys/keyring.c index d0bccebbd3b5..41bcf57e96f2 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -713,7 +713,6 @@ descend_to_keyring:  		 * doesn't contain any keyring pointers.  		 */  		shortcut = assoc_array_ptr_to_shortcut(ptr); -		smp_read_barrier_depends();  		if ((shortcut->index_key[0] & ASSOC_ARRAY_FAN_MASK) != 0)  			goto not_this_keyring; @@ -723,8 +722,6 @@ descend_to_keyring:  	}  	node = assoc_array_ptr_to_node(ptr); -	smp_read_barrier_depends(); -  	ptr = node->slots[0];  	if (!assoc_array_ptr_is_meta(ptr))  		goto begin_node; @@ -736,7 +733,6 @@ descend_to_node:  	kdebug("descend");  	if (assoc_array_ptr_is_shortcut(ptr)) {  		shortcut = assoc_array_ptr_to_shortcut(ptr); -		smp_read_barrier_depends();  		ptr = READ_ONCE(shortcut->next_node);  		BUG_ON(!assoc_array_ptr_is_node(ptr));  	} @@ -744,7 +740,6 @@ descend_to_node:  begin_node:  	kdebug("begin_node"); -	smp_read_barrier_depends();  	slot = 0;  ascend_to_node:  	/* Go through the slots in a node */ @@ -792,14 +787,12 @@ ascend_to_node:  	if (ptr && assoc_array_ptr_is_shortcut(ptr)) {  		shortcut = assoc_array_ptr_to_shortcut(ptr); -		smp_read_barrier_depends();  		ptr = READ_ONCE(shortcut->back_pointer);  		slot = shortcut->parent_slot;  	}  	if (!ptr)  		goto not_this_keyring;  	node = assoc_array_ptr_to_node(ptr); -	smp_read_barrier_depends();  	slot++;  	/* If we've ascended to the root (zero backpointer), we must have just diff --git a/security/keys/trusted.c b/security/keys/trusted.c index 98aa89ff7bfd..423776682025 100644 --- a/security/keys/trusted.c +++ b/security/keys/trusted.c @@ -355,13 +355,12 @@ out:   * For key specific tpm requests, we will generate and send our   * own TPM command packets using the drivers send function.   */ -static int trusted_tpm_send(const u32 chip_num, unsigned char *cmd, -			    size_t buflen) +static int trusted_tpm_send(unsigned char *cmd, size_t buflen)  {  	int rc;  	dump_tpm_buf(cmd); -	rc = tpm_send(chip_num, cmd, buflen); +	rc = tpm_send(NULL, cmd, buflen);  	dump_tpm_buf(cmd);  	if (rc > 0)  		/* Can't return positive return codes values to keyctl */ @@ -382,10 +381,10 @@ static int pcrlock(const int pcrnum)  	if (!capable(CAP_SYS_ADMIN))  		return -EPERM; -	ret = tpm_get_random(TPM_ANY_NUM, hash, SHA1_DIGEST_SIZE); +	ret = tpm_get_random(NULL, hash, SHA1_DIGEST_SIZE);  	if (ret != SHA1_DIGEST_SIZE)  		return ret; -	return tpm_pcr_extend(TPM_ANY_NUM, pcrnum, hash) ? -EINVAL : 0; +	return tpm_pcr_extend(NULL, pcrnum, hash) ? -EINVAL : 0;  }  /* @@ -398,7 +397,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,  	unsigned char ononce[TPM_NONCE_SIZE];  	int ret; -	ret = tpm_get_random(TPM_ANY_NUM, ononce, TPM_NONCE_SIZE); +	ret = tpm_get_random(NULL, ononce, TPM_NONCE_SIZE);  	if (ret != TPM_NONCE_SIZE)  		return ret; @@ -410,7 +409,7 @@ static int osap(struct tpm_buf *tb, struct osapsess *s,  	store32(tb, handle);  	storebytes(tb, ononce, TPM_NONCE_SIZE); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0)  		return ret; @@ -434,7 +433,7 @@ static int oiap(struct tpm_buf *tb, uint32_t *handle, unsigned char *nonce)  	store16(tb, TPM_TAG_RQU_COMMAND);  	store32(tb, TPM_OIAP_SIZE);  	store32(tb, TPM_ORD_OIAP); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0)  		return ret; @@ -493,7 +492,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,  	if (ret < 0)  		goto out; -	ret = tpm_get_random(TPM_ANY_NUM, td->nonceodd, TPM_NONCE_SIZE); +	ret = tpm_get_random(NULL, td->nonceodd, TPM_NONCE_SIZE);  	if (ret != TPM_NONCE_SIZE)  		goto out;  	ordinal = htonl(TPM_ORD_SEAL); @@ -542,7 +541,7 @@ static int tpm_seal(struct tpm_buf *tb, uint16_t keytype,  	store8(tb, cont);  	storebytes(tb, td->pubauth, SHA1_DIGEST_SIZE); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0)  		goto out; @@ -603,7 +602,7 @@ static int tpm_unseal(struct tpm_buf *tb,  	ordinal = htonl(TPM_ORD_UNSEAL);  	keyhndl = htonl(SRKHANDLE); -	ret = tpm_get_random(TPM_ANY_NUM, nonceodd, TPM_NONCE_SIZE); +	ret = tpm_get_random(NULL, nonceodd, TPM_NONCE_SIZE);  	if (ret != TPM_NONCE_SIZE) {  		pr_info("trusted_key: tpm_get_random failed (%d)\n", ret);  		return ret; @@ -635,7 +634,7 @@ static int tpm_unseal(struct tpm_buf *tb,  	store8(tb, cont);  	storebytes(tb, authdata2, SHA1_DIGEST_SIZE); -	ret = trusted_tpm_send(TPM_ANY_NUM, tb->data, MAX_BUF_SIZE); +	ret = trusted_tpm_send(tb->data, MAX_BUF_SIZE);  	if (ret < 0) {  		pr_info("trusted_key: authhmac failed (%d)\n", ret);  		return ret; @@ -748,7 +747,7 @@ static int getoptions(char *c, struct trusted_key_payload *pay,  	int i;  	int tpm2; -	tpm2 = tpm_is_tpm2(TPM_ANY_NUM); +	tpm2 = tpm_is_tpm2(NULL);  	if (tpm2 < 0)  		return tpm2; @@ -917,7 +916,7 @@ static struct trusted_key_options *trusted_options_alloc(void)  	struct trusted_key_options *options;  	int tpm2; -	tpm2 = tpm_is_tpm2(TPM_ANY_NUM); +	tpm2 = tpm_is_tpm2(NULL);  	if (tpm2 < 0)  		return NULL; @@ -967,7 +966,7 @@ static int trusted_instantiate(struct key *key,  	size_t key_len;  	int tpm2; -	tpm2 = tpm_is_tpm2(TPM_ANY_NUM); +	tpm2 = tpm_is_tpm2(NULL);  	if (tpm2 < 0)  		return tpm2; @@ -1008,7 +1007,7 @@ static int trusted_instantiate(struct key *key,  	switch (key_cmd) {  	case Opt_load:  		if (tpm2) -			ret = tpm_unseal_trusted(TPM_ANY_NUM, payload, options); +			ret = tpm_unseal_trusted(NULL, payload, options);  		else  			ret = key_unseal(payload, options);  		dump_payload(payload); @@ -1018,13 +1017,13 @@ static int trusted_instantiate(struct key *key,  		break;  	case Opt_new:  		key_len = payload->key_len; -		ret = tpm_get_random(TPM_ANY_NUM, payload->key, key_len); +		ret = tpm_get_random(NULL, payload->key, key_len);  		if (ret != key_len) {  			pr_info("trusted_key: key_create failed (%d)\n", ret);  			goto out;  		}  		if (tpm2) -			ret = tpm_seal_trusted(TPM_ANY_NUM, payload, options); +			ret = tpm_seal_trusted(NULL, payload, options);  		else  			ret = key_seal(payload, options);  		if (ret < 0) diff --git a/security/selinux/include/netlabel.h b/security/selinux/include/netlabel.h index 75686d53df07..e77a5e307955 100644 --- a/security/selinux/include/netlabel.h +++ b/security/selinux/include/netlabel.h @@ -19,8 +19,7 @@   * the GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program;  if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *   */ diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index aaba6677ee2e..2c297b995b16 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -22,8 +22,7 @@   * the GNU General Public License for more details.   *   * You should have received a copy of the GNU General Public License - * along with this program;  if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program.  If not, see <http://www.gnu.org/licenses/>.   *   */ diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 33cfe5d3d6cb..8900ea5cbabf 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -867,6 +867,9 @@ int security_bounded_transition(u32 old_sid, u32 new_sid)  	int index;  	int rc; +	if (!ss_initialized) +		return 0; +  	read_lock(&policy_rwlock);  	rc = -EINVAL; @@ -1413,27 +1416,25 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,  	if (!scontext_len)  		return -EINVAL; +	/* Copy the string to allow changes and ensure a NUL terminator */ +	scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags); +	if (!scontext2) +		return -ENOMEM; +  	if (!ss_initialized) {  		int i;  		for (i = 1; i < SECINITSID_NUM; i++) { -			if (!strcmp(initial_sid_to_string[i], scontext)) { +			if (!strcmp(initial_sid_to_string[i], scontext2)) {  				*sid = i; -				return 0; +				goto out;  			}  		}  		*sid = SECINITSID_KERNEL; -		return 0; +		goto out;  	}  	*sid = SECSID_NULL; -	/* Copy the string so that we can modify the copy as we parse it. */ -	scontext2 = kmalloc(scontext_len + 1, gfp_flags); -	if (!scontext2) -		return -ENOMEM; -	memcpy(scontext2, scontext, scontext_len); -	scontext2[scontext_len] = 0; -  	if (force) {  		/* Save another copy for storing in uninterpreted form */  		rc = -ENOMEM; diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 56e354fcdfc6..928188902901 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -452,7 +452,7 @@ int selinux_xfrm_postroute_last(u32 sk_sid, struct sk_buff *skb,  	if (dst) {  		struct dst_entry *iter; -		for (iter = dst; iter != NULL; iter = iter->child) { +		for (iter = dst; iter != NULL; iter = xfrm_dst_child(iter)) {  			struct xfrm_state *x = iter->xfrm;  			if (x && selinux_authorizable_xfrm(x)) diff --git a/security/smack/smack.h b/security/smack/smack.h index 6a71fc7831ab..f7db791fb566 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -321,6 +321,7 @@ struct smack_known *smk_import_entry(const char *, int);  void smk_insert_entry(struct smack_known *skp);  struct smack_known *smk_find_entry(const char *);  bool smack_privileged(int cap); +bool smack_privileged_cred(int cap, const struct cred *cred);  void smk_destroy_label_list(struct list_head *list);  /* diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index 1a3004189447..9a4c0ad46518 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c @@ -623,26 +623,24 @@ struct smack_known *smack_from_secid(const u32 secid)  LIST_HEAD(smack_onlycap_list);  DEFINE_MUTEX(smack_onlycap_lock); -/* +/** + * smack_privileged_cred - are all privilege requirements met by cred + * @cap: The requested capability + * @cred: the credential to use + *   * Is the task privileged and allowed to be privileged   * by the onlycap rule.   *   * Returns true if the task is allowed to be privileged, false if it's not.   */ -bool smack_privileged(int cap) +bool smack_privileged_cred(int cap, const struct cred *cred)  { -	struct smack_known *skp = smk_of_current(); +	struct task_smack *tsp = cred->security; +	struct smack_known *skp = tsp->smk_task;  	struct smack_known_list_elem *sklep;  	int rc; -	/* -	 * All kernel tasks are privileged -	 */ -	if (unlikely(current->flags & PF_KTHREAD)) -		return true; - -	rc = cap_capable(current_cred(), &init_user_ns, cap, -				SECURITY_CAP_AUDIT); +	rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT);  	if (rc)  		return false; @@ -662,3 +660,23 @@ bool smack_privileged(int cap)  	return false;  } + +/** + * smack_privileged - are all privilege requirements met + * @cap: The requested capability + * + * Is the task privileged and allowed to be privileged + * by the onlycap rule. + * + * Returns true if the task is allowed to be privileged, false if it's not. + */ +bool smack_privileged(int cap) +{ +	/* +	 * All kernel tasks are privileged +	 */ +	if (unlikely(current->flags & PF_KTHREAD)) +		return true; + +	return smack_privileged_cred(cap, current_cred()); +} diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 14cc7940b36d..03fdecba93bb 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2866,12 +2866,16 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,  #endif  #ifdef SMACK_IPV6_SECMARK_LABELING  	struct smack_known *rsp; -	struct socket_smack *ssp = sock->sk->sk_security; +	struct socket_smack *ssp;  #endif  	if (sock->sk == NULL)  		return 0; +#ifdef SMACK_IPV6_SECMARK_LABELING +	ssp = sock->sk->sk_security; +#endif +  	switch (sock->sk->sk_family) {  	case PF_INET:  		if (addrlen < sizeof(struct sockaddr_in)) @@ -4365,6 +4369,10 @@ static int smack_key_permission(key_ref_t key_ref,  	 */  	if (tkp == NULL)  		return -EACCES; + +	if (smack_privileged_cred(CAP_MAC_OVERRIDE, cred)) +		return 0; +  #ifdef CONFIG_AUDIT  	smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY);  	ad.a.u.key_struct.key = keyp->serial; diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 0f73fe30e37a..479b03a7a17e 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c @@ -456,14 +456,14 @@ void tomoyo_read_log(struct tomoyo_io_buffer *head)   * @file: Pointer to "struct file".   * @wait: Pointer to "poll_table". Maybe NULL.   * - * Returns POLLIN | POLLRDNORM when ready to read an audit log. + * Returns EPOLLIN | EPOLLRDNORM when ready to read an audit log.   */ -unsigned int tomoyo_poll_log(struct file *file, poll_table *wait) +__poll_t tomoyo_poll_log(struct file *file, poll_table *wait)  {  	if (tomoyo_log_count) -		return POLLIN | POLLRDNORM; +		return EPOLLIN | EPOLLRDNORM;  	poll_wait(file, &tomoyo_log_wait, wait);  	if (tomoyo_log_count) -		return POLLIN | POLLRDNORM; +		return EPOLLIN | EPOLLRDNORM;  	return 0;  } diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 25eed4b0b0e8..03923a138ef5 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -2116,17 +2116,17 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid   * @file: Pointer to "struct file".   * @wait: Pointer to "poll_table".   * - * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise. + * Returns EPOLLIN | EPOLLRDNORM when ready to read, 0 otherwise.   *   * Waits for access requests which violated policy in enforcing mode.   */ -static unsigned int tomoyo_poll_query(struct file *file, poll_table *wait) +static __poll_t tomoyo_poll_query(struct file *file, poll_table *wait)  {  	if (!list_empty(&tomoyo_query_list)) -		return POLLIN | POLLRDNORM; +		return EPOLLIN | EPOLLRDNORM;  	poll_wait(file, &tomoyo_query_wait, wait);  	if (!list_empty(&tomoyo_query_list)) -		return POLLIN | POLLRDNORM; +		return EPOLLIN | EPOLLRDNORM;  	return 0;  } @@ -2450,15 +2450,15 @@ int tomoyo_open_control(const u8 type, struct file *file)   * @file: Pointer to "struct file".   * @wait: Pointer to "poll_table". Maybe NULL.   * - * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, - * POLLOUT | POLLWRNORM otherwise. + * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write, + * EPOLLOUT | EPOLLWRNORM otherwise.   */ -unsigned int tomoyo_poll_control(struct file *file, poll_table *wait) +__poll_t tomoyo_poll_control(struct file *file, poll_table *wait)  {  	struct tomoyo_io_buffer *head = file->private_data;  	if (head->poll) -		return head->poll(file, wait) | POLLOUT | POLLWRNORM; -	return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; +		return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM; +	return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;  }  /** diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 7adccdd8e36d..539bcdd30bb8 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -789,7 +789,7 @@ struct tomoyo_acl_param {  struct tomoyo_io_buffer {  	void (*read) (struct tomoyo_io_buffer *);  	int (*write) (struct tomoyo_io_buffer *); -	unsigned int (*poll) (struct file *file, poll_table *wait); +	__poll_t (*poll) (struct file *file, poll_table *wait);  	/* Exclusive lock for this structure.   */  	struct mutex io_sem;  	char __user *read_user_buf; @@ -981,8 +981,8 @@ int tomoyo_path_number_perm(const u8 operation, const struct path *path,  			    unsigned long number);  int tomoyo_path_perm(const u8 operation, const struct path *path,  		     const char *target); -unsigned int tomoyo_poll_control(struct file *file, poll_table *wait); -unsigned int tomoyo_poll_log(struct file *file, poll_table *wait); +__poll_t tomoyo_poll_control(struct file *file, poll_table *wait); +__poll_t tomoyo_poll_log(struct file *file, poll_table *wait);  int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr,  				  int addr_len);  int tomoyo_socket_connect_permission(struct socket *sock, diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index 49393c2a3f8b..1d3d7e7a1f05 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -154,10 +154,10 @@ static int tomoyo_release(struct inode *inode, struct file *file)   * @file: Pointer to "struct file".   * @wait: Pointer to "poll_table". Maybe NULL.   * - * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, - * POLLOUT | POLLWRNORM otherwise. + * Returns EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM if ready to read/write, + * EPOLLOUT | EPOLLWRNORM otherwise.   */ -static unsigned int tomoyo_poll(struct file *file, poll_table *wait) +static __poll_t tomoyo_poll(struct file *file, poll_table *wait)  {  	return tomoyo_poll_control(file, wait);  } diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 8298e094f4f7..ffda91a4a1aa 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -250,15 +250,10 @@ int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3,  		} else {  			struct task_struct *tracer; -			rcu_read_lock(); -			tracer = find_task_by_vpid(arg2); -			if (tracer) -				get_task_struct(tracer); -			else +			tracer = find_get_task_by_vpid(arg2); +			if (!tracer) {  				rc = -EINVAL; -			rcu_read_unlock(); - -			if (tracer) { +			} else {  				rc = yama_ptracer_add(tracer, myself);  				put_task_struct(tracer);  			} |