From: Greg Kroah-Hartman Date: Thu, 11 Jul 2019 11:44:51 +0000 (+0200) Subject: 4.9-stable patches X-Git-Tag: v5.2.1~42 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=71539f1883fbe5f661222d017e94edbf6c1bbde1;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: udf-fix-incorrect-final-not_allocated-hole-extent-length.patch x86-ptrace-fix-possible-spectre-v1-in-ptrace_get_debugreg.patch x86-tls-fix-possible-spectre-v1-in-do_get_thread_area.patch --- diff --git a/queue-4.9/series b/queue-4.9/series index 50da5ec13f3..e69073d29ab 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -19,3 +19,6 @@ md-fix-for-divide-error-in-status_resync.patch bnx2x-check-if-transceiver-implements-ddm-before-acc.patch ip6_tunnel-allow-not-to-count-pkts-on-tstats-by-pass.patch net-sunrpc-clnt-fix-xps-refcount-imbalance-on-the-er.patch +udf-fix-incorrect-final-not_allocated-hole-extent-length.patch +x86-ptrace-fix-possible-spectre-v1-in-ptrace_get_debugreg.patch +x86-tls-fix-possible-spectre-v1-in-do_get_thread_area.patch diff --git a/queue-4.9/udf-fix-incorrect-final-not_allocated-hole-extent-length.patch b/queue-4.9/udf-fix-incorrect-final-not_allocated-hole-extent-length.patch new file mode 100644 index 00000000000..db091f3c803 --- /dev/null +++ b/queue-4.9/udf-fix-incorrect-final-not_allocated-hole-extent-length.patch @@ -0,0 +1,223 @@ +From fa33cdbf3eceb0206a4f844fe91aeebcf6ff2b7a Mon Sep 17 00:00:00 2001 +From: "Steven J. Magnani" +Date: Sun, 30 Jun 2019 21:39:35 -0500 +Subject: udf: Fix incorrect final NOT_ALLOCATED (hole) extent length + +From: Steven J. Magnani + +commit fa33cdbf3eceb0206a4f844fe91aeebcf6ff2b7a upstream. + +In some cases, using the 'truncate' command to extend a UDF file results +in a mismatch between the length of the file's extents (specifically, due +to incorrect length of the final NOT_ALLOCATED extent) and the information +(file) length. The discrepancy can prevent other operating systems +(i.e., Windows 10) from opening the file. + +Two particular errors have been observed when extending a file: + +1. The final extent is larger than it should be, having been rounded up + to a multiple of the block size. + +B. The final extent is not shorter than it should be, due to not having + been updated when the file's information length was increased. + +[JK: simplified udf_do_extend_final_block(), fixed up some types] + +Fixes: 2c948b3f86e5 ("udf: Avoid IO in udf_clear_inode") +CC: stable@vger.kernel.org +Signed-off-by: Steven J. Magnani +Link: https://lore.kernel.org/r/1561948775-5878-1-git-send-email-steve@digidescorp.com +Signed-off-by: Jan Kara +Signed-off-by: Greg Kroah-Hartman + +--- + fs/udf/inode.c | 93 ++++++++++++++++++++++++++++++++++++--------------------- + 1 file changed, 60 insertions(+), 33 deletions(-) + +--- a/fs/udf/inode.c ++++ b/fs/udf/inode.c +@@ -478,13 +478,15 @@ static struct buffer_head *udf_getblk(st + return NULL; + } + +-/* Extend the file by 'blocks' blocks, return the number of extents added */ ++/* Extend the file with new blocks totaling 'new_block_bytes', ++ * return the number of extents added ++ */ + static int udf_do_extend_file(struct inode *inode, + struct extent_position *last_pos, + struct kernel_long_ad *last_ext, +- sector_t blocks) ++ loff_t new_block_bytes) + { +- sector_t add; ++ uint32_t add; + int count = 0, fake = !(last_ext->extLength & UDF_EXTENT_LENGTH_MASK); + struct super_block *sb = inode->i_sb; + struct kernel_lb_addr prealloc_loc = {}; +@@ -494,7 +496,7 @@ static int udf_do_extend_file(struct ino + + /* The previous extent is fake and we should not extend by anything + * - there's nothing to do... */ +- if (!blocks && fake) ++ if (!new_block_bytes && fake) + return 0; + + iinfo = UDF_I(inode); +@@ -525,13 +527,12 @@ static int udf_do_extend_file(struct ino + /* Can we merge with the previous extent? */ + if ((last_ext->extLength & UDF_EXTENT_FLAG_MASK) == + EXT_NOT_RECORDED_NOT_ALLOCATED) { +- add = ((1 << 30) - sb->s_blocksize - +- (last_ext->extLength & UDF_EXTENT_LENGTH_MASK)) >> +- sb->s_blocksize_bits; +- if (add > blocks) +- add = blocks; +- blocks -= add; +- last_ext->extLength += add << sb->s_blocksize_bits; ++ add = (1 << 30) - sb->s_blocksize - ++ (last_ext->extLength & UDF_EXTENT_LENGTH_MASK); ++ if (add > new_block_bytes) ++ add = new_block_bytes; ++ new_block_bytes -= add; ++ last_ext->extLength += add; + } + + if (fake) { +@@ -552,28 +553,27 @@ static int udf_do_extend_file(struct ino + } + + /* Managed to do everything necessary? */ +- if (!blocks) ++ if (!new_block_bytes) + goto out; + + /* All further extents will be NOT_RECORDED_NOT_ALLOCATED */ + last_ext->extLocation.logicalBlockNum = 0; + last_ext->extLocation.partitionReferenceNum = 0; +- add = (1 << (30-sb->s_blocksize_bits)) - 1; +- last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | +- (add << sb->s_blocksize_bits); ++ add = (1 << 30) - sb->s_blocksize; ++ last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | add; + + /* Create enough extents to cover the whole hole */ +- while (blocks > add) { +- blocks -= add; ++ while (new_block_bytes > add) { ++ new_block_bytes -= add; + err = udf_add_aext(inode, last_pos, &last_ext->extLocation, + last_ext->extLength, 1); + if (err) + return err; + count++; + } +- if (blocks) { ++ if (new_block_bytes) { + last_ext->extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | +- (blocks << sb->s_blocksize_bits); ++ new_block_bytes; + err = udf_add_aext(inode, last_pos, &last_ext->extLocation, + last_ext->extLength, 1); + if (err) +@@ -604,6 +604,24 @@ out: + return count; + } + ++/* Extend the final block of the file to final_block_len bytes */ ++static void udf_do_extend_final_block(struct inode *inode, ++ struct extent_position *last_pos, ++ struct kernel_long_ad *last_ext, ++ uint32_t final_block_len) ++{ ++ struct super_block *sb = inode->i_sb; ++ uint32_t added_bytes; ++ ++ added_bytes = final_block_len - ++ (last_ext->extLength & (sb->s_blocksize - 1)); ++ last_ext->extLength += added_bytes; ++ UDF_I(inode)->i_lenExtents += added_bytes; ++ ++ udf_write_aext(inode, last_pos, &last_ext->extLocation, ++ last_ext->extLength, 1); ++} ++ + static int udf_extend_file(struct inode *inode, loff_t newsize) + { + +@@ -613,10 +631,12 @@ static int udf_extend_file(struct inode + int8_t etype; + struct super_block *sb = inode->i_sb; + sector_t first_block = newsize >> sb->s_blocksize_bits, offset; ++ unsigned long partial_final_block; + int adsize; + struct udf_inode_info *iinfo = UDF_I(inode); + struct kernel_long_ad extent; +- int err; ++ int err = 0; ++ int within_final_block; + + if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) + adsize = sizeof(struct short_ad); +@@ -626,18 +646,8 @@ static int udf_extend_file(struct inode + BUG(); + + etype = inode_bmap(inode, first_block, &epos, &eloc, &elen, &offset); ++ within_final_block = (etype != -1); + +- /* File has extent covering the new size (could happen when extending +- * inside a block)? */ +- if (etype != -1) +- return 0; +- if (newsize & (sb->s_blocksize - 1)) +- offset++; +- /* Extended file just to the boundary of the last file block? */ +- if (offset == 0) +- return 0; +- +- /* Truncate is extending the file by 'offset' blocks */ + if ((!epos.bh && epos.offset == udf_file_entry_alloc_offset(inode)) || + (epos.bh && epos.offset == sizeof(struct allocExtDesc))) { + /* File has no extents at all or has empty last +@@ -651,7 +661,22 @@ static int udf_extend_file(struct inode + &extent.extLength, 0); + extent.extLength |= etype << 30; + } +- err = udf_do_extend_file(inode, &epos, &extent, offset); ++ ++ partial_final_block = newsize & (sb->s_blocksize - 1); ++ ++ /* File has extent covering the new size (could happen when extending ++ * inside a block)? ++ */ ++ if (within_final_block) { ++ /* Extending file within the last file block */ ++ udf_do_extend_final_block(inode, &epos, &extent, ++ partial_final_block); ++ } else { ++ loff_t add = ((loff_t)offset << sb->s_blocksize_bits) | ++ partial_final_block; ++ err = udf_do_extend_file(inode, &epos, &extent, add); ++ } ++ + if (err < 0) + goto out; + err = 0; +@@ -756,6 +781,7 @@ static sector_t inode_getblk(struct inod + /* Are we beyond EOF? */ + if (etype == -1) { + int ret; ++ loff_t hole_len; + isBeyondEOF = true; + if (count) { + if (c) +@@ -771,7 +797,8 @@ static sector_t inode_getblk(struct inod + startnum = (offset > 0); + } + /* Create extents for the hole between EOF and offset */ +- ret = udf_do_extend_file(inode, &prev_epos, laarr, offset); ++ hole_len = (loff_t)offset << inode->i_blkbits; ++ ret = udf_do_extend_file(inode, &prev_epos, laarr, hole_len); + if (ret < 0) { + brelse(prev_epos.bh); + brelse(cur_epos.bh); diff --git a/queue-4.9/x86-ptrace-fix-possible-spectre-v1-in-ptrace_get_debugreg.patch b/queue-4.9/x86-ptrace-fix-possible-spectre-v1-in-ptrace_get_debugreg.patch new file mode 100644 index 00000000000..fa391ec3deb --- /dev/null +++ b/queue-4.9/x86-ptrace-fix-possible-spectre-v1-in-ptrace_get_debugreg.patch @@ -0,0 +1,54 @@ +From 31a2fbb390fee4231281b939e1979e810f945415 Mon Sep 17 00:00:00 2001 +From: Dianzhang Chen +Date: Tue, 25 Jun 2019 23:30:17 +0800 +Subject: x86/ptrace: Fix possible spectre-v1 in ptrace_get_debugreg() + +From: Dianzhang Chen + +commit 31a2fbb390fee4231281b939e1979e810f945415 upstream. + +The index to access the threads ptrace_bps is controlled by userspace via +syscall: sys_ptrace(), hence leading to a potential exploitation of the +Spectre variant 1 vulnerability. + +The index can be controlled from: + ptrace -> arch_ptrace -> ptrace_get_debugreg. + +Fix this by sanitizing the user supplied index before using it access +thread->ptrace_bps. + +Signed-off-by: Dianzhang Chen +Signed-off-by: Thomas Gleixner +Cc: bp@alien8.de +Cc: hpa@zytor.com +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/1561476617-3759-1-git-send-email-dianzhangchen0@gmail.com +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/ptrace.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/arch/x86/kernel/ptrace.c ++++ b/arch/x86/kernel/ptrace.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -650,9 +651,11 @@ static unsigned long ptrace_get_debugreg + { + struct thread_struct *thread = &tsk->thread; + unsigned long val = 0; ++ int index = n; + + if (n < HBP_NUM) { +- struct perf_event *bp = thread->ptrace_bps[n]; ++ index = array_index_nospec(index, HBP_NUM); ++ struct perf_event *bp = thread->ptrace_bps[index]; + + if (bp) + val = bp->hw.info.address; diff --git a/queue-4.9/x86-tls-fix-possible-spectre-v1-in-do_get_thread_area.patch b/queue-4.9/x86-tls-fix-possible-spectre-v1-in-do_get_thread_area.patch new file mode 100644 index 00000000000..0a69c555b9b --- /dev/null +++ b/queue-4.9/x86-tls-fix-possible-spectre-v1-in-do_get_thread_area.patch @@ -0,0 +1,63 @@ +From 993773d11d45c90cb1c6481c2638c3d9f092ea5b Mon Sep 17 00:00:00 2001 +From: Dianzhang Chen +Date: Wed, 26 Jun 2019 12:50:30 +0800 +Subject: x86/tls: Fix possible spectre-v1 in do_get_thread_area() + +From: Dianzhang Chen + +commit 993773d11d45c90cb1c6481c2638c3d9f092ea5b upstream. + +The index to access the threads tls array is controlled by userspace +via syscall: sys_ptrace(), hence leading to a potential exploitation +of the Spectre variant 1 vulnerability. + +The index can be controlled from: + ptrace -> arch_ptrace -> do_get_thread_area. + +Fix this by sanitizing the user supplied index before using it to access +the p->thread.tls_array. + +Signed-off-by: Dianzhang Chen +Signed-off-by: Thomas Gleixner +Cc: bp@alien8.de +Cc: hpa@zytor.com +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/1561524630-3642-1-git-send-email-dianzhangchen0@gmail.com +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/tls.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +--- a/arch/x86/kernel/tls.c ++++ b/arch/x86/kernel/tls.c +@@ -4,6 +4,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -219,6 +220,7 @@ int do_get_thread_area(struct task_struc + struct user_desc __user *u_info) + { + struct user_desc info; ++ int index; + + if (idx == -1 && get_user(idx, &u_info->entry_number)) + return -EFAULT; +@@ -226,8 +228,11 @@ int do_get_thread_area(struct task_struc + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) + return -EINVAL; + +- fill_user_desc(&info, idx, +- &p->thread.tls_array[idx - GDT_ENTRY_TLS_MIN]); ++ index = idx - GDT_ENTRY_TLS_MIN; ++ index = array_index_nospec(index, ++ GDT_ENTRY_TLS_MAX - GDT_ENTRY_TLS_MIN + 1); ++ ++ fill_user_desc(&info, idx, &p->thread.tls_array[index]); + + if (copy_to_user(u_info, &info, sizeof(info))) + return -EFAULT;