]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 May 2017 10:22:46 +0000 (12:22 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 23 May 2017 10:22:46 +0000 (12:22 +0200)
added patches:
ext4-crypto-don-t-let-data-integrity-writebacks-fail-with-enomem.patch
ext4-crypto-fix-some-error-handling.patch
f2fs-check-entire-encrypted-bigname-when-finding-a-dentry.patch
fscrypt-avoid-collisions-when-presenting-long-encrypted-filenames.patch
fscrypt-fix-context-consistency-check-when-key-s-unavailable.patch
net-qmi_wwan-add-simcom-7230e.patch

queue-4.4/ext4-crypto-don-t-let-data-integrity-writebacks-fail-with-enomem.patch [new file with mode: 0644]
queue-4.4/ext4-crypto-fix-some-error-handling.patch [new file with mode: 0644]
queue-4.4/f2fs-check-entire-encrypted-bigname-when-finding-a-dentry.patch [new file with mode: 0644]
queue-4.4/fscrypt-avoid-collisions-when-presenting-long-encrypted-filenames.patch [new file with mode: 0644]
queue-4.4/fscrypt-fix-context-consistency-check-when-key-s-unavailable.patch [new file with mode: 0644]
queue-4.4/net-qmi_wwan-add-simcom-7230e.patch [new file with mode: 0644]
queue-4.4/series

diff --git a/queue-4.4/ext4-crypto-don-t-let-data-integrity-writebacks-fail-with-enomem.patch b/queue-4.4/ext4-crypto-don-t-let-data-integrity-writebacks-fail-with-enomem.patch
new file mode 100644 (file)
index 0000000..db0afe0
--- /dev/null
@@ -0,0 +1,216 @@
+From c9af28fdd44922a6c10c9f8315718408af98e315 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Sat, 26 Mar 2016 16:14:34 -0400
+Subject: ext4 crypto: don't let data integrity writebacks fail with ENOMEM
+
+From: Theodore Ts'o <tytso@mit.edu>
+
+commit c9af28fdd44922a6c10c9f8315718408af98e315 upstream.
+
+We don't want the writeback triggered from the journal commit (in
+data=writeback mode) to cause the journal to abort due to
+generic_writepages() returning an ENOMEM error.  In addition, if
+fsync() fails with ENOMEM, most applications will probably not do the
+right thing.
+
+So if we are doing a data integrity sync, and ext4_encrypt() returns
+ENOMEM, we will submit any queued I/O to date, and then retry the
+allocation using GFP_NOFAIL.
+
+Google-Bug-Id: 27641567
+
+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   |   37 +++++++++++++++++++++----------------
+ fs/ext4/ext4.h     |    6 ++++--
+ fs/ext4/page-io.c  |   14 +++++++++++++-
+ fs/ext4/readpage.c |    2 +-
+ 4 files changed, 39 insertions(+), 20 deletions(-)
+
+--- a/fs/ext4/crypto.c
++++ b/fs/ext4/crypto.c
+@@ -94,7 +94,8 @@ void ext4_release_crypto_ctx(struct ext4
+  * Return: An allocated and initialized encryption context on success; error
+  * value or NULL otherwise.
+  */
+-struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode)
++struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
++                                          gfp_t gfp_flags)
+ {
+       struct ext4_crypto_ctx *ctx = NULL;
+       int res = 0;
+@@ -121,7 +122,7 @@ struct ext4_crypto_ctx *ext4_get_crypto_
+               list_del(&ctx->free_list);
+       spin_unlock_irqrestore(&ext4_crypto_ctx_lock, flags);
+       if (!ctx) {
+-              ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, GFP_NOFS);
++              ctx = kmem_cache_zalloc(ext4_crypto_ctx_cachep, gfp_flags);
+               if (!ctx) {
+                       res = -ENOMEM;
+                       goto out;
+@@ -258,7 +259,8 @@ static int ext4_page_crypto(struct inode
+                           ext4_direction_t rw,
+                           pgoff_t index,
+                           struct page *src_page,
+-                          struct page *dest_page)
++                          struct page *dest_page,
++                          gfp_t gfp_flags)
+ {
+       u8 xts_tweak[EXT4_XTS_TWEAK_SIZE];
+@@ -269,7 +271,7 @@ static int ext4_page_crypto(struct inode
+       struct crypto_ablkcipher *tfm = ci->ci_ctfm;
+       int res = 0;
+-      req = ablkcipher_request_alloc(tfm, GFP_NOFS);
++      req = ablkcipher_request_alloc(tfm, gfp_flags);
+       if (!req) {
+               printk_ratelimited(KERN_ERR
+                                  "%s: crypto_request_alloc() failed\n",
+@@ -310,9 +312,10 @@ static int ext4_page_crypto(struct inode
+       return 0;
+ }
+-static struct page *alloc_bounce_page(struct ext4_crypto_ctx *ctx)
++static struct page *alloc_bounce_page(struct ext4_crypto_ctx *ctx,
++                                    gfp_t gfp_flags)
+ {
+-      ctx->w.bounce_page = mempool_alloc(ext4_bounce_page_pool, GFP_NOWAIT);
++      ctx->w.bounce_page = mempool_alloc(ext4_bounce_page_pool, gfp_flags);
+       if (ctx->w.bounce_page == NULL)
+               return ERR_PTR(-ENOMEM);
+       ctx->flags |= EXT4_WRITE_PATH_FL;
+@@ -335,7 +338,8 @@ static struct page *alloc_bounce_page(st
+  * error value or NULL.
+  */
+ struct page *ext4_encrypt(struct inode *inode,
+-                        struct page *plaintext_page)
++                        struct page *plaintext_page,
++                        gfp_t gfp_flags)
+ {
+       struct ext4_crypto_ctx *ctx;
+       struct page *ciphertext_page = NULL;
+@@ -343,17 +347,17 @@ struct page *ext4_encrypt(struct inode *
+       BUG_ON(!PageLocked(plaintext_page));
+-      ctx = ext4_get_crypto_ctx(inode);
++      ctx = ext4_get_crypto_ctx(inode, gfp_flags);
+       if (IS_ERR(ctx))
+               return (struct page *) ctx;
+       /* The encryption operation will require a bounce page. */
+-      ciphertext_page = alloc_bounce_page(ctx);
++      ciphertext_page = alloc_bounce_page(ctx, gfp_flags);
+       if (IS_ERR(ciphertext_page))
+               goto errout;
+       ctx->w.control_page = plaintext_page;
+       err = ext4_page_crypto(inode, EXT4_ENCRYPT, plaintext_page->index,
+-                             plaintext_page, ciphertext_page);
++                             plaintext_page, ciphertext_page, gfp_flags);
+       if (err) {
+               ciphertext_page = ERR_PTR(err);
+       errout:
+@@ -381,8 +385,8 @@ int ext4_decrypt(struct page *page)
+ {
+       BUG_ON(!PageLocked(page));
+-      return ext4_page_crypto(page->mapping->host,
+-                              EXT4_DECRYPT, page->index, page, page);
++      return ext4_page_crypto(page->mapping->host, EXT4_DECRYPT,
++                              page->index, page, page, GFP_NOFS);
+ }
+ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
+@@ -403,11 +407,11 @@ int ext4_encrypted_zeroout(struct inode
+       BUG_ON(inode->i_sb->s_blocksize != PAGE_CACHE_SIZE);
+-      ctx = ext4_get_crypto_ctx(inode);
++      ctx = ext4_get_crypto_ctx(inode, GFP_NOFS);
+       if (IS_ERR(ctx))
+               return PTR_ERR(ctx);
+-      ciphertext_page = alloc_bounce_page(ctx);
++      ciphertext_page = alloc_bounce_page(ctx, GFP_NOWAIT);
+       if (IS_ERR(ciphertext_page)) {
+               err = PTR_ERR(ciphertext_page);
+               goto errout;
+@@ -415,11 +419,12 @@ int ext4_encrypted_zeroout(struct inode
+       while (len--) {
+               err = ext4_page_crypto(inode, EXT4_ENCRYPT, lblk,
+-                                     ZERO_PAGE(0), ciphertext_page);
++                                     ZERO_PAGE(0), ciphertext_page,
++                                     GFP_NOFS);
+               if (err)
+                       goto errout;
+-              bio = bio_alloc(GFP_KERNEL, 1);
++              bio = bio_alloc(GFP_NOWAIT, 1);
+               if (!bio) {
+                       err = -ENOMEM;
+                       goto errout;
+--- a/fs/ext4/ext4.h
++++ b/fs/ext4/ext4.h
+@@ -2261,11 +2261,13 @@ extern struct kmem_cache *ext4_crypt_inf
+ bool ext4_valid_contents_enc_mode(uint32_t mode);
+ uint32_t ext4_validate_encryption_key_size(uint32_t mode, uint32_t size);
+ extern struct workqueue_struct *ext4_read_workqueue;
+-struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode);
++struct ext4_crypto_ctx *ext4_get_crypto_ctx(struct inode *inode,
++                                          gfp_t gfp_flags);
+ void ext4_release_crypto_ctx(struct ext4_crypto_ctx *ctx);
+ void ext4_restore_control_page(struct page *data_page);
+ struct page *ext4_encrypt(struct inode *inode,
+-                        struct page *plaintext_page);
++                        struct page *plaintext_page,
++                        gfp_t gfp_flags);
+ 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;
+--- a/fs/ext4/page-io.c
++++ b/fs/ext4/page-io.c
+@@ -23,6 +23,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/mm.h>
++#include <linux/backing-dev.h>
+ #include "ext4_jbd2.h"
+ #include "xattr.h"
+@@ -485,9 +486,20 @@ int ext4_bio_write_page(struct ext4_io_s
+       if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) &&
+           nr_to_submit) {
+-              data_page = ext4_encrypt(inode, page);
++              gfp_t gfp_flags = GFP_NOFS;
++
++      retry_encrypt:
++              data_page = ext4_encrypt(inode, page, gfp_flags);
+               if (IS_ERR(data_page)) {
+                       ret = PTR_ERR(data_page);
++                      if (ret == ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
++                              if (io->io_bio) {
++                                      ext4_io_submit(io);
++                                      congestion_wait(BLK_RW_ASYNC, HZ/50);
++                              }
++                              gfp_flags |= __GFP_NOFAIL;
++                              goto retry_encrypt;
++                      }
+                       data_page = NULL;
+                       goto out;
+               }
+--- a/fs/ext4/readpage.c
++++ b/fs/ext4/readpage.c
+@@ -279,7 +279,7 @@ int ext4_mpage_readpages(struct address_
+                       if (ext4_encrypted_inode(inode) &&
+                           S_ISREG(inode->i_mode)) {
+-                              ctx = ext4_get_crypto_ctx(inode);
++                              ctx = ext4_get_crypto_ctx(inode, GFP_NOFS);
+                               if (IS_ERR(ctx))
+                                       goto set_error_page;
+                       }
diff --git a/queue-4.4/ext4-crypto-fix-some-error-handling.patch b/queue-4.4/ext4-crypto-fix-some-error-handling.patch
new file mode 100644 (file)
index 0000000..72f1c41
--- /dev/null
@@ -0,0 +1,32 @@
+From 4762cc3fbbd89e5fd316d6e4d3244a8984444f8d Mon Sep 17 00:00:00 2001
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Date: Sat, 2 Apr 2016 18:13:38 -0400
+Subject: ext4 crypto: fix some error handling
+
+From: Dan Carpenter <dan.carpenter@oracle.com>
+
+commit 4762cc3fbbd89e5fd316d6e4d3244a8984444f8d upstream.
+
+We should be testing for -ENOMEM but the minus sign is missing.
+
+Fixes: c9af28fdd449 ('ext4 crypto: don't let data integrity writebacks fail with ENOMEM')
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+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/page-io.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/ext4/page-io.c
++++ b/fs/ext4/page-io.c
+@@ -492,7 +492,7 @@ int ext4_bio_write_page(struct ext4_io_s
+               data_page = ext4_encrypt(inode, page, gfp_flags);
+               if (IS_ERR(data_page)) {
+                       ret = PTR_ERR(data_page);
+-                      if (ret == ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
++                      if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) {
+                               if (io->io_bio) {
+                                       ext4_io_submit(io);
+                                       congestion_wait(BLK_RW_ASYNC, HZ/50);
diff --git a/queue-4.4/f2fs-check-entire-encrypted-bigname-when-finding-a-dentry.patch b/queue-4.4/f2fs-check-entire-encrypted-bigname-when-finding-a-dentry.patch
new file mode 100644 (file)
index 0000000..386971f
--- /dev/null
@@ -0,0 +1,155 @@
+From 6332cd32c8290a80e929fc044dc5bdba77396e33 Mon Sep 17 00:00:00 2001
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+Date: Mon, 24 Apr 2017 10:00:08 -0700
+Subject: f2fs: check entire encrypted bigname when finding a dentry
+
+From: Jaegeuk Kim <jaegeuk@kernel.org>
+
+commit 6332cd32c8290a80e929fc044dc5bdba77396e33 upstream.
+
+If user has no key under an encrypted dir, fscrypt gives digested dentries.
+Previously, when looking up a dentry, f2fs only checks its hash value with
+first 4 bytes of the digested dentry, which didn't handle hash collisions fully.
+This patch enhances to check entire dentry bytes likewise ext4.
+
+Eric reported how to reproduce this issue by:
+
+ # seq -f "edir/abcdefghijklmnopqrstuvwxyz012345%.0f" 100000 | xargs touch
+ # find edir -type f | xargs stat -c %i | sort | uniq | wc -l
+100000
+ # sync
+ # echo 3 > /proc/sys/vm/drop_caches
+ # keyctl new_session
+ # find edir -type f | xargs stat -c %i | sort | uniq | wc -l
+99999
+
+Cc: <stable@vger.kernel.org>
+Reported-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
+(fixed f2fs_dentry_hash() to work even when the hash is 0)
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+
+---
+ fs/f2fs/dir.c    |   32 +++++++++++++++++++++-----------
+ fs/f2fs/f2fs.h   |    3 ++-
+ fs/f2fs/hash.c   |    7 ++++++-
+ fs/f2fs/inline.c |    4 ++--
+ 4 files changed, 31 insertions(+), 15 deletions(-)
+
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -124,19 +124,29 @@ struct f2fs_dir_entry *find_target_dentr
+               de = &d->dentry[bit_pos];
+-              /* encrypted case */
++              if (de->hash_code != namehash)
++                      goto not_match;
++
+               de_name.name = d->filename[bit_pos];
+               de_name.len = le16_to_cpu(de->name_len);
+-              /* show encrypted name */
+-              if (fname->hash) {
+-                      if (de->hash_code == fname->hash)
+-                              goto found;
+-              } else if (de_name.len == name->len &&
+-                      de->hash_code == namehash &&
+-                      !memcmp(de_name.name, name->name, name->len))
++#ifdef CONFIG_F2FS_FS_ENCRYPTION
++              if (unlikely(!name->name)) {
++                      if (fname->usr_fname->name[0] == '_') {
++                              if (de_name.len >= 16 &&
++                                      !memcmp(de_name.name + de_name.len - 16,
++                                              fname->crypto_buf.name + 8, 16))
++                                      goto found;
++                              goto not_match;
++                      }
++                      name->name = fname->crypto_buf.name;
++                      name->len = fname->crypto_buf.len;
++              }
++#endif
++              if (de_name.len == name->len &&
++                              !memcmp(de_name.name, name->name, name->len))
+                       goto found;
+-
++not_match:
+               if (max_slots && max_len > *max_slots)
+                       *max_slots = max_len;
+               max_len = 0;
+@@ -170,7 +180,7 @@ static struct f2fs_dir_entry *find_in_le
+       int max_slots;
+       f2fs_hash_t namehash;
+-      namehash = f2fs_dentry_hash(&name);
++      namehash = f2fs_dentry_hash(&name, fname);
+       f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH);
+@@ -547,7 +557,7 @@ int __f2fs_add_link(struct inode *dir, c
+       level = 0;
+       slots = GET_DENTRY_SLOTS(new_name.len);
+-      dentry_hash = f2fs_dentry_hash(&new_name);
++      dentry_hash = f2fs_dentry_hash(&new_name, NULL);
+       current_depth = F2FS_I(dir)->i_current_depth;
+       if (F2FS_I(dir)->chash == dentry_hash) {
+--- a/fs/f2fs/f2fs.h
++++ b/fs/f2fs/f2fs.h
+@@ -1722,7 +1722,8 @@ void f2fs_msg(struct super_block *, cons
+ /*
+  * hash.c
+  */
+-f2fs_hash_t f2fs_dentry_hash(const struct qstr *);
++f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info,
++                              struct f2fs_filename *fname);
+ /*
+  * node.c
+--- a/fs/f2fs/hash.c
++++ b/fs/f2fs/hash.c
+@@ -70,7 +70,8 @@ static void str2hashbuf(const unsigned c
+               *buf++ = pad;
+ }
+-f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info)
++f2fs_hash_t f2fs_dentry_hash(const struct qstr *name_info,
++                              struct f2fs_filename *fname)
+ {
+       __u32 hash;
+       f2fs_hash_t f2fs_hash;
+@@ -79,6 +80,10 @@ f2fs_hash_t f2fs_dentry_hash(const struc
+       const unsigned char *name = name_info->name;
+       size_t len = name_info->len;
++      /* encrypted bigname case */
++      if (fname && !fname->disk_name.name)
++              return cpu_to_le32(fname->hash);
++
+       if (is_dot_dotdot(name_info))
+               return 0;
+--- a/fs/f2fs/inline.c
++++ b/fs/f2fs/inline.c
+@@ -303,7 +303,7 @@ struct f2fs_dir_entry *find_in_inline_di
+       if (IS_ERR(ipage))
+               return NULL;
+-      namehash = f2fs_dentry_hash(&name);
++      namehash = f2fs_dentry_hash(&name, fname);
+       inline_dentry = inline_data_addr(ipage);
+@@ -468,7 +468,7 @@ int f2fs_add_inline_entry(struct inode *
+       f2fs_wait_on_page_writeback(ipage, NODE);
+-      name_hash = f2fs_dentry_hash(name);
++      name_hash = f2fs_dentry_hash(name, NULL);
+       make_dentry_ptr(NULL, &d, (void *)dentry_blk, 2);
+       f2fs_update_dentry(ino, mode, &d, name, name_hash, bit_pos);
diff --git a/queue-4.4/fscrypt-avoid-collisions-when-presenting-long-encrypted-filenames.patch b/queue-4.4/fscrypt-avoid-collisions-when-presenting-long-encrypted-filenames.patch
new file mode 100644 (file)
index 0000000..dcf227f
--- /dev/null
@@ -0,0 +1,123 @@
+From 6b06cdee81d68a8a829ad8e8d0f31d6836744af9 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Mon, 24 Apr 2017 10:00:09 -0700
+Subject: fscrypt: avoid collisions when presenting long encrypted filenames
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 6b06cdee81d68a8a829ad8e8d0f31d6836744af9 upstream.
+
+When accessing an encrypted directory without the key, userspace must
+operate on filenames derived from the ciphertext names, which contain
+arbitrary bytes.  Since we must support filenames as long as NAME_MAX,
+we can't always just base64-encode the ciphertext, since that may make
+it too long.  Currently, this is solved by presenting long names in an
+abbreviated form containing any needed filesystem-specific hashes (e.g.
+to identify a directory block), then the last 16 bytes of ciphertext.
+This needs to be sufficient to identify the actual name on lookup.
+
+However, there is a bug.  It seems to have been assumed that due to the
+use of a CBC (ciphertext block chaining)-based encryption mode, the last
+16 bytes (i.e. the AES block size) of ciphertext would depend on the
+full plaintext, preventing collisions.  However, we actually use CBC
+with ciphertext stealing (CTS), which handles the last two blocks
+specially, causing them to appear "flipped".  Thus, it's actually the
+second-to-last block which depends on the full plaintext.
+
+This caused long filenames that differ only near the end of their
+plaintexts to, when observed without the key, point to the wrong inode
+and be undeletable.  For example, with ext4:
+
+    # echo pass | e4crypt add_key -p 16 edir/
+    # seq -f "edir/abcdefghijklmnopqrstuvwxyz012345%.0f" 100000 | xargs touch
+    # find edir/ -type f | xargs stat -c %i | sort | uniq | wc -l
+    100000
+    # sync
+    # echo 3 > /proc/sys/vm/drop_caches
+    # keyctl new_session
+    # find edir/ -type f | xargs stat -c %i | sort | uniq | wc -l
+    2004
+    # rm -rf edir/
+    rm: cannot remove 'edir/_A7nNFi3rhkEQlJ6P,hdzluhODKOeWx5V': Structure needs cleaning
+    ...
+
+To fix this, when presenting long encrypted filenames, encode the
+second-to-last block of ciphertext rather than the last 16 bytes.
+
+Although it would be nice to solve this without depending on a specific
+encryption mode, that would mean doing a cryptographic hash like SHA-256
+which would be much less efficient.  This way is sufficient for now, and
+it's still compatible with encryption modes like HEH which are strong
+pseudorandom permutations.  Also, changing the presented names is still
+allowed at any time because they are only provided to allow applications
+to do things like delete encrypted directories.  They're not designed to
+be used to persistently identify files --- which would be hard to do
+anyway, given that they're encrypted after all.
+
+For ease of backports, this patch only makes the minimal fix to both
+ext4 and f2fs.  It leaves ubifs as-is, since ubifs doesn't compare the
+ciphertext block yet.  Follow-on patches will clean things up properly
+and make the filesystems use a shared helper function.
+
+Fixes: 5de0b4d0cd15 ("ext4 crypto: simplify and speed up filename encryption")
+Reported-by: Gwendal Grignou <gwendal@chromium.org>
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/crypto_fname.c |    2 +-
+ fs/ext4/namei.c        |    4 ++--
+ fs/f2fs/crypto_fname.c |    2 +-
+ fs/f2fs/dir.c          |    4 ++--
+ 4 files changed, 6 insertions(+), 6 deletions(-)
+
+--- a/fs/ext4/crypto_fname.c
++++ b/fs/ext4/crypto_fname.c
+@@ -343,7 +343,7 @@ int _ext4_fname_disk_to_usr(struct inode
+               memcpy(buf+4, &hinfo->minor_hash, 4);
+       } else
+               memset(buf, 0, 8);
+-      memcpy(buf + 8, iname->name + iname->len - 16, 16);
++      memcpy(buf + 8, iname->name + ((iname->len - 17) & ~15), 16);
+       oname->name[0] = '_';
+       ret = digest_encode(buf, 24, oname->name+1);
+       oname->len = ret + 1;
+--- a/fs/ext4/namei.c
++++ b/fs/ext4/namei.c
+@@ -1243,9 +1243,9 @@ static inline int ext4_match(struct ext4
+       if (unlikely(!name)) {
+               if (fname->usr_fname->name[0] == '_') {
+                       int ret;
+-                      if (de->name_len < 16)
++                      if (de->name_len <= 32)
+                               return 0;
+-                      ret = memcmp(de->name + de->name_len - 16,
++                      ret = memcmp(de->name + ((de->name_len - 17) & ~15),
+                                    fname->crypto_buf.name + 8, 16);
+                       return (ret == 0) ? 1 : 0;
+               }
+--- a/fs/f2fs/crypto_fname.c
++++ b/fs/f2fs/crypto_fname.c
+@@ -333,7 +333,7 @@ int f2fs_fname_disk_to_usr(struct inode
+               memset(buf + 4, 0, 4);
+       } else
+               memset(buf, 0, 8);
+-      memcpy(buf + 8, iname->name + iname->len - 16, 16);
++      memcpy(buf + 8, iname->name + ((iname->len - 17) & ~15), 16);
+       oname->name[0] = '_';
+       ret = digest_encode(buf, 24, oname->name + 1);
+       oname->len = ret + 1;
+--- a/fs/f2fs/dir.c
++++ b/fs/f2fs/dir.c
+@@ -133,8 +133,8 @@ struct f2fs_dir_entry *find_target_dentr
+ #ifdef CONFIG_F2FS_FS_ENCRYPTION
+               if (unlikely(!name->name)) {
+                       if (fname->usr_fname->name[0] == '_') {
+-                              if (de_name.len >= 16 &&
+-                                      !memcmp(de_name.name + de_name.len - 16,
++                              if (de_name.len > 32 &&
++                                      !memcmp(de_name.name + ((de_name.len - 17) & ~15),
+                                               fname->crypto_buf.name + 8, 16))
+                                       goto found;
+                               goto not_match;
diff --git a/queue-4.4/fscrypt-fix-context-consistency-check-when-key-s-unavailable.patch b/queue-4.4/fscrypt-fix-context-consistency-check-when-key-s-unavailable.patch
new file mode 100644 (file)
index 0000000..2c83f30
--- /dev/null
@@ -0,0 +1,240 @@
+From 272f98f6846277378e1758a49a49d7bf39343c02 Mon Sep 17 00:00:00 2001
+From: Eric Biggers <ebiggers@google.com>
+Date: Fri, 7 Apr 2017 10:58:37 -0700
+Subject: fscrypt: fix context consistency check when key(s) unavailable
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 272f98f6846277378e1758a49a49d7bf39343c02 upstream.
+
+To mitigate some types of offline attacks, filesystem encryption is
+designed to enforce that all files in an encrypted directory tree use
+the same encryption policy (i.e. the same encryption context excluding
+the nonce).  However, the fscrypt_has_permitted_context() function which
+enforces this relies on comparing struct fscrypt_info's, which are only
+available when we have the encryption keys.  This can cause two
+incorrect behaviors:
+
+1. If we have the parent directory's key but not the child's key, or
+   vice versa, then fscrypt_has_permitted_context() returned false,
+   causing applications to see EPERM or ENOKEY.  This is incorrect if
+   the encryption contexts are in fact consistent.  Although we'd
+   normally have either both keys or neither key in that case since the
+   master_key_descriptors would be the same, this is not guaranteed
+   because keys can be added or removed from keyrings at any time.
+
+2. If we have neither the parent's key nor the child's key, then
+   fscrypt_has_permitted_context() returned true, causing applications
+   to see no error (or else an error for some other reason).  This is
+   incorrect if the encryption contexts are in fact inconsistent, since
+   in that case we should deny access.
+
+To fix this, retrieve and compare the fscrypt_contexts if we are unable
+to set up both fscrypt_infos.
+
+While this slightly hurts performance when accessing an encrypted
+directory tree without the key, this isn't a case we really need to be
+optimizing for; access *with* the key is much more important.
+Furthermore, the performance hit is barely noticeable given that we are
+already retrieving the fscrypt_context and doing two keyring searches in
+fscrypt_get_encryption_info().  If we ever actually wanted to optimize
+this case we might start by caching the fscrypt_contexts.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/ext4/crypto_policy.c |   66 ++++++++++++++++++++++++++++++++++--------------
+ fs/f2fs/crypto_policy.c |   65 ++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 96 insertions(+), 35 deletions(-)
+
+--- a/fs/ext4/crypto_policy.c
++++ b/fs/ext4/crypto_policy.c
+@@ -148,26 +148,38 @@ int ext4_get_policy(struct inode *inode,
+ int ext4_is_child_context_consistent_with_parent(struct inode *parent,
+                                                struct inode *child)
+ {
+-      struct ext4_crypt_info *parent_ci, *child_ci;
++      const struct ext4_crypt_info *parent_ci, *child_ci;
++      struct ext4_encryption_context parent_ctx, child_ctx;
+       int res;
+-      if ((parent == NULL) || (child == NULL)) {
+-              pr_err("parent %p child %p\n", parent, child);
+-              WARN_ON(1);     /* Should never happen */
+-              return 0;
+-      }
+-
+       /* No restrictions on file types which are never encrypted */
+       if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
+           !S_ISLNK(child->i_mode))
+               return 1;
+-      /* no restrictions if the parent directory is not encrypted */
++      /* No restrictions if the parent directory is unencrypted */
+       if (!ext4_encrypted_inode(parent))
+               return 1;
+-      /* if the child directory is not encrypted, this is always a problem */
++
++      /* Encrypted directories must not contain unencrypted files */
+       if (!ext4_encrypted_inode(child))
+               return 0;
++
++      /*
++       * Both parent and child are encrypted, so verify they use the same
++       * encryption policy.  Compare the fscrypt_info structs if the keys are
++       * available, otherwise retrieve and compare the fscrypt_contexts.
++       *
++       * Note that the fscrypt_context retrieval will be required frequently
++       * when accessing an encrypted directory tree without the key.
++       * Performance-wise this is not a big deal because we already don't
++       * really optimize for file access without the key (to the extent that
++       * such access is even possible), given that any attempted access
++       * already causes a fscrypt_context retrieval and keyring search.
++       *
++       * In any case, if an unexpected error occurs, fall back to "forbidden".
++       */
++
+       res = ext4_get_encryption_info(parent);
+       if (res)
+               return 0;
+@@ -176,17 +188,35 @@ int ext4_is_child_context_consistent_wit
+               return 0;
+       parent_ci = EXT4_I(parent)->i_crypt_info;
+       child_ci = EXT4_I(child)->i_crypt_info;
+-      if (!parent_ci && !child_ci)
+-              return 1;
+-      if (!parent_ci || !child_ci)
++      if (parent_ci && child_ci) {
++              return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
++                            EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
++                      (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
++                      (parent_ci->ci_filename_mode ==
++                       child_ci->ci_filename_mode) &&
++                      (parent_ci->ci_flags == child_ci->ci_flags);
++      }
++
++      res = ext4_xattr_get(parent, EXT4_XATTR_INDEX_ENCRYPTION,
++                           EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
++                           &parent_ctx, sizeof(parent_ctx));
++      if (res != sizeof(parent_ctx))
++              return 0;
++
++      res = ext4_xattr_get(child, EXT4_XATTR_INDEX_ENCRYPTION,
++                           EXT4_XATTR_NAME_ENCRYPTION_CONTEXT,
++                           &child_ctx, sizeof(child_ctx));
++      if (res != sizeof(child_ctx))
+               return 0;
+-      return (memcmp(parent_ci->ci_master_key,
+-                     child_ci->ci_master_key,
+-                     EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
+-              (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
+-              (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
+-              (parent_ci->ci_flags == child_ci->ci_flags));
++      return memcmp(parent_ctx.master_key_descriptor,
++                    child_ctx.master_key_descriptor,
++                    EXT4_KEY_DESCRIPTOR_SIZE) == 0 &&
++              (parent_ctx.contents_encryption_mode ==
++               child_ctx.contents_encryption_mode) &&
++              (parent_ctx.filenames_encryption_mode ==
++               child_ctx.filenames_encryption_mode) &&
++              (parent_ctx.flags == child_ctx.flags);
+ }
+ /**
+--- a/fs/f2fs/crypto_policy.c
++++ b/fs/f2fs/crypto_policy.c
+@@ -141,25 +141,38 @@ int f2fs_get_policy(struct inode *inode,
+ int f2fs_is_child_context_consistent_with_parent(struct inode *parent,
+                                               struct inode *child)
+ {
+-      struct f2fs_crypt_info *parent_ci, *child_ci;
++      const struct f2fs_crypt_info *parent_ci, *child_ci;
++      struct f2fs_encryption_context parent_ctx, child_ctx;
+       int res;
+-      if ((parent == NULL) || (child == NULL)) {
+-              pr_err("parent %p child %p\n", parent, child);
+-              BUG_ON(1);
+-      }
+-
+       /* No restrictions on file types which are never encrypted */
+       if (!S_ISREG(child->i_mode) && !S_ISDIR(child->i_mode) &&
+           !S_ISLNK(child->i_mode))
+               return 1;
+-      /* no restrictions if the parent directory is not encrypted */
++      /* No restrictions if the parent directory is unencrypted */
+       if (!f2fs_encrypted_inode(parent))
+               return 1;
+-      /* if the child directory is not encrypted, this is always a problem */
++
++      /* Encrypted directories must not contain unencrypted files */
+       if (!f2fs_encrypted_inode(child))
+               return 0;
++
++      /*
++       * Both parent and child are encrypted, so verify they use the same
++       * encryption policy.  Compare the fscrypt_info structs if the keys are
++       * available, otherwise retrieve and compare the fscrypt_contexts.
++       *
++       * Note that the fscrypt_context retrieval will be required frequently
++       * when accessing an encrypted directory tree without the key.
++       * Performance-wise this is not a big deal because we already don't
++       * really optimize for file access without the key (to the extent that
++       * such access is even possible), given that any attempted access
++       * already causes a fscrypt_context retrieval and keyring search.
++       *
++       * In any case, if an unexpected error occurs, fall back to "forbidden".
++       */
++
+       res = f2fs_get_encryption_info(parent);
+       if (res)
+               return 0;
+@@ -168,17 +181,35 @@ int f2fs_is_child_context_consistent_wit
+               return 0;
+       parent_ci = F2FS_I(parent)->i_crypt_info;
+       child_ci = F2FS_I(child)->i_crypt_info;
+-      if (!parent_ci && !child_ci)
+-              return 1;
+-      if (!parent_ci || !child_ci)
++      if (parent_ci && child_ci) {
++              return memcmp(parent_ci->ci_master_key, child_ci->ci_master_key,
++                            F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
++                      (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
++                      (parent_ci->ci_filename_mode ==
++                       child_ci->ci_filename_mode) &&
++                      (parent_ci->ci_flags == child_ci->ci_flags);
++      }
++
++      res = f2fs_getxattr(parent, F2FS_XATTR_INDEX_ENCRYPTION,
++                          F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
++                          &parent_ctx, sizeof(parent_ctx), NULL);
++      if (res != sizeof(parent_ctx))
++              return 0;
++
++      res = f2fs_getxattr(child, F2FS_XATTR_INDEX_ENCRYPTION,
++                          F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
++                          &child_ctx, sizeof(child_ctx), NULL);
++      if (res != sizeof(child_ctx))
+               return 0;
+-      return (memcmp(parent_ci->ci_master_key,
+-                      child_ci->ci_master_key,
+-                      F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
+-              (parent_ci->ci_data_mode == child_ci->ci_data_mode) &&
+-              (parent_ci->ci_filename_mode == child_ci->ci_filename_mode) &&
+-              (parent_ci->ci_flags == child_ci->ci_flags));
++      return memcmp(parent_ctx.master_key_descriptor,
++                    child_ctx.master_key_descriptor,
++                    F2FS_KEY_DESCRIPTOR_SIZE) == 0 &&
++              (parent_ctx.contents_encryption_mode ==
++               child_ctx.contents_encryption_mode) &&
++              (parent_ctx.filenames_encryption_mode ==
++               child_ctx.filenames_encryption_mode) &&
++              (parent_ctx.flags == child_ctx.flags);
+ }
+ /**
diff --git a/queue-4.4/net-qmi_wwan-add-simcom-7230e.patch b/queue-4.4/net-qmi_wwan-add-simcom-7230e.patch
new file mode 100644 (file)
index 0000000..d603554
--- /dev/null
@@ -0,0 +1,35 @@
+From 18715b261541f35ccede9b8686ee3ebaac697d38 Mon Sep 17 00:00:00 2001
+From: Kristian Evensen <kristian.evensen@gmail.com>
+Date: Thu, 7 Jan 2016 16:41:33 +0100
+Subject: net: qmi_wwan: Add SIMCom 7230E
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Kristian Evensen <kristian.evensen@gmail.com>
+
+commit 18715b261541f35ccede9b8686ee3ebaac697d38 upstream.
+
+SIMCom 7230E is a QMI LTE module with support for most "normal" bands.
+Manual testing has showed that only interface five works.
+
+Cc: Bjørn Mork <bjorn@mork.no>
+Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
+Acked-by: Bjørn Mork <bjorn@mork.no>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/usb/qmi_wwan.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/net/usb/qmi_wwan.c
++++ b/drivers/net/usb/qmi_wwan.c
+@@ -754,6 +754,7 @@ static const struct usb_device_id produc
+       {QMI_FIXED_INTF(0x413c, 0x81b1, 8)},    /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
+       {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},    /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
+       {QMI_FIXED_INTF(0x22de, 0x9061, 3)},    /* WeTelecom WPD-600N */
++      {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},    /* SIMCom 7230E */
+       /* 4. Gobi 1000 devices */
+       {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
index 15b68493ce454b896918a27374b7165bb9d58916..f1c7d259b8f4e2e898c8420571d7db120b520d21 100644 (file)
@@ -42,3 +42,9 @@ pid_ns-sleep-in-task_interruptible-in-zap_pid_ns_processes.patch
 pid_ns-fix-race-between-setns-ed-fork-and-zap_pid_ns_processes.patch
 usb-serial-ftdi_sio-fix-setting-latency-for-unprivileged-users.patch
 usb-serial-ftdi_sio-add-olimex-arm-usb-tiny-h-pids.patch
+ext4-crypto-don-t-let-data-integrity-writebacks-fail-with-enomem.patch
+ext4-crypto-fix-some-error-handling.patch
+net-qmi_wwan-add-simcom-7230e.patch
+fscrypt-fix-context-consistency-check-when-key-s-unavailable.patch
+f2fs-check-entire-encrypted-bigname-when-finding-a-dentry.patch
+fscrypt-avoid-collisions-when-presenting-long-encrypted-filenames.patch