]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 8 Jun 2021 13:58:49 +0000 (15:58 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 8 Jun 2021 13:58:49 +0000 (15:58 +0200)
added patches:
btrfs-fix-error-handling-in-btrfs_del_csums.patch
nfc-fix-null-ptr-dereference-in-llcp_sock_getname-after-failed-connect.patch
ocfs2-fix-data-corruption-by-fallocate.patch

queue-4.14/btrfs-fix-error-handling-in-btrfs_del_csums.patch [new file with mode: 0644]
queue-4.14/nfc-fix-null-ptr-dereference-in-llcp_sock_getname-after-failed-connect.patch [new file with mode: 0644]
queue-4.14/ocfs2-fix-data-corruption-by-fallocate.patch [new file with mode: 0644]
queue-4.14/series

diff --git a/queue-4.14/btrfs-fix-error-handling-in-btrfs_del_csums.patch b/queue-4.14/btrfs-fix-error-handling-in-btrfs_del_csums.patch
new file mode 100644 (file)
index 0000000..4069337
--- /dev/null
@@ -0,0 +1,93 @@
+From b86652be7c83f70bf406bed18ecf55adb9bfb91b Mon Sep 17 00:00:00 2001
+From: Josef Bacik <josef@toxicpanda.com>
+Date: Wed, 19 May 2021 10:52:45 -0400
+Subject: btrfs: fix error handling in btrfs_del_csums
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+commit b86652be7c83f70bf406bed18ecf55adb9bfb91b upstream.
+
+Error injection stress would sometimes fail with checksums on disk that
+did not have a corresponding extent.  This occurred because the pattern
+in btrfs_del_csums was
+
+       while (1) {
+               ret = btrfs_search_slot();
+               if (ret < 0)
+                       break;
+       }
+       ret = 0;
+out:
+       btrfs_free_path(path);
+       return ret;
+
+If we got an error from btrfs_search_slot we'd clear the error because
+we were breaking instead of goto out.  Instead of using goto out, simply
+handle the cases where we may leave a random value in ret, and get rid
+of the
+
+       ret = 0;
+out:
+
+pattern and simply allow break to have the proper error reporting.  With
+this fix we properly abort the transaction and do not commit thinking we
+successfully deleted the csum.
+
+Reviewed-by: Qu Wenruo <wqu@suse.com>
+CC: stable@vger.kernel.org # 4.4+
+Signed-off-by: Josef Bacik <josef@toxicpanda.com>
+Reviewed-by: David Sterba <dsterba@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/file-item.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/fs/btrfs/file-item.c
++++ b/fs/btrfs/file-item.c
+@@ -599,7 +599,7 @@ int btrfs_del_csums(struct btrfs_trans_h
+       u64 end_byte = bytenr + len;
+       u64 csum_end;
+       struct extent_buffer *leaf;
+-      int ret;
++      int ret = 0;
+       u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
+       int blocksize_bits = fs_info->sb->s_blocksize_bits;
+@@ -615,6 +615,7 @@ int btrfs_del_csums(struct btrfs_trans_h
+               path->leave_spinning = 1;
+               ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+               if (ret > 0) {
++                      ret = 0;
+                       if (path->slots[0] == 0)
+                               break;
+                       path->slots[0]--;
+@@ -671,7 +672,7 @@ int btrfs_del_csums(struct btrfs_trans_h
+                       ret = btrfs_del_items(trans, root, path,
+                                             path->slots[0], del_nr);
+                       if (ret)
+-                              goto out;
++                              break;
+                       if (key.offset == bytenr)
+                               break;
+               } else if (key.offset < bytenr && csum_end > end_byte) {
+@@ -715,8 +716,9 @@ int btrfs_del_csums(struct btrfs_trans_h
+                       ret = btrfs_split_item(trans, root, path, &key, offset);
+                       if (ret && ret != -EAGAIN) {
+                               btrfs_abort_transaction(trans, ret);
+-                              goto out;
++                              break;
+                       }
++                      ret = 0;
+                       key.offset = end_byte - 1;
+               } else {
+@@ -726,8 +728,6 @@ int btrfs_del_csums(struct btrfs_trans_h
+               }
+               btrfs_release_path(path);
+       }
+-      ret = 0;
+-out:
+       btrfs_free_path(path);
+       return ret;
+ }
diff --git a/queue-4.14/nfc-fix-null-ptr-dereference-in-llcp_sock_getname-after-failed-connect.patch b/queue-4.14/nfc-fix-null-ptr-dereference-in-llcp_sock_getname-after-failed-connect.patch
new file mode 100644 (file)
index 0000000..f752597
--- /dev/null
@@ -0,0 +1,59 @@
+From 4ac06a1e013cf5fdd963317ffd3b968560f33bba Mon Sep 17 00:00:00 2001
+From: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+Date: Mon, 31 May 2021 09:21:38 +0200
+Subject: nfc: fix NULL ptr dereference in llcp_sock_getname() after failed connect
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+
+commit 4ac06a1e013cf5fdd963317ffd3b968560f33bba upstream.
+
+It's possible to trigger NULL pointer dereference by local unprivileged
+user, when calling getsockname() after failed bind() (e.g. the bind
+fails because LLCP_SAP_MAX used as SAP):
+
+  BUG: kernel NULL pointer dereference, address: 0000000000000000
+  CPU: 1 PID: 426 Comm: llcp_sock_getna Not tainted 5.13.0-rc2-next-20210521+ #9
+  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1 04/01/2014
+  Call Trace:
+   llcp_sock_getname+0xb1/0xe0
+   __sys_getpeername+0x95/0xc0
+   ? lockdep_hardirqs_on_prepare+0xd5/0x180
+   ? syscall_enter_from_user_mode+0x1c/0x40
+   __x64_sys_getpeername+0x11/0x20
+   do_syscall_64+0x36/0x70
+   entry_SYSCALL_64_after_hwframe+0x44/0xae
+
+This can be reproduced with Syzkaller C repro (bind followed by
+getpeername):
+https://syzkaller.appspot.com/x/repro.c?x=14def446e00000
+
+Cc: <stable@vger.kernel.org>
+Fixes: d646960f7986 ("NFC: Initial LLCP support")
+Reported-by: syzbot+80fb126e7f7d8b1a5914@syzkaller.appspotmail.com
+Reported-by: butt3rflyh4ck <butterflyhuangxx@gmail.com>
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
+Link: https://lore.kernel.org/r/20210531072138.5219-1-krzysztof.kozlowski@canonical.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/nfc/llcp_sock.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/net/nfc/llcp_sock.c
++++ b/net/nfc/llcp_sock.c
+@@ -122,6 +122,7 @@ static int llcp_sock_bind(struct socket
+       if (!llcp_sock->service_name) {
+               nfc_llcp_local_put(llcp_sock->local);
+               llcp_sock->local = NULL;
++              llcp_sock->dev = NULL;
+               ret = -ENOMEM;
+               goto put_dev;
+       }
+@@ -131,6 +132,7 @@ static int llcp_sock_bind(struct socket
+               llcp_sock->local = NULL;
+               kfree(llcp_sock->service_name);
+               llcp_sock->service_name = NULL;
++              llcp_sock->dev = NULL;
+               ret = -EADDRINUSE;
+               goto put_dev;
+       }
diff --git a/queue-4.14/ocfs2-fix-data-corruption-by-fallocate.patch b/queue-4.14/ocfs2-fix-data-corruption-by-fallocate.patch
new file mode 100644 (file)
index 0000000..30c3a68
--- /dev/null
@@ -0,0 +1,148 @@
+From 6bba4471f0cc1296fe3c2089b9e52442d3074b2e Mon Sep 17 00:00:00 2001
+From: Junxiao Bi <junxiao.bi@oracle.com>
+Date: Fri, 4 Jun 2021 20:01:42 -0700
+Subject: ocfs2: fix data corruption by fallocate
+
+From: Junxiao Bi <junxiao.bi@oracle.com>
+
+commit 6bba4471f0cc1296fe3c2089b9e52442d3074b2e upstream.
+
+When fallocate punches holes out of inode size, if original isize is in
+the middle of last cluster, then the part from isize to the end of the
+cluster will be zeroed with buffer write, at that time isize is not yet
+updated to match the new size, if writeback is kicked in, it will invoke
+ocfs2_writepage()->block_write_full_page() where the pages out of inode
+size will be dropped.  That will cause file corruption.  Fix this by
+zero out eof blocks when extending the inode size.
+
+Running the following command with qemu-image 4.2.1 can get a corrupted
+coverted image file easily.
+
+    qemu-img convert -p -t none -T none -f qcow2 $qcow_image \
+             -O qcow2 -o compat=1.1 $qcow_image.conv
+
+The usage of fallocate in qemu is like this, it first punches holes out
+of inode size, then extend the inode size.
+
+    fallocate(11, FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, 2276196352, 65536) = 0
+    fallocate(11, 0, 2276196352, 65536) = 0
+
+v1: https://www.spinics.net/lists/linux-fsdevel/msg193999.html
+v2: https://lore.kernel.org/linux-fsdevel/20210525093034.GB4112@quack2.suse.cz/T/
+
+Link: https://lkml.kernel.org/r/20210528210648.9124-1-junxiao.bi@oracle.com
+Signed-off-by: Junxiao Bi <junxiao.bi@oracle.com>
+Reviewed-by: Joseph Qi <joseph.qi@linux.alibaba.com>
+Cc: Jan Kara <jack@suse.cz>
+Cc: Mark Fasheh <mark@fasheh.com>
+Cc: Joel Becker <jlbec@evilplan.org>
+Cc: Changwei Ge <gechangwei@live.cn>
+Cc: Gang He <ghe@suse.com>
+Cc: Jun Piao <piaojun@huawei.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/ocfs2/file.c |   55 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 50 insertions(+), 5 deletions(-)
+
+--- a/fs/ocfs2/file.c
++++ b/fs/ocfs2/file.c
+@@ -1862,6 +1862,45 @@ out:
+ }
+ /*
++ * zero out partial blocks of one cluster.
++ *
++ * start: file offset where zero starts, will be made upper block aligned.
++ * len: it will be trimmed to the end of current cluster if "start + len"
++ *      is bigger than it.
++ */
++static int ocfs2_zeroout_partial_cluster(struct inode *inode,
++                                      u64 start, u64 len)
++{
++      int ret;
++      u64 start_block, end_block, nr_blocks;
++      u64 p_block, offset;
++      u32 cluster, p_cluster, nr_clusters;
++      struct super_block *sb = inode->i_sb;
++      u64 end = ocfs2_align_bytes_to_clusters(sb, start);
++
++      if (start + len < end)
++              end = start + len;
++
++      start_block = ocfs2_blocks_for_bytes(sb, start);
++      end_block = ocfs2_blocks_for_bytes(sb, end);
++      nr_blocks = end_block - start_block;
++      if (!nr_blocks)
++              return 0;
++
++      cluster = ocfs2_bytes_to_clusters(sb, start);
++      ret = ocfs2_get_clusters(inode, cluster, &p_cluster,
++                              &nr_clusters, NULL);
++      if (ret)
++              return ret;
++      if (!p_cluster)
++              return 0;
++
++      offset = start_block - ocfs2_clusters_to_blocks(sb, cluster);
++      p_block = ocfs2_clusters_to_blocks(sb, p_cluster) + offset;
++      return sb_issue_zeroout(sb, p_block, nr_blocks, GFP_NOFS);
++}
++
++/*
+  * Parts of this function taken from xfs_change_file_space()
+  */
+ static int __ocfs2_change_file_space(struct file *file, struct inode *inode,
+@@ -1871,7 +1910,7 @@ static int __ocfs2_change_file_space(str
+ {
+       int ret;
+       s64 llen;
+-      loff_t size;
++      loff_t size, orig_isize;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       struct buffer_head *di_bh = NULL;
+       handle_t *handle;
+@@ -1902,6 +1941,7 @@ static int __ocfs2_change_file_space(str
+               goto out_inode_unlock;
+       }
++      orig_isize = i_size_read(inode);
+       switch (sr->l_whence) {
+       case 0: /*SEEK_SET*/
+               break;
+@@ -1909,7 +1949,7 @@ static int __ocfs2_change_file_space(str
+               sr->l_start += f_pos;
+               break;
+       case 2: /*SEEK_END*/
+-              sr->l_start += i_size_read(inode);
++              sr->l_start += orig_isize;
+               break;
+       default:
+               ret = -EINVAL;
+@@ -1963,6 +2003,14 @@ static int __ocfs2_change_file_space(str
+       default:
+               ret = -EINVAL;
+       }
++
++      /* zeroout eof blocks in the cluster. */
++      if (!ret && change_size && orig_isize < size) {
++              ret = ocfs2_zeroout_partial_cluster(inode, orig_isize,
++                                      size - orig_isize);
++              if (!ret)
++                      i_size_write(inode, size);
++      }
+       up_write(&OCFS2_I(inode)->ip_alloc_sem);
+       if (ret) {
+               mlog_errno(ret);
+@@ -1979,9 +2027,6 @@ static int __ocfs2_change_file_space(str
+               goto out_inode_unlock;
+       }
+-      if (change_size && i_size_read(inode) < size)
+-              i_size_write(inode, size);
+-
+       inode->i_ctime = inode->i_mtime = current_time(inode);
+       ret = ocfs2_mark_inode_dirty(handle, inode, di_bh);
+       if (ret < 0)
index 339886148504c55c6fca09b8a5baabf76f28e2a7..6f8c46d8cad8e520530fef34ddbfe8d4d578e93e 100644 (file)
@@ -19,4 +19,7 @@ net-caif-fix-memory-leak-in-cfusbl_device_notify.patch
 alsa-timer-fix-master-timer-notification.patch
 ext4-fix-bug-on-in-ext4_es_cache_extent-as-ext4_split_extent_at-failed.patch
 pid-take-a-reference-when-initializing-cad_pid.patch
+ocfs2-fix-data-corruption-by-fallocate.patch
+nfc-fix-null-ptr-dereference-in-llcp_sock_getname-after-failed-connect.patch
+btrfs-fix-error-handling-in-btrfs_del_csums.patch
 usb-dwc2-fix-build-in-periphal-only-mode.patch