From: Greg Kroah-Hartman Date: Tue, 23 May 2017 10:22:46 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v3.18.55~41 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f3e3ce4f694bc3d9ba2da3032064e20cbe8ff515;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches 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 --- 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 index 00000000000..db0afe07b72 --- /dev/null +++ b/queue-4.4/ext4-crypto-don-t-let-data-integrity-writebacks-fail-with-enomem.patch @@ -0,0 +1,216 @@ +From c9af28fdd44922a6c10c9f8315718408af98e315 Mon Sep 17 00:00:00 2001 +From: Theodore Ts'o +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 + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman +--- + 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 + #include + #include ++#include + + #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 index 00000000000..72f1c41d678 --- /dev/null +++ b/queue-4.4/ext4-crypto-fix-some-error-handling.patch @@ -0,0 +1,32 @@ +From 4762cc3fbbd89e5fd316d6e4d3244a8984444f8d Mon Sep 17 00:00:00 2001 +From: Dan Carpenter +Date: Sat, 2 Apr 2016 18:13:38 -0400 +Subject: ext4 crypto: fix some error handling + +From: Dan Carpenter + +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 +Signed-off-by: Theodore Ts'o +Signed-off-by: Eric Biggers +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..386971fe610 --- /dev/null +++ b/queue-4.4/f2fs-check-entire-encrypted-bigname-when-finding-a-dentry.patch @@ -0,0 +1,155 @@ +From 6332cd32c8290a80e929fc044dc5bdba77396e33 Mon Sep 17 00:00:00 2001 +From: Jaegeuk Kim +Date: Mon, 24 Apr 2017 10:00:08 -0700 +Subject: f2fs: check entire encrypted bigname when finding a dentry + +From: Jaegeuk Kim + +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: +Reported-by: Eric Biggers +Signed-off-by: Jaegeuk Kim +(fixed f2fs_dentry_hash() to work even when the hash is 0) +Signed-off-by: Eric Biggers +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + + +--- + 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 index 00000000000..dcf227f9007 --- /dev/null +++ b/queue-4.4/fscrypt-avoid-collisions-when-presenting-long-encrypted-filenames.patch @@ -0,0 +1,123 @@ +From 6b06cdee81d68a8a829ad8e8d0f31d6836744af9 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Mon, 24 Apr 2017 10:00:09 -0700 +Subject: fscrypt: avoid collisions when presenting long encrypted filenames + +From: Eric Biggers + +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 +Signed-off-by: Eric Biggers +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..2c83f304cc9 --- /dev/null +++ b/queue-4.4/fscrypt-fix-context-consistency-check-when-key-s-unavailable.patch @@ -0,0 +1,240 @@ +From 272f98f6846277378e1758a49a49d7bf39343c02 Mon Sep 17 00:00:00 2001 +From: Eric Biggers +Date: Fri, 7 Apr 2017 10:58:37 -0700 +Subject: fscrypt: fix context consistency check when key(s) unavailable + +From: Eric Biggers + +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 +Signed-off-by: Theodore Ts'o +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..d60355493eb --- /dev/null +++ b/queue-4.4/net-qmi_wwan-add-simcom-7230e.patch @@ -0,0 +1,35 @@ +From 18715b261541f35ccede9b8686ee3ebaac697d38 Mon Sep 17 00:00:00 2001 +From: Kristian Evensen +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 + +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 +Signed-off-by: Kristian Evensen +Acked-by: Bjørn Mork +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + 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 */ diff --git a/queue-4.4/series b/queue-4.4/series index 15b68493ce4..f1c7d259b8f 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -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