]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 29 Nov 2018 13:19:35 +0000 (14:19 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 29 Nov 2018 13:19:35 +0000 (14:19 +0100)
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

queue-4.14/evm-add-support-for-portable-signature-format.patch [new file with mode: 0644]
queue-4.14/ima-always-measure-and-audit-files-in-policy.patch [new file with mode: 0644]
queue-4.14/ima-re-initialize-iint-atomic_flags.patch [new file with mode: 0644]
queue-4.14/ima-re-introduce-own-integrity-cache-lock.patch [new file with mode: 0644]
queue-4.14/net-ieee802154-6lowpan-fix-frag-reassembly.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/evm-add-support-for-portable-signature-format.patch b/queue-4.14/evm-add-support-for-portable-signature-format.patch
new file mode 100644 (file)
index 0000000..2c11e6b
--- /dev/null
@@ -0,0 +1,331 @@
+From 50b977481fce90aa5fbda55e330b9d722733e358 Mon Sep 17 00:00:00 2001
+From: Matthew Garrett <mjg59@google.com>
+Date: Tue, 7 Nov 2017 07:17:42 -0800
+Subject: EVM: Add support for portable signature format
+
+From: Matthew Garrett <mjg59@google.com>
+
+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 <mjg59@google.com>
+Cc: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
+Cc: Mikhail Kurinnoi <viewizard@viewizard.com>
+Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Cc: Aditya Kali <adityakali@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.b[0],
+                                   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
+@@ -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";
+@@ -120,7 +120,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 */
+@@ -161,22 +162,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:
+@@ -277,7 +282,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)
+@@ -345,7 +350,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,
+@@ -422,6 +428,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
+@@ -230,7 +230,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.14/ima-always-measure-and-audit-files-in-policy.patch b/queue-4.14/ima-always-measure-and-audit-files-in-policy.patch
new file mode 100644 (file)
index 0000000..4e5521d
--- /dev/null
@@ -0,0 +1,188 @@
+From f3cc6b25dcc5616f0d5c720009b2ac66f97df2ff Mon Sep 17 00:00:00 2001
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Date: Sat, 17 Jun 2017 23:56:23 -0400
+Subject: ima: always measure and audit files in policy
+
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+
+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 <zohar@linux.vnet.ibm.com>
+Reviewed-by: Dmitry Kasatkin <dmitry.kasatkin@huawei.com>
+Cc: Aditya Kali <adityakali@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -199,42 +199,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;
+ }
+@@ -278,7 +295,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.14/ima-re-initialize-iint-atomic_flags.patch b/queue-4.14/ima-re-initialize-iint-atomic_flags.patch
new file mode 100644 (file)
index 0000000..5330c0b
--- /dev/null
@@ -0,0 +1,33 @@
+From e2598077dc6a26c9644393e5c21f22a90dbdccdb Mon Sep 17 00:00:00 2001
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Date: Tue, 23 Jan 2018 10:00:41 -0500
+Subject: ima: re-initialize iint->atomic_flags
+
+From: Mimi Zohar <zohar@linux.vnet.ibm.com>
+
+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 <zohar@linux.vnet.ibm.com>
+Signed-off-by: James Morris <jmorris@namei.org>
+Cc: Aditya Kali <adityakali@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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.14/ima-re-introduce-own-integrity-cache-lock.patch b/queue-4.14/ima-re-introduce-own-integrity-cache-lock.patch
new file mode 100644 (file)
index 0000000..8b20f0c
--- /dev/null
@@ -0,0 +1,358 @@
+From 0d73a55208e94fc9fb6deaeea61438cd3280d4c0 Mon Sep 17 00:00:00 2001
+From: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
+Date: Tue, 5 Dec 2017 21:06:34 +0200
+Subject: ima: re-introduce own integrity cache lock
+
+From: Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
+
+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 <dmitry.kasatkin@huawei.com>
+Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
+Cc: Aditya Kali <adityakali@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -251,6 +251,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
+@@ -269,7 +270,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,
+@@ -320,7 +321,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)
+@@ -330,7 +331,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));
+ }
+ /**
+@@ -353,16 +356,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);
+ }
+ /*
+@@ -391,12 +392,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.14/net-ieee802154-6lowpan-fix-frag-reassembly.patch b/queue-4.14/net-ieee802154-6lowpan-fix-frag-reassembly.patch
new file mode 100644 (file)
index 0000000..4c22379
--- /dev/null
@@ -0,0 +1,71 @@
+From f18fa5de5ba7f1d6650951502bb96a6e4715a948 Mon Sep 17 00:00:00 2001
+From: Alexander Aring <aring@mojatatu.com>
+Date: Fri, 20 Apr 2018 14:54:13 -0400
+Subject: net: ieee802154: 6lowpan: fix frag reassembly
+
+From: Alexander Aring <aring@mojatatu.com>
+
+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 <aring@mojatatu.com>
+Reported-by: Stefan Schmidt <stefan@osg.samsung.com>
+Signed-off-by: Stefan Schmidt <stefan@osg.samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -20,8 +20,8 @@ typedef unsigned __bitwise lowpan_rx_res
+ 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
+@@ -75,14 +75,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;
+@@ -372,7 +372,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)
index a28f65119232634ba03e547c669dcfc3e267a97c..900c0744294f1d69e138ad7886f705e6197f347e 100644 (file)
@@ -93,3 +93,8 @@ 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
 rcu-make-need_resched-respond-to-urgent-rcu-qs-needs.patch
+net-ieee802154-6lowpan-fix-frag-reassembly.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