]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 May 2017 18:02:39 +0000 (11:02 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 May 2017 18:02:39 +0000 (11:02 -0700)
added patches:
ext4-crypto-revalidate-dentry-after-adding-or-removing-the-key.patch
ext4-crypto-use-dget_parent-in-ext4_d_revalidate.patch
ext4-fscrypto-avoid-rcu-lookup-in-d_revalidate.patch
ext4-require-encryption-feature-for-ext4_ioc_set_encryption_policy.patch
nfsd-stricter-decoding-of-write-like-nfsv2-v3-ops.patch
nfsd4-minor-nfsv2-v3-write-decoding-cleanup.patch

queue-4.4/ext4-crypto-revalidate-dentry-after-adding-or-removing-the-key.patch [new file with mode: 0644]
queue-4.4/ext4-crypto-use-dget_parent-in-ext4_d_revalidate.patch [new file with mode: 0644]
queue-4.4/ext4-fscrypto-avoid-rcu-lookup-in-d_revalidate.patch [new file with mode: 0644]
queue-4.4/ext4-require-encryption-feature-for-ext4_ioc_set_encryption_policy.patch [new file with mode: 0644]
queue-4.4/nfsd-stricter-decoding-of-write-like-nfsv2-v3-ops.patch [new file with mode: 0644]
queue-4.4/nfsd4-minor-nfsv2-v3-write-decoding-cleanup.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/ext4-crypto-revalidate-dentry-after-adding-or-removing-the-key.patch b/queue-4.4/ext4-crypto-revalidate-dentry-after-adding-or-removing-the-key.patch
new file mode 100644 (file)
index 0000000..2ce4895
--- /dev/null
@@ -0,0 +1,133 @@
+From 28b4c263961c47da84ed8b5be0b5116bad1133eb Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Sun, 7 Feb 2016 19:35:05 -0500
+Subject: ext4 crypto: revalidate dentry after adding or removing the key
+
+From: Theodore Ts'o <tytso@mit.edu>
+
+commit 28b4c263961c47da84ed8b5be0b5116bad1133eb upstream.
+
+Add a validation check for dentries for encrypted directory to make
+sure we're not caching stale data after a key has been added or removed.
+
+Also check to make sure that status of the encryption key is updated
+when readdir(2) is executed.
+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/crypto.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ fs/ext4/dir.c    |    6 ++++++
+ fs/ext4/ext4.h   |    1 +
+ fs/ext4/namei.c  |   18 ++++++++++++++++++
+ 4 files changed, 75 insertions(+)
+
+--- a/fs/ext4/crypto.c
++++ b/fs/ext4/crypto.c
+@@ -469,3 +469,53 @@ uint32_t ext4_validate_encryption_key_si
+               return size;
+       return 0;
+ }
++
++/*
++ * Validate dentries for encrypted directories to make sure we aren't
++ * potentially caching stale data after a key has been added or
++ * removed.
++ */
++static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags)
++{
++      struct inode *dir = d_inode(dentry->d_parent);
++      struct ext4_crypt_info *ci = EXT4_I(dir)->i_crypt_info;
++      int dir_has_key, cached_with_key;
++
++      if (!ext4_encrypted_inode(dir))
++              return 0;
++
++      /* this should eventually be an flag in d_flags */
++      cached_with_key = dentry->d_fsdata != NULL;
++      dir_has_key = (ci != NULL);
++
++      /*
++       * If the dentry was cached without the key, and it is a
++       * negative dentry, it might be a valid name.  We can't check
++       * if the key has since been made available due to locking
++       * reasons, so we fail the validation so ext4_lookup() can do
++       * this check.
++       *
++       * We also fail the validation if the dentry was created with
++       * the key present, but we no longer have the key, or vice versa.
++       */
++      if ((!cached_with_key && d_is_negative(dentry)) ||
++          (!cached_with_key && dir_has_key) ||
++          (cached_with_key && !dir_has_key)) {
++#if 0                         /* Revalidation debug */
++              char buf[80];
++              char *cp = simple_dname(dentry, buf, sizeof(buf));
++
++              if (IS_ERR(cp))
++                      cp = (char *) "???";
++              pr_err("revalidate: %s %p %d %d %d\n", cp, dentry->d_fsdata,
++                     cached_with_key, d_is_negative(dentry),
++                     dir_has_key);
++#endif
++              return 0;
++      }
++      return 1;
++}
++
++const struct dentry_operations ext4_encrypted_d_ops = {
++      .d_revalidate = ext4_d_revalidate,
++};
+--- a/fs/ext4/dir.c
++++ b/fs/ext4/dir.c
+@@ -111,6 +111,12 @@ static int ext4_readdir(struct file *fil
+       int dir_has_error = 0;
+       struct ext4_str fname_crypto_str = {.name = NULL, .len = 0};
++      if (ext4_encrypted_inode(inode)) {
++              err = ext4_get_encryption_info(inode);
++              if (err && err != -ENOKEY)
++                      return err;
++      }
++
+       if (is_dx_dir(inode)) {
+               err = ext4_dx_readdir(file, ctx);
+               if (err != ERR_BAD_DX_DIR) {
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -2268,6 +2268,7 @@ struct page *ext4_encrypt(struct inode *
+                         struct page *plaintext_page);
+ int ext4_decrypt(struct page *page);
+ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex);
++extern const struct dentry_operations ext4_encrypted_d_ops;
+ #ifdef CONFIG_EXT4_FS_ENCRYPTION
+ int ext4_init_crypto(void);
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -1557,6 +1557,24 @@ static struct dentry *ext4_lookup(struct
+       struct ext4_dir_entry_2 *de;
+       struct buffer_head *bh;
++       if (ext4_encrypted_inode(dir)) {
++               int res = ext4_get_encryption_info(dir);
++
++              /*
++               * This should be a properly defined flag for
++               * dentry->d_flags when we uplift this to the VFS.
++               * d_fsdata is set to (void *) 1 if if the dentry is
++               * created while the directory was encrypted and we
++               * don't have access to the key.
++               */
++             dentry->d_fsdata = NULL;
++             if (ext4_encryption_info(dir))
++                     dentry->d_fsdata = (void *) 1;
++             d_set_d_op(dentry, &ext4_encrypted_d_ops);
++             if (res && res != -ENOKEY)
++                     return ERR_PTR(res);
++       }
++
+       if (dentry->d_name.len > EXT4_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
diff --git a/queue-4.4/ext4-crypto-use-dget_parent-in-ext4_d_revalidate.patch b/queue-4.4/ext4-crypto-use-dget_parent-in-ext4_d_revalidate.patch
new file mode 100644 (file)
index 0000000..d6df7ff
--- /dev/null
@@ -0,0 +1,49 @@
+From 3d43bcfef5f0548845a425365011c499875491b0 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Sat, 26 Mar 2016 16:15:42 -0400
+Subject: ext4 crypto: use dget_parent() in ext4_d_revalidate()
+
+From: Theodore Ts'o <tytso@mit.edu>
+
+commit 3d43bcfef5f0548845a425365011c499875491b0 upstream.
+
+This avoids potential problems caused by a race where the inode gets
+renamed out from its parent directory and the parent directory is
+deleted while ext4_d_revalidate() is running.
+
+Fixes: 28b4c263961c
+Reported-by: Al Viro <viro@ZenIV.linux.org.uk>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/crypto.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/fs/ext4/crypto.c
++++ b/fs/ext4/crypto.c
+@@ -477,16 +477,21 @@ uint32_t ext4_validate_encryption_key_si
+  */
+ static int ext4_d_revalidate(struct dentry *dentry, unsigned int flags)
+ {
+-      struct inode *dir = d_inode(dentry->d_parent);
+-      struct ext4_crypt_info *ci = EXT4_I(dir)->i_crypt_info;
++      struct dentry *dir;
++      struct ext4_crypt_info *ci;
+       int dir_has_key, cached_with_key;
+-      if (!ext4_encrypted_inode(dir))
++      dir = dget_parent(dentry);
++      if (!ext4_encrypted_inode(d_inode(dir))) {
++              dput(dir);
+               return 0;
++      }
++      ci = EXT4_I(d_inode(dir))->i_crypt_info;
+       /* this should eventually be an flag in d_flags */
+       cached_with_key = dentry->d_fsdata != NULL;
+       dir_has_key = (ci != NULL);
++      dput(dir);
+       /*
+        * If the dentry was cached without the key, and it is a
diff --git a/queue-4.4/ext4-fscrypto-avoid-rcu-lookup-in-d_revalidate.patch b/queue-4.4/ext4-fscrypto-avoid-rcu-lookup-in-d_revalidate.patch
new file mode 100644 (file)
index 0000000..fdb3b10
--- /dev/null
@@ -0,0 +1,42 @@
+From 03a8bb0e53d9562276045bdfcf2b5de2e4cff5a1 Mon Sep 17 00:00:00 2001
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Tue, 12 Apr 2016 16:05:36 -0700
+Subject: ext4/fscrypto: avoid RCU lookup in d_revalidate
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 03a8bb0e53d9562276045bdfcf2b5de2e4cff5a1 upstream.
+
+As Al pointed, d_revalidate should return RCU lookup before using d_inode.
+This was originally introduced by:
+commit 34286d666230 ("fs: rcu-walk aware d_revalidate method").
+
+Reported-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+Cc: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ext4/crypto.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/fs/ext4/crypto.c
++++ b/fs/ext4/crypto.c
+@@ -34,6 +34,7 @@
+ #include <linux/random.h>
+ #include <linux/scatterlist.h>
+ #include <linux/spinlock_types.h>
++#include <linux/namei.h>
+ #include "ext4_extents.h"
+ #include "xattr.h"
+@@ -481,6 +482,9 @@ static int ext4_d_revalidate(struct dent
+       struct ext4_crypt_info *ci;
+       int dir_has_key, cached_with_key;
++      if (flags & LOOKUP_RCU)
++              return -ECHILD;
++
+       dir = dget_parent(dentry);
+       if (!ext4_encrypted_inode(d_inode(dir))) {
+               dput(dir);
diff --git a/queue-4.4/ext4-require-encryption-feature-for-ext4_ioc_set_encryption_policy.patch b/queue-4.4/ext4-require-encryption-feature-for-ext4_ioc_set_encryption_policy.patch
new file mode 100644 (file)
index 0000000..ef8d76e
--- /dev/null
@@ -0,0 +1,38 @@
+From 9a200d075e5d05be1fcad4547a0f8aee4e2f9a04 Mon Sep 17 00:00:00 2001
+From: Richard Weinberger <richard@nod.at>
+Date: Fri, 30 Sep 2016 01:49:55 -0400
+Subject: ext4: require encryption feature for EXT4_IOC_SET_ENCRYPTION_POLICY
+
+From: Richard Weinberger <richard@nod.at>
+
+commit 9a200d075e5d05be1fcad4547a0f8aee4e2f9a04 upstream.
+
+...otherwise an user can enable encryption for certain files even
+when the filesystem is unable to support it.
+Such a case would be a filesystem created by mkfs.ext4's default
+settings, 1KiB block size. Ext4 supports encyption only when block size
+is equal to PAGE_SIZE.
+But this constraint is only checked when the encryption feature flag
+is set.
+
+Signed-off-by: Richard Weinberger <richard@nod.at>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/ioctl.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/ext4/ioctl.c
++++ b/fs/ext4/ioctl.c
+@@ -622,6 +622,9 @@ resizefs_out:
+               struct ext4_encryption_policy policy;
+               int err = 0;
++              if (!ext4_has_feature_encrypt(sb))
++                      return -EOPNOTSUPP;
++
+               if (copy_from_user(&policy,
+                                  (struct ext4_encryption_policy __user *)arg,
+                                  sizeof(policy))) {
diff --git a/queue-4.4/nfsd-stricter-decoding-of-write-like-nfsv2-v3-ops.patch b/queue-4.4/nfsd-stricter-decoding-of-write-like-nfsv2-v3-ops.patch
new file mode 100644 (file)
index 0000000..a925538
--- /dev/null
@@ -0,0 +1,60 @@
+From 13bf9fbff0e5e099e2b6f003a0ab8ae145436309 Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Fri, 21 Apr 2017 15:26:30 -0400
+Subject: nfsd: stricter decoding of write-like NFSv2/v3 ops
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: J. Bruce Fields <bfields@redhat.com>
+
+commit 13bf9fbff0e5e099e2b6f003a0ab8ae145436309 upstream.
+
+The NFSv2/v3 code does not systematically check whether we decode past
+the end of the buffer.  This generally appears to be harmless, but there
+are a few places where we do arithmetic on the pointers involved and
+don't account for the possibility that a length could be negative.  Add
+checks to catch these.
+
+Reported-by: Tuomas Haanpää <thaan@synopsys.com>
+Reported-by: Ari Kauppi <ari@synopsys.com>
+Reviewed-by: NeilBrown <neilb@suse.com>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/nfs3xdr.c |    4 ++++
+ fs/nfsd/nfsxdr.c  |    2 ++
+ 2 files changed, 6 insertions(+)
+
+--- a/fs/nfsd/nfs3xdr.c
++++ b/fs/nfsd/nfs3xdr.c
+@@ -368,6 +368,8 @@ nfs3svc_decode_writeargs(struct svc_rqst
+       args->count = ntohl(*p++);
+       args->stable = ntohl(*p++);
+       len = args->len = ntohl(*p++);
++      if ((void *)p > head->iov_base + head->iov_len)
++              return 0;
+       /*
+        * The count must equal the amount of data passed.
+        */
+@@ -471,6 +473,8 @@ nfs3svc_decode_symlinkargs(struct svc_rq
+       /* first copy and check from the first page */
+       old = (char*)p;
+       vec = &rqstp->rq_arg.head[0];
++      if ((void *)old > vec->iov_base + vec->iov_len)
++              return 0;
+       avail = vec->iov_len - (old - (char*)vec->iov_base);
+       while (len && avail && *old) {
+               *new++ = *old++;
+--- a/fs/nfsd/nfsxdr.c
++++ b/fs/nfsd/nfsxdr.c
+@@ -302,6 +302,8 @@ nfssvc_decode_writeargs(struct svc_rqst
+        * bytes.
+        */
+       hdr = (void*)p - head->iov_base;
++      if (hdr > head->iov_len)
++              return 0;
+       dlen = head->iov_len + rqstp->rq_arg.page_len - hdr;
+       /*
diff --git a/queue-4.4/nfsd4-minor-nfsv2-v3-write-decoding-cleanup.patch b/queue-4.4/nfsd4-minor-nfsv2-v3-write-decoding-cleanup.patch
new file mode 100644 (file)
index 0000000..ae2a340
--- /dev/null
@@ -0,0 +1,86 @@
+From db44bac41bbfc0c0d9dd943092d8bded3c9db19b Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Tue, 25 Apr 2017 16:21:34 -0400
+Subject: nfsd4: minor NFSv2/v3 write decoding cleanup
+
+From: J. Bruce Fields <bfields@redhat.com>
+
+commit db44bac41bbfc0c0d9dd943092d8bded3c9db19b upstream.
+
+Use a couple shortcuts that will simplify a following bugfix.
+
+(Minor backporting required to account for a change from f34b95689d2c
+"The NFSv2/NFSv3 server does not handle zero length WRITE requests
+correctly".)
+
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ fs/nfsd/nfs3xdr.c |    8 ++++----
+ fs/nfsd/nfsxdr.c  |    8 ++++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/fs/nfsd/nfs3xdr.c
++++ b/fs/nfsd/nfs3xdr.c
+@@ -358,6 +358,7 @@ nfs3svc_decode_writeargs(struct svc_rqst
+ {
+       unsigned int len, v, hdr, dlen;
+       u32 max_blocksize = svc_max_payload(rqstp);
++      struct kvec *head = rqstp->rq_arg.head;
+       p = decode_fh(p, &args->fh);
+       if (!p)
+@@ -377,9 +378,8 @@ nfs3svc_decode_writeargs(struct svc_rqst
+        * Check to make sure that we got the right number of
+        * bytes.
+        */
+-      hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
+-      dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+-              - hdr;
++      hdr = (void*)p - head->iov_base;
++      dlen = head->iov_len + rqstp->rq_arg.page_len - hdr;
+       /*
+        * Round the length of the data which was specified up to
+        * the next multiple of XDR units and then compare that
+@@ -396,7 +396,7 @@ nfs3svc_decode_writeargs(struct svc_rqst
+               len = args->len = max_blocksize;
+       }
+       rqstp->rq_vec[0].iov_base = (void*)p;
+-      rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
++      rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
+       v = 0;
+       while (len > rqstp->rq_vec[v].iov_len) {
+               len -= rqstp->rq_vec[v].iov_len;
+--- a/fs/nfsd/nfsxdr.c
++++ b/fs/nfsd/nfsxdr.c
+@@ -280,6 +280,7 @@ nfssvc_decode_writeargs(struct svc_rqst
+                                       struct nfsd_writeargs *args)
+ {
+       unsigned int len, hdr, dlen;
++      struct kvec *head = rqstp->rq_arg.head;
+       int v;
+       p = decode_fh(p, &args->fh);
+@@ -300,9 +301,8 @@ nfssvc_decode_writeargs(struct svc_rqst
+        * Check to make sure that we got the right number of
+        * bytes.
+        */
+-      hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
+-      dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
+-              - hdr;
++      hdr = (void*)p - head->iov_base;
++      dlen = head->iov_len + rqstp->rq_arg.page_len - hdr;
+       /*
+        * Round the length of the data which was specified up to
+@@ -316,7 +316,7 @@ nfssvc_decode_writeargs(struct svc_rqst
+               return 0;
+       rqstp->rq_vec[0].iov_base = (void*)p;
+-      rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
++      rqstp->rq_vec[0].iov_len = head->iov_len - hdr;
+       v = 0;
+       while (len > rqstp->rq_vec[v].iov_len) {
+               len -= rqstp->rq_vec[v].iov_len;
index ccb617667e3bc73bd1fce051d078935645925866..e3b118c775a13ecdc49d91b7b430f70ab9f6ade4 100644 (file)
@@ -12,3 +12,9 @@ scsi-cxlflash-improve-eeh-recovery-time.patch
 netlink-allow-direct-reclaim-for-fallback-allocation.patch
 ib-qib-rename-bits_per_page-to-rvt_bits_per_page.patch
 ib-ehca-fix-maybe-uninitialized-warnings.patch
+ext4-require-encryption-feature-for-ext4_ioc_set_encryption_policy.patch
+ext4-crypto-revalidate-dentry-after-adding-or-removing-the-key.patch
+ext4-crypto-use-dget_parent-in-ext4_d_revalidate.patch
+ext4-fscrypto-avoid-rcu-lookup-in-d_revalidate.patch
+nfsd4-minor-nfsv2-v3-write-decoding-cleanup.patch
+nfsd-stricter-decoding-of-write-like-nfsv2-v3-ops.patch