]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Sep 2021 13:21:17 +0000 (15:21 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Sep 2021 13:21:17 +0000 (15:21 +0200)
added patches:
qnx4-work-around-gcc-false-positive-warning-bug.patch
xen-balloon-fix-balloon-kthread-freezing.patch

queue-4.19/qnx4-work-around-gcc-false-positive-warning-bug.patch [new file with mode: 0644]
queue-4.19/series
queue-4.19/xen-balloon-fix-balloon-kthread-freezing.patch [new file with mode: 0644]

diff --git a/queue-4.19/qnx4-work-around-gcc-false-positive-warning-bug.patch b/queue-4.19/qnx4-work-around-gcc-false-positive-warning-bug.patch
new file mode 100644 (file)
index 0000000..7785286
--- /dev/null
@@ -0,0 +1,120 @@
+From d5f6545934c47e97c0b48a645418e877b452a992 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Mon, 20 Sep 2021 10:26:21 -0700
+Subject: qnx4: work around gcc false positive warning bug
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit d5f6545934c47e97c0b48a645418e877b452a992 upstream.
+
+In commit b7213ffa0e58 ("qnx4: avoid stringop-overread errors") I tried
+to teach gcc about how the directory entry structure can be two
+different things depending on a status flag.  It made the code clearer,
+and it seemed to make gcc happy.
+
+However, Arnd points to a gcc bug, where despite using two different
+members of a union, gcc then gets confused, and uses the size of one of
+the members to decide if a string overrun happens.  And not necessarily
+the rigth one.
+
+End result: with some configurations, gcc-11 will still complain about
+the source buffer size being overread:
+
+  fs/qnx4/dir.c: In function 'qnx4_readdir':
+  fs/qnx4/dir.c:76:32: error: 'strnlen' specified bound [16, 48] exceeds source size 1 [-Werror=stringop-overread]
+     76 |                         size = strnlen(name, size);
+        |                                ^~~~~~~~~~~~~~~~~~~
+  fs/qnx4/dir.c:26:22: note: source object declared here
+     26 |                 char de_name;
+        |                      ^~~~~~~
+
+because gcc will get confused about which union member entry is actually
+getting accessed, even when the source code is very clear about it.  Gcc
+internally will have combined two "redundant" pointers (pointing to
+different union elements that are at the same offset), and takes the
+size checking from one or the other - not necessarily the right one.
+
+This is clearly a gcc bug, but we can work around it fairly easily.  The
+biggest thing here is the big honking comment about why we do what we
+do.
+
+Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6
+Reported-and-tested-by: Arnd Bergmann <arnd@kernel.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/qnx4/dir.c |   36 +++++++++++++++++++++++++++---------
+ 1 file changed, 27 insertions(+), 9 deletions(-)
+
+--- a/fs/qnx4/dir.c
++++ b/fs/qnx4/dir.c
+@@ -20,12 +20,33 @@
+  * depending on the status field in the last byte. The
+  * first byte is where the name start either way, and a
+  * zero means it's empty.
++ *
++ * Also, due to a bug in gcc, we don't want to use the
++ * real (differently sized) name arrays in the inode and
++ * link entries, but always the 'de_name[]' one in the
++ * fake struct entry.
++ *
++ * See
++ *
++ *   https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578#c6
++ *
++ * for details, but basically gcc will take the size of the
++ * 'name' array from one of the used union entries randomly.
++ *
++ * This use of 'de_name[]' (48 bytes) avoids the false positive
++ * warnings that would happen if gcc decides to use 'inode.di_name'
++ * (16 bytes) even when the pointer and size were to come from
++ * 'link.dl_name' (48 bytes).
++ *
++ * In all cases the actual name pointer itself is the same, it's
++ * only the gcc internal 'what is the size of this field' logic
++ * that can get confused.
+  */
+ union qnx4_directory_entry {
+       struct {
+-              char de_name;
+-              char de_pad[62];
+-              char de_status;
++              const char de_name[48];
++              u8 de_pad[15];
++              u8 de_status;
+       };
+       struct qnx4_inode_entry inode;
+       struct qnx4_link_info link;
+@@ -53,29 +74,26 @@ static int qnx4_readdir(struct file *fil
+               ix = (ctx->pos >> QNX4_DIR_ENTRY_SIZE_BITS) % QNX4_INODES_PER_BLOCK;
+               for (; ix < QNX4_INODES_PER_BLOCK; ix++, ctx->pos += QNX4_DIR_ENTRY_SIZE) {
+                       union qnx4_directory_entry *de;
+-                      const char *name;
+                       offset = ix * QNX4_DIR_ENTRY_SIZE;
+                       de = (union qnx4_directory_entry *) (bh->b_data + offset);
+-                      if (!de->de_name)
++                      if (!de->de_name[0])
+                               continue;
+                       if (!(de->de_status & (QNX4_FILE_USED|QNX4_FILE_LINK)))
+                               continue;
+                       if (!(de->de_status & QNX4_FILE_LINK)) {
+                               size = sizeof(de->inode.di_fname);
+-                              name = de->inode.di_fname;
+                               ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
+                       } else {
+                               size = sizeof(de->link.dl_fname);
+-                              name = de->link.dl_fname;
+                               ino = ( le32_to_cpu(de->link.dl_inode_blk) - 1 ) *
+                                       QNX4_INODES_PER_BLOCK +
+                                       de->link.dl_inode_ndx;
+                       }
+-                      size = strnlen(name, size);
++                      size = strnlen(de->de_name, size);
+                       QNX4DEBUG((KERN_INFO "qnx4_readdir:%.*s\n", size, name));
+-                      if (!dir_emit(ctx, name, size, ino, DT_UNKNOWN)) {
++                      if (!dir_emit(ctx, de->de_name, size, ino, DT_UNKNOWN)) {
+                               brelse(bh);
+                               return 0;
+                       }
index 2b99d63c64d933fd1e67dcf978038d28e3352316..1d9c3384ca2ad99bf49c49b2218d5d76adf69ae5 100644 (file)
@@ -51,3 +51,5 @@ tcp-address-problems-caused-by-edt-misshaps.patch
 tcp-always-set-retrans_stamp-on-recovery.patch
 tcp-create-a-helper-to-model-exponential-backoff.patch
 tcp-adjust-rto_base-in-retransmits_timed_out.patch
+xen-balloon-fix-balloon-kthread-freezing.patch
+qnx4-work-around-gcc-false-positive-warning-bug.patch
diff --git a/queue-4.19/xen-balloon-fix-balloon-kthread-freezing.patch b/queue-4.19/xen-balloon-fix-balloon-kthread-freezing.patch
new file mode 100644 (file)
index 0000000..45cb419
--- /dev/null
@@ -0,0 +1,37 @@
+From 96f5bd03e1be606987644b71899ea56a8d05f825 Mon Sep 17 00:00:00 2001
+From: Juergen Gross <jgross@suse.com>
+Date: Mon, 20 Sep 2021 12:03:45 +0200
+Subject: xen/balloon: fix balloon kthread freezing
+
+From: Juergen Gross <jgross@suse.com>
+
+commit 96f5bd03e1be606987644b71899ea56a8d05f825 upstream.
+
+Commit 8480ed9c2bbd56 ("xen/balloon: use a kernel thread instead a
+workqueue") switched the Xen balloon driver to use a kernel thread.
+Unfortunately the patch omitted to call try_to_freeze() or to use
+wait_event_freezable_timeout(), causing a system suspend to fail.
+
+Fixes: 8480ed9c2bbd56 ("xen/balloon: use a kernel thread instead a workqueue")
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
+Link: https://lore.kernel.org/r/20210920100345.21939-1-jgross@suse.com
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/balloon.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/xen/balloon.c
++++ b/drivers/xen/balloon.c
+@@ -539,8 +539,8 @@ static int balloon_thread(void *unused)
+                       timeout = 3600 * HZ;
+               credit = current_credit();
+-              wait_event_interruptible_timeout(balloon_thread_wq,
+-                               balloon_thread_cond(state, credit), timeout);
++              wait_event_freezable_timeout(balloon_thread_wq,
++                      balloon_thread_cond(state, credit), timeout);
+               if (kthread_should_stop())
+                       return 0;