From e9d2bfbf9876fe8445cf11d9820cee88826c131b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 29 Nov 2018 14:20:14 +0100 Subject: [PATCH] 4.9-stable patches added patches: evm-add-support-for-portable-signature-format.patch ima-always-measure-and-audit-files-in-policy.patch ima-re-initialize-iint-atomic_flags.patch ima-re-introduce-own-integrity-cache-lock.patch net-ieee802154-6lowpan-fix-frag-reassembly.patch revert-evm-translate-user-group-ids-relative-to-s_user_ns-when-computing-hmac.patch --- ...upport-for-portable-signature-format.patch | 331 ++++++++++++++++ ...ys-measure-and-audit-files-in-policy.patch | 188 +++++++++ .../ima-re-initialize-iint-atomic_flags.patch | 33 ++ ...e-introduce-own-integrity-cache-lock.patch | 358 ++++++++++++++++++ ...ee802154-6lowpan-fix-frag-reassembly.patch | 71 ++++ ...ive-to-s_user_ns-when-computing-hmac.patch | 51 +++ queue-4.9/series | 6 + 7 files changed, 1038 insertions(+) create mode 100644 queue-4.9/evm-add-support-for-portable-signature-format.patch create mode 100644 queue-4.9/ima-always-measure-and-audit-files-in-policy.patch create mode 100644 queue-4.9/ima-re-initialize-iint-atomic_flags.patch create mode 100644 queue-4.9/ima-re-introduce-own-integrity-cache-lock.patch create mode 100644 queue-4.9/net-ieee802154-6lowpan-fix-frag-reassembly.patch create mode 100644 queue-4.9/revert-evm-translate-user-group-ids-relative-to-s_user_ns-when-computing-hmac.patch diff --git a/queue-4.9/evm-add-support-for-portable-signature-format.patch b/queue-4.9/evm-add-support-for-portable-signature-format.patch new file mode 100644 index 00000000000..1ad47b2dd29 --- /dev/null +++ b/queue-4.9/evm-add-support-for-portable-signature-format.patch @@ -0,0 +1,331 @@ +From 50b977481fce90aa5fbda55e330b9d722733e358 Mon Sep 17 00:00:00 2001 +From: Matthew Garrett +Date: Tue, 7 Nov 2017 07:17:42 -0800 +Subject: EVM: Add support for portable signature format + +From: Matthew Garrett + +commit 50b977481fce90aa5fbda55e330b9d722733e358 upstream. + +The EVM signature includes the inode number and (optionally) the +filesystem UUID, making it impractical to ship EVM signatures in +packages. This patch adds a new portable format intended to allow +distributions to include EVM signatures. It is identical to the existing +format but hardcodes the inode and generation numbers to 0 and does not +include the filesystem UUID even if the kernel is configured to do so. + +Removing the inode means that the metadata and signature from one file +could be copied to another file without invalidating it. This is avoided +by ensuring that an IMA xattr is present during EVM validation. + +Portable signatures are intended to be immutable - ie, they will never +be transformed into HMACs. + +Based on earlier work by Dmitry Kasatkin and Mikhail Kurinnoi. + +Signed-off-by: Matthew Garrett +Cc: Dmitry Kasatkin +Cc: Mikhail Kurinnoi +Signed-off-by: Mimi Zohar +Cc: Aditya Kali +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/integrity.h | 1 + security/integrity/evm/evm.h | 2 + security/integrity/evm/evm_crypto.c | 75 +++++++++++++++++++++++++++++----- + security/integrity/evm/evm_main.c | 29 ++++++++----- + security/integrity/ima/ima_appraise.c | 4 + + security/integrity/integrity.h | 2 + 6 files changed, 92 insertions(+), 21 deletions(-) + +--- a/include/linux/integrity.h ++++ b/include/linux/integrity.h +@@ -14,6 +14,7 @@ + + enum integrity_status { + INTEGRITY_PASS = 0, ++ INTEGRITY_PASS_IMMUTABLE, + INTEGRITY_FAIL, + INTEGRITY_NOLABEL, + INTEGRITY_NOXATTRS, +--- a/security/integrity/evm/evm.h ++++ b/security/integrity/evm/evm.h +@@ -48,7 +48,7 @@ int evm_calc_hmac(struct dentry *dentry, + 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); +--- a/security/integrity/evm/evm_crypto.c ++++ b/security/integrity/evm/evm_crypto.c +@@ -139,7 +139,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; +@@ -150,8 +150,13 @@ static void hmac_add_misc(struct shash_d + } 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 +@@ -164,7 +169,8 @@ static void hmac_add_misc(struct shash_d + 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, + sizeof(inode->i_sb->s_uuid)); + crypto_shash_final(desc, digest); +@@ -190,6 +196,7 @@ static int evm_calc_hmac_or_hash(struct + char *xattr_value = NULL; + int error; + int size; ++ bool ima_present = false; + + if (!(inode->i_opflags & IOP_XATTR)) + return -EOPNOTSUPP; +@@ -200,11 +207,18 @@ static int evm_calc_hmac_or_hash(struct + + 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, +@@ -219,9 +233,14 @@ static int evm_calc_hmac_or_hash(struct + 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); +@@ -233,17 +252,45 @@ int evm_calc_hmac(struct dentry *dentry, + 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 + * +@@ -256,6 +303,16 @@ int evm_update_evmxattr(struct dentry *d + 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) { +@@ -281,7 +338,7 @@ int evm_init_hmac(struct inode *inode, c + } + + 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; + } +--- a/security/integrity/evm/evm_main.c ++++ b/security/integrity/evm/evm_main.c +@@ -29,7 +29,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"; +@@ -118,7 +118,8 @@ static enum integrity_status evm_verify_ + 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 */ +@@ -155,22 +156,26 @@ static enum integrity_status evm_verify_ + 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: +@@ -271,7 +276,7 @@ static enum integrity_status evm_verify_ + * 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) +@@ -339,7 +344,8 @@ int evm_inode_setxattr(struct dentry *de + 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, +@@ -416,6 +422,9 @@ void evm_inode_post_removexattr(struct d + /** + * 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) + { +--- a/security/integrity/ima/ima_appraise.c ++++ b/security/integrity/ima/ima_appraise.c +@@ -214,7 +214,9 @@ int ima_appraise_measurement(enum ima_ho + } + + 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"; +--- a/security/integrity/integrity.h ++++ b/security/integrity/integrity.h +@@ -33,6 +33,7 @@ + #define IMA_DIGSIG_REQUIRED 0x02000000 + #define IMA_PERMIT_DIRECTIO 0x04000000 + #define IMA_NEW_FILE 0x08000000 ++#define EVM_IMMUTABLE_DIGSIG 0x10000000 + + #define IMA_DO_MASK (IMA_MEASURE | IMA_APPRAISE | IMA_AUDIT | \ + IMA_APPRAISE_SUBMASK) +@@ -58,6 +59,7 @@ enum evm_ima_xattr_type { + EVM_XATTR_HMAC, + EVM_IMA_XATTR_DIGSIG, + IMA_XATTR_DIGEST_NG, ++ EVM_XATTR_PORTABLE_DIGSIG, + IMA_XATTR_LAST + }; + diff --git a/queue-4.9/ima-always-measure-and-audit-files-in-policy.patch b/queue-4.9/ima-always-measure-and-audit-files-in-policy.patch new file mode 100644 index 00000000000..04904d6817c --- /dev/null +++ b/queue-4.9/ima-always-measure-and-audit-files-in-policy.patch @@ -0,0 +1,188 @@ +From f3cc6b25dcc5616f0d5c720009b2ac66f97df2ff Mon Sep 17 00:00:00 2001 +From: Mimi Zohar +Date: Sat, 17 Jun 2017 23:56:23 -0400 +Subject: ima: always measure and audit files in policy + +From: Mimi Zohar + +commit f3cc6b25dcc5616f0d5c720009b2ac66f97df2ff upstream. + +All files matching a "measure" rule must be included in the IMA +measurement list, even when the file hash cannot be calculated. +Similarly, all files matching an "audit" rule must be audited, even when +the file hash can not be calculated. + +The file data hash field contained in the IMA measurement list template +data will contain 0's instead of the actual file hash digest. + +Note: +In general, adding, deleting or in anyway changing which files are +included in the IMA measurement list is not a good idea, as it might +result in not being able to unseal trusted keys sealed to a specific +TPM PCR value. This patch not only adds file measurements that were +not previously measured, but specifies that the file hash value for +these files will be 0's. + +As the IMA measurement list ordering is not consistent from one boot +to the next, it is unlikely that anyone is sealing keys based on the +IMA measurement list. Remote attestation servers should be able to +process these new measurement records, but might complain about +these unknown records. + +Signed-off-by: Mimi Zohar +Reviewed-by: Dmitry Kasatkin +Cc: Aditya Kali +Signed-off-by: Greg Kroah-Hartman + +--- + security/integrity/ima/ima_api.c | 69 ++++++++++++++++++++++-------------- + security/integrity/ima/ima_crypto.c | 10 +++++ + security/integrity/ima/ima_main.c | 9 ++-- + 3 files changed, 57 insertions(+), 31 deletions(-) + +--- a/security/integrity/ima/ima_api.c ++++ b/security/integrity/ima/ima_api.c +@@ -198,42 +198,59 @@ int ima_collect_measurement(struct integ + struct inode *inode = file_inode(file); + const char *filename = file->f_path.dentry->d_name.name; + int result = 0; ++ int length; ++ void *tmpbuf; ++ u64 i_version; + struct { + struct ima_digest_data hdr; + char digest[IMA_MAX_DIGEST_SIZE]; + } hash; + +- if (!(iint->flags & IMA_COLLECTED)) { +- u64 i_version = file_inode(file)->i_version; ++ if (iint->flags & IMA_COLLECTED) ++ goto out; + +- if (file->f_flags & O_DIRECT) { +- audit_cause = "failed(directio)"; +- result = -EACCES; +- goto out; +- } +- +- hash.hdr.algo = algo; +- +- result = (!buf) ? ima_calc_file_hash(file, &hash.hdr) : +- ima_calc_buffer_hash(buf, size, &hash.hdr); +- if (!result) { +- int length = sizeof(hash.hdr) + hash.hdr.length; +- void *tmpbuf = krealloc(iint->ima_hash, length, +- GFP_NOFS); +- if (tmpbuf) { +- iint->ima_hash = tmpbuf; +- memcpy(iint->ima_hash, &hash, length); +- iint->version = i_version; +- iint->flags |= IMA_COLLECTED; +- } else +- result = -ENOMEM; +- } ++ /* ++ * Dectecting file change is based on i_version. On filesystems ++ * which do not support i_version, support is limited to an initial ++ * measurement/appraisal/audit. ++ */ ++ i_version = file_inode(file)->i_version; ++ hash.hdr.algo = algo; ++ ++ /* Initialize hash digest to 0's in case of failure */ ++ memset(&hash.digest, 0, sizeof(hash.digest)); ++ ++ if (buf) ++ result = ima_calc_buffer_hash(buf, size, &hash.hdr); ++ else ++ result = ima_calc_file_hash(file, &hash.hdr); ++ ++ if (result && result != -EBADF && result != -EINVAL) ++ goto out; ++ ++ length = sizeof(hash.hdr) + hash.hdr.length; ++ tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS); ++ if (!tmpbuf) { ++ result = -ENOMEM; ++ goto out; + } ++ ++ iint->ima_hash = tmpbuf; ++ memcpy(iint->ima_hash, &hash, length); ++ iint->version = i_version; ++ ++ /* Possibly temporary failure due to type of read (eg. O_DIRECT) */ ++ if (!result) ++ iint->flags |= IMA_COLLECTED; + out: +- if (result) ++ if (result) { ++ if (file->f_flags & O_DIRECT) ++ audit_cause = "failed(directio)"; ++ + integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, + filename, "collect_data", audit_cause, + result, 0); ++ } + return result; + } + +@@ -277,7 +294,7 @@ void ima_store_measurement(struct integr + } + + result = ima_store_template(entry, violation, inode, filename, pcr); +- if (!result || result == -EEXIST) { ++ if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) { + iint->flags |= IMA_MEASURED; + iint->measured_pcrs |= (0x1 << pcr); + } +--- a/security/integrity/ima/ima_crypto.c ++++ b/security/integrity/ima/ima_crypto.c +@@ -443,6 +443,16 @@ int ima_calc_file_hash(struct file *file + loff_t i_size; + int rc; + ++ /* ++ * For consistency, fail file's opened with the O_DIRECT flag on ++ * filesystems mounted with/without DAX option. ++ */ ++ if (file->f_flags & O_DIRECT) { ++ hash->length = hash_digest_size[ima_hash_algo]; ++ hash->algo = ima_hash_algo; ++ return -EINVAL; ++ } ++ + i_size = i_size_read(file_inode(file)); + + if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { +--- a/security/integrity/ima/ima_main.c ++++ b/security/integrity/ima/ima_main.c +@@ -242,11 +242,8 @@ static int process_measurement(struct fi + hash_algo = ima_get_hash_algo(xattr_value, xattr_len); + + rc = ima_collect_measurement(iint, file, buf, size, hash_algo); +- if (rc != 0) { +- if (file->f_flags & O_DIRECT) +- rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES; ++ if (rc != 0 && rc != -EBADF && rc != -EINVAL) + goto out_digsig; +- } + + if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ + pathname = ima_d_path(&file->f_path, &pathbuf, filename); +@@ -254,12 +251,14 @@ static int process_measurement(struct fi + if (action & IMA_MEASURE) + ima_store_measurement(iint, file, pathname, + xattr_value, xattr_len, pcr); +- if (action & IMA_APPRAISE_SUBMASK) ++ if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) + rc = ima_appraise_measurement(func, iint, file, pathname, + xattr_value, xattr_len, opened); + 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) && + !(iint->flags & IMA_NEW_FILE)) diff --git a/queue-4.9/ima-re-initialize-iint-atomic_flags.patch b/queue-4.9/ima-re-initialize-iint-atomic_flags.patch new file mode 100644 index 00000000000..5330c0b8b95 --- /dev/null +++ b/queue-4.9/ima-re-initialize-iint-atomic_flags.patch @@ -0,0 +1,33 @@ +From e2598077dc6a26c9644393e5c21f22a90dbdccdb Mon Sep 17 00:00:00 2001 +From: Mimi Zohar +Date: Tue, 23 Jan 2018 10:00:41 -0500 +Subject: ima: re-initialize iint->atomic_flags + +From: Mimi Zohar + +commit e2598077dc6a26c9644393e5c21f22a90dbdccdb upstream. + +Intermittently security.ima is not being written for new files. This +patch re-initializes the new slab iint->atomic_flags field before +freeing it. + +Fixes: commit 0d73a55208e9 ("ima: re-introduce own integrity cache lock") +Signed-off-by: Mimi Zohar +Signed-off-by: James Morris +Cc: Aditya Kali +Signed-off-by: Greg Kroah-Hartman + +--- + security/integrity/iint.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/security/integrity/iint.c ++++ b/security/integrity/iint.c +@@ -74,6 +74,7 @@ static void iint_free(struct integrity_i + 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; diff --git a/queue-4.9/ima-re-introduce-own-integrity-cache-lock.patch b/queue-4.9/ima-re-introduce-own-integrity-cache-lock.patch new file mode 100644 index 00000000000..ff8959ded7b --- /dev/null +++ b/queue-4.9/ima-re-introduce-own-integrity-cache-lock.patch @@ -0,0 +1,358 @@ +From 0d73a55208e94fc9fb6deaeea61438cd3280d4c0 Mon Sep 17 00:00:00 2001 +From: Dmitry Kasatkin +Date: Tue, 5 Dec 2017 21:06:34 +0200 +Subject: ima: re-introduce own integrity cache lock + +From: Dmitry Kasatkin + +commit 0d73a55208e94fc9fb6deaeea61438cd3280d4c0 upstream. + +Before IMA appraisal was introduced, IMA was using own integrity cache +lock along with i_mutex. process_measurement and ima_file_free took +the iint->mutex first and then the i_mutex, while setxattr, chmod and +chown took the locks in reverse order. To resolve the potential deadlock, +i_mutex was moved to protect entire IMA functionality and the redundant +iint->mutex was eliminated. + +Solution was based on the assumption that filesystem code does not take +i_mutex further. But when file is opened with O_DIRECT flag, direct-io +implementation takes i_mutex and produces deadlock. Furthermore, certain +other filesystem operations, such as llseek, also take i_mutex. + +More recently some filesystems have replaced their filesystem specific +lock with the global i_rwsem to read a file. As a result, when IMA +attempts to calculate the file hash, reading the file attempts to take +the i_rwsem again. + +To resolve O_DIRECT related deadlock problem, this patch re-introduces +iint->mutex. But to eliminate the original chmod() related deadlock +problem, this patch eliminates the requirement for chmod hooks to take +the iint->mutex by introducing additional atomic iint->attr_flags to +indicate calling of the hooks. The allowed locking order is to take +the iint->mutex first and then the i_rwsem. + +Original flags were cleared in chmod(), setxattr() or removwxattr() +hooks and tested when file was closed or opened again. New atomic flags +are set or cleared in those hooks and tested to clear iint->flags on +close or on open. + +Atomic flags are following: +* IMA_CHANGE_ATTR - indicates that chATTR() was called (chmod, chown, + chgrp) and file attributes have changed. On file open, it causes IMA + to clear iint->flags to re-evaluate policy and perform IMA functions + again. +* IMA_CHANGE_XATTR - indicates that setxattr or removexattr was called + and extended attributes have changed. On file open, it causes IMA to + clear iint->flags IMA_DONE_MASK to re-appraise. +* IMA_UPDATE_XATTR - indicates that security.ima needs to be updated. + It is cleared if file policy changes and no update is needed. +* IMA_DIGSIG - indicates that file security.ima has signature and file + security.ima must not update to file has on file close. +* IMA_MUST_MEASURE - indicates the file is in the measurement policy. + +Fixes: Commit 6552321831dc ("xfs: remove i_iolock and use i_rwsem in +the VFS inode instead") + +Signed-off-by: Dmitry Kasatkin +Signed-off-by: Mimi Zohar +Cc: Aditya Kali +Signed-off-by: Greg Kroah-Hartman + +--- + security/integrity/iint.c | 2 + security/integrity/ima/ima_appraise.c | 27 ++++++------- + security/integrity/ima/ima_main.c | 70 +++++++++++++++++++++++----------- + security/integrity/integrity.h | 18 ++++++-- + 4 files changed, 77 insertions(+), 40 deletions(-) + +--- a/security/integrity/iint.c ++++ b/security/integrity/iint.c +@@ -155,12 +155,14 @@ static void init_once(void *foo) + memset(iint, 0, sizeof(*iint)); + iint->version = 0; + iint->flags = 0UL; ++ iint->atomic_flags = 0; + 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) +--- a/security/integrity/ima/ima_appraise.c ++++ b/security/integrity/ima/ima_appraise.c +@@ -234,6 +234,7 @@ int ima_appraise_measurement(enum ima_ho + 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 +@@ -252,7 +253,7 @@ int ima_appraise_measurement(enum ima_ho + 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, +@@ -303,7 +304,7 @@ void ima_update_xattr(struct integrity_i + 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) +@@ -313,7 +314,9 @@ void ima_update_xattr(struct integrity_i + if (rc < 0) + return; + ++ inode_lock(file_inode(file)); + ima_fix_xattr(dentry, iint); ++ inode_unlock(file_inode(file)); + } + + /** +@@ -336,16 +339,14 @@ void ima_inode_post_setattr(struct dentr + return; + + must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); ++ if (!must_appraise) ++ __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 (!must_appraise) ++ clear_bit(IMA_UPDATE_XATTR, &iint->atomic_flags); + } +- if (!must_appraise) +- __vfs_removexattr(dentry, XATTR_NAME_IMA); + } + + /* +@@ -374,12 +375,12 @@ static void ima_reset_appraise_flags(str + 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, +--- a/security/integrity/ima/ima_main.c ++++ b/security/integrity/ima/ima_main.c +@@ -99,10 +99,13 @@ static void ima_rdwr_violation_check(str + 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; + } +@@ -124,21 +127,24 @@ static void ima_check_last_writer(struct + 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) { ++ update = test_and_clear_bit(IMA_UPDATE_XATTR, ++ &iint->atomic_flags); + if ((iint->version != inode->i_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); + } + + /** +@@ -171,7 +177,7 @@ static int process_measurement(struct fi + 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; +@@ -202,17 +208,31 @@ static int process_measurement(struct fi + 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; +- } +- } ++ ++ 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, +@@ -230,7 +250,7 @@ static int process_measurement(struct fi + if (!action) { + if (must_appraise) + rc = ima_get_cache_status(iint, func); +- goto out_digsig; ++ goto out_locked; + } + + template_desc = ima_template_desc_current(); +@@ -243,7 +263,7 @@ static int process_measurement(struct fi + + 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); +@@ -251,26 +271,32 @@ static int process_measurement(struct fi + 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; + } + +--- a/security/integrity/integrity.h ++++ b/security/integrity/integrity.h +@@ -29,11 +29,10 @@ + /* 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 EVM_IMMUTABLE_DIGSIG 0x10000000 ++#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) +@@ -54,6 +53,13 @@ + #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, +@@ -102,10 +108,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/queue-4.9/net-ieee802154-6lowpan-fix-frag-reassembly.patch b/queue-4.9/net-ieee802154-6lowpan-fix-frag-reassembly.patch new file mode 100644 index 00000000000..ca2992c124b --- /dev/null +++ b/queue-4.9/net-ieee802154-6lowpan-fix-frag-reassembly.patch @@ -0,0 +1,71 @@ +From f18fa5de5ba7f1d6650951502bb96a6e4715a948 Mon Sep 17 00:00:00 2001 +From: Alexander Aring +Date: Fri, 20 Apr 2018 14:54:13 -0400 +Subject: net: ieee802154: 6lowpan: fix frag reassembly + +From: Alexander Aring + +commit f18fa5de5ba7f1d6650951502bb96a6e4715a948 upstream. + +This patch initialize stack variables which are used in +frag_lowpan_compare_key to zero. In my case there are padding bytes in the +structures ieee802154_addr as well in frag_lowpan_compare_key. Otherwise +the key variable contains random bytes. The result is that a compare of +two keys by memcmp works incorrect. + +Fixes: 648700f76b03 ("inet: frags: use rhashtables for reassembly units") +Signed-off-by: Alexander Aring +Reported-by: Stefan Schmidt +Signed-off-by: Stefan Schmidt +Signed-off-by: Greg Kroah-Hartman + +--- + net/ieee802154/6lowpan/6lowpan_i.h | 4 ++-- + net/ieee802154/6lowpan/reassembly.c | 14 +++++++------- + 2 files changed, 9 insertions(+), 9 deletions(-) + +--- a/net/ieee802154/6lowpan/6lowpan_i.h ++++ b/net/ieee802154/6lowpan/6lowpan_i.h +@@ -19,8 +19,8 @@ typedef unsigned __bitwise__ lowpan_rx_r + struct frag_lowpan_compare_key { + u16 tag; + u16 d_size; +- const struct ieee802154_addr src; +- const struct ieee802154_addr dst; ++ struct ieee802154_addr src; ++ struct ieee802154_addr dst; + }; + + /* Equivalent of ipv4 struct ipq +--- a/net/ieee802154/6lowpan/reassembly.c ++++ b/net/ieee802154/6lowpan/reassembly.c +@@ -74,14 +74,14 @@ fq_find(struct net *net, const struct lo + { + struct netns_ieee802154_lowpan *ieee802154_lowpan = + net_ieee802154_lowpan(net); +- struct frag_lowpan_compare_key key = { +- .tag = cb->d_tag, +- .d_size = cb->d_size, +- .src = *src, +- .dst = *dst, +- }; ++ struct frag_lowpan_compare_key key = {}; + struct inet_frag_queue *q; + ++ key.tag = cb->d_tag; ++ key.d_size = cb->d_size; ++ key.src = *src; ++ key.dst = *dst; ++ + q = inet_frag_find(&ieee802154_lowpan->frags, &key); + if (!q) + return NULL; +@@ -371,7 +371,7 @@ int lowpan_frag_rcv(struct sk_buff *skb, + struct lowpan_frag_queue *fq; + struct net *net = dev_net(skb->dev); + struct lowpan_802154_cb *cb = lowpan_802154_cb(skb); +- struct ieee802154_hdr hdr; ++ struct ieee802154_hdr hdr = {}; + int err; + + if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0) diff --git a/queue-4.9/revert-evm-translate-user-group-ids-relative-to-s_user_ns-when-computing-hmac.patch b/queue-4.9/revert-evm-translate-user-group-ids-relative-to-s_user_ns-when-computing-hmac.patch new file mode 100644 index 00000000000..4893a2ec4eb --- /dev/null +++ b/queue-4.9/revert-evm-translate-user-group-ids-relative-to-s_user_ns-when-computing-hmac.patch @@ -0,0 +1,51 @@ +From 19339c251607a3defc7f089511ce8561936fee45 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Fri, 2 Dec 2016 09:35:31 -0600 +Subject: Revert "evm: Translate user/group ids relative to s_user_ns when computing HMAC" + +From: Eric W. Biederman + +commit 19339c251607a3defc7f089511ce8561936fee45 upstream. + +This reverts commit 0b3c9761d1e405514a551ed24d3ea89aea26ce14. + +Seth Forshee writes: +> All right, I think 0b3c9761d1e405514a551ed24d3ea89aea26ce14 should be +> reverted then. EVM is a machine-local integrity mechanism, and so it +> makes sense that the signature would be based on the kernel's notion of +> the uid and not the filesystem's. + +I added a commment explaining why the EVM hmac needs to be in the +kernel's notion of uid and gid, not the filesystems to prevent +remounting the filesystem and gaining unwaranted trust in files. + +Acked-by: Seth Forshee +Signed-off-by: "Eric W. Biederman" +Cc: Aditya Kali +Signed-off-by: Greg Kroah-Hartman + +--- + security/integrity/evm/evm_crypto.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +--- a/security/integrity/evm/evm_crypto.c ++++ b/security/integrity/evm/evm_crypto.c +@@ -152,8 +152,16 @@ static void hmac_add_misc(struct shash_d + memset(&hmac_misc, 0, sizeof(hmac_misc)); + hmac_misc.ino = inode->i_ino; + hmac_misc.generation = inode->i_generation; +- hmac_misc.uid = from_kuid(inode->i_sb->s_user_ns, inode->i_uid); +- hmac_misc.gid = from_kgid(inode->i_sb->s_user_ns, inode->i_gid); ++ /* 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 ++ * where first they are written in an unprivileged fuse mount ++ * of a filesystem and then the system is tricked to mount the ++ * filesystem for real on next boot and trust it because ++ * everything is signed. ++ */ ++ hmac_misc.uid = from_kuid(&init_user_ns, inode->i_uid); ++ 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) diff --git a/queue-4.9/series b/queue-4.9/series index 979fc3c8dd7..bf8671b3655 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -84,3 +84,9 @@ sched-core-allow-__sched_setscheduler-in-interrupts-when-pi-is-not-used.patch namei-allow-restricted-o_creat-of-fifos-and-regular-files.patch lan78xx-read-mac-address-from-dt-if-present.patch s390-mm-check-for-valid-vma-before-zapping-in-gmap_discard.patch +net-ieee802154-6lowpan-fix-frag-reassembly.patch +revert-evm-translate-user-group-ids-relative-to-s_user_ns-when-computing-hmac.patch +ima-always-measure-and-audit-files-in-policy.patch +evm-add-support-for-portable-signature-format.patch +ima-re-introduce-own-integrity-cache-lock.patch +ima-re-initialize-iint-atomic_flags.patch -- 2.47.3