]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.9-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Jul 2019 11:44:51 +0000 (13:44 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Jul 2019 11:44:51 +0000 (13:44 +0200)
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

queue-4.9/series
queue-4.9/udf-fix-incorrect-final-not_allocated-hole-extent-length.patch [new file with mode: 0644]
queue-4.9/x86-ptrace-fix-possible-spectre-v1-in-ptrace_get_debugreg.patch [new file with mode: 0644]
queue-4.9/x86-tls-fix-possible-spectre-v1-in-do_get_thread_area.patch [new file with mode: 0644]

index 50da5ec13f399e83fa5b75ffc8188d1ea0cdcefe..e69073d29abbe73c27d9a1580a0c32f27b21ea84 100644 (file)
@@ -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 (file)
index 0000000..db091f3
--- /dev/null
@@ -0,0 +1,223 @@
+From fa33cdbf3eceb0206a4f844fe91aeebcf6ff2b7a Mon Sep 17 00:00:00 2001
+From: "Steven J. Magnani" <steve.magnani@digidescorp.com>
+Date: Sun, 30 Jun 2019 21:39:35 -0500
+Subject: udf: Fix incorrect final NOT_ALLOCATED (hole) extent length
+
+From: Steven J. Magnani <steve.magnani@digidescorp.com>
+
+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 <steve@digidescorp.com>
+Link: https://lore.kernel.org/r/1561948775-5878-1-git-send-email-steve@digidescorp.com
+Signed-off-by: Jan Kara <jack@suse.cz>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 (file)
index 0000000..fa391ec
--- /dev/null
@@ -0,0 +1,54 @@
+From 31a2fbb390fee4231281b939e1979e810f945415 Mon Sep 17 00:00:00 2001
+From: Dianzhang Chen <dianzhangchen0@gmail.com>
+Date: Tue, 25 Jun 2019 23:30:17 +0800
+Subject: x86/ptrace: Fix possible spectre-v1 in ptrace_get_debugreg()
+
+From: Dianzhang Chen <dianzhangchen0@gmail.com>
+
+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 <dianzhangchen0@gmail.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+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 <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/rcupdate.h>
+ #include <linux/export.h>
+ #include <linux/context_tracking.h>
++#include <linux/nospec.h>
+ #include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+@@ -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 (file)
index 0000000..0a69c55
--- /dev/null
@@ -0,0 +1,63 @@
+From 993773d11d45c90cb1c6481c2638c3d9f092ea5b Mon Sep 17 00:00:00 2001
+From: Dianzhang Chen <dianzhangchen0@gmail.com>
+Date: Wed, 26 Jun 2019 12:50:30 +0800
+Subject: x86/tls: Fix possible spectre-v1 in do_get_thread_area()
+
+From: Dianzhang Chen <dianzhangchen0@gmail.com>
+
+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 <dianzhangchen0@gmail.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+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 <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/user.h>
+ #include <linux/regset.h>
+ #include <linux/syscalls.h>
++#include <linux/nospec.h>
+ #include <asm/uaccess.h>
+ #include <asm/desc.h>
+@@ -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;