From: Greg Kroah-Hartman Date: Fri, 5 May 2017 18:02:39 +0000 (-0700) Subject: 4.4-stable patches X-Git-Tag: v3.18.52~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=34147756efe9a2702a4310e6ab09ad36209b70d0;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches 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 --- 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 index 00000000000..2ce4895a831 --- /dev/null +++ b/queue-4.4/ext4-crypto-revalidate-dentry-after-adding-or-removing-the-key.patch @@ -0,0 +1,133 @@ +From 28b4c263961c47da84ed8b5be0b5116bad1133eb Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sun, 7 Feb 2016 19:35:05 -0500 +Subject: ext4 crypto: revalidate dentry after adding or removing the key + +From: Theodore Ts'o + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..d6df7ff938e --- /dev/null +++ b/queue-4.4/ext4-crypto-use-dget_parent-in-ext4_d_revalidate.patch @@ -0,0 +1,49 @@ +From 3d43bcfef5f0548845a425365011c499875491b0 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +Date: Sat, 26 Mar 2016 16:15:42 -0400 +Subject: ext4 crypto: use dget_parent() in ext4_d_revalidate() + +From: Theodore Ts'o + +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 +Signed-off-by: Theodore Ts'o +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..fdb3b104592 --- /dev/null +++ b/queue-4.4/ext4-fscrypto-avoid-rcu-lookup-in-d_revalidate.patch @@ -0,0 +1,42 @@ +From 03a8bb0e53d9562276045bdfcf2b5de2e4cff5a1 Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim +Date: Tue, 12 Apr 2016 16:05:36 -0700 +Subject: ext4/fscrypto: avoid RCU lookup in d_revalidate + +From: Jaegeuk Kim + +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 +Signed-off-by: Jaegeuk Kim +Cc: Theodore Ts'o +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + + #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 index 00000000000..ef8d76e9d70 --- /dev/null +++ b/queue-4.4/ext4-require-encryption-feature-for-ext4_ioc_set_encryption_policy.patch @@ -0,0 +1,38 @@ +From 9a200d075e5d05be1fcad4547a0f8aee4e2f9a04 Mon Sep 17 00:00:00 2001 +From: Richard Weinberger +Date: Fri, 30 Sep 2016 01:49:55 -0400 +Subject: ext4: require encryption feature for EXT4_IOC_SET_ENCRYPTION_POLICY + +From: Richard Weinberger + +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 +Signed-off-by: Theodore Ts'o +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..a9255382ea1 --- /dev/null +++ b/queue-4.4/nfsd-stricter-decoding-of-write-like-nfsv2-v3-ops.patch @@ -0,0 +1,60 @@ +From 13bf9fbff0e5e099e2b6f003a0ab8ae145436309 Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +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 + +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ää +Reported-by: Ari Kauppi +Reviewed-by: NeilBrown +Signed-off-by: J. Bruce Fields +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..ae2a3407ead --- /dev/null +++ b/queue-4.4/nfsd4-minor-nfsv2-v3-write-decoding-cleanup.patch @@ -0,0 +1,86 @@ +From db44bac41bbfc0c0d9dd943092d8bded3c9db19b Mon Sep 17 00:00:00 2001 +From: "J. Bruce Fields" +Date: Tue, 25 Apr 2017 16:21:34 -0400 +Subject: nfsd4: minor NFSv2/v3 write decoding cleanup + +From: J. Bruce Fields + +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 +Signed-off-by: Greg Kroah-Hartman + + +--- + 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; diff --git a/queue-4.4/series b/queue-4.4/series index ccb617667e3..e3b118c775a 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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