From e60deace459bd1032c26068b0894564f3503bc47 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Sat, 1 Aug 2020 17:58:03 -0400 Subject: [PATCH] Fixes for 4.4 Signed-off-by: Sasha Levin --- ...eakpoint-don-t-invoke-overflow-handl.patch | 86 ++++++++++ ...eger-underflow-at-struct-fbcon_ops-c.patch | 157 ++++++++++++++++++ queue-4.4/series | 4 + ...x-truncated-.bss-with-fdata-sections.patch | 54 ++++++ ...page-align-end-of-.page_aligned-sect.patch | 84 ++++++++++ 5 files changed, 385 insertions(+) create mode 100644 queue-4.4/arm-8986-1-hw_breakpoint-don-t-invoke-overflow-handl.patch create mode 100644 queue-4.4/fbdev-detect-integer-underflow-at-struct-fbcon_ops-c.patch create mode 100644 queue-4.4/x86-build-lto-fix-truncated-.bss-with-fdata-sections.patch create mode 100644 queue-4.4/x86-vmlinux.lds-page-align-end-of-.page_aligned-sect.patch diff --git a/queue-4.4/arm-8986-1-hw_breakpoint-don-t-invoke-overflow-handl.patch b/queue-4.4/arm-8986-1-hw_breakpoint-don-t-invoke-overflow-handl.patch new file mode 100644 index 00000000000..b33be7a3f67 --- /dev/null +++ b/queue-4.4/arm-8986-1-hw_breakpoint-don-t-invoke-overflow-handl.patch @@ -0,0 +1,86 @@ +From 41953ab8b82a6b368a29f41136e96573b995600e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Jun 2020 11:16:45 +0100 +Subject: ARM: 8986/1: hw_breakpoint: Don't invoke overflow handler on uaccess + watchpoints + +From: Will Deacon + +[ Upstream commit eec13b42d41b0f3339dcf0c4da43734427c68620 ] + +Unprivileged memory accesses generated by the so-called "translated" +instructions (e.g. LDRT) in kernel mode can cause user watchpoints to fire +unexpectedly. In such cases, the hw_breakpoint logic will invoke the user +overflow handler which will typically raise a SIGTRAP back to the current +task. This is futile when returning back to the kernel because (a) the +signal won't have been delivered and (b) userspace can't handle the thing +anyway. + +Avoid invoking the user overflow handler for watchpoints triggered by +kernel uaccess routines, and instead single-step over the faulting +instruction as we would if no overflow handler had been installed. + +Cc: +Fixes: f81ef4a920c8 ("ARM: 6356/1: hw-breakpoint: add ARM backend for the hw-breakpoint framework") +Reported-by: Luis Machado +Tested-by: Luis Machado +Signed-off-by: Will Deacon +Signed-off-by: Russell King +Signed-off-by: Sasha Levin +--- + arch/arm/kernel/hw_breakpoint.c | 27 ++++++++++++++++++++++----- + 1 file changed, 22 insertions(+), 5 deletions(-) + +diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c +index abcbea1ae30ba..78c6be1b27145 100644 +--- a/arch/arm/kernel/hw_breakpoint.c ++++ b/arch/arm/kernel/hw_breakpoint.c +@@ -688,6 +688,12 @@ static void disable_single_step(struct perf_event *bp) + arch_install_hw_breakpoint(bp); + } + ++static int watchpoint_fault_on_uaccess(struct pt_regs *regs, ++ struct arch_hw_breakpoint *info) ++{ ++ return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER; ++} ++ + static void watchpoint_handler(unsigned long addr, unsigned int fsr, + struct pt_regs *regs) + { +@@ -747,16 +753,27 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, + } + + pr_debug("watchpoint fired: address = 0x%x\n", info->trigger); ++ ++ /* ++ * If we triggered a user watchpoint from a uaccess routine, ++ * then handle the stepping ourselves since userspace really ++ * can't help us with this. ++ */ ++ if (watchpoint_fault_on_uaccess(regs, info)) ++ goto step; ++ + perf_bp_event(wp, regs); + + /* +- * If no overflow handler is present, insert a temporary +- * mismatch breakpoint so we can single-step over the +- * watchpoint trigger. ++ * Defer stepping to the overflow handler if one is installed. ++ * Otherwise, insert a temporary mismatch breakpoint so that ++ * we can single-step over the watchpoint trigger. + */ +- if (!wp->overflow_handler) +- enable_single_step(wp, instruction_pointer(regs)); ++ if (wp->overflow_handler) ++ goto unlock; + ++step: ++ enable_single_step(wp, instruction_pointer(regs)); + unlock: + rcu_read_unlock(); + } +-- +2.25.1 + diff --git a/queue-4.4/fbdev-detect-integer-underflow-at-struct-fbcon_ops-c.patch b/queue-4.4/fbdev-detect-integer-underflow-at-struct-fbcon_ops-c.patch new file mode 100644 index 00000000000..37b78146566 --- /dev/null +++ b/queue-4.4/fbdev-detect-integer-underflow-at-struct-fbcon_ops-c.patch @@ -0,0 +1,157 @@ +From c1cc1807f3c7dff53c23b0d9f9eabefa8818f399 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2020 10:51:02 +0900 +Subject: fbdev: Detect integer underflow at "struct fbcon_ops"->clear_margins. + +From: Tetsuo Handa + +[ Upstream commit 033724d6864245a11f8e04c066002e6ad22b3fd0 ] + +syzbot is reporting general protection fault in bitfill_aligned() [1] +caused by integer underflow in bit_clear_margins(). The cause of this +problem is when and how do_vc_resize() updates vc->vc_{cols,rows}. + +If vc_do_resize() fails (e.g. kzalloc() fails) when var.xres or var.yres +is going to shrink, vc->vc_{cols,rows} will not be updated. This allows +bit_clear_margins() to see info->var.xres < (vc->vc_cols * cw) or +info->var.yres < (vc->vc_rows * ch). Unexpectedly large rw or bh will +try to overrun the __iomem region and causes general protection fault. + +Also, vc_resize(vc, 0, 0) does not set vc->vc_{cols,rows} = 0 due to + + new_cols = (cols ? cols : vc->vc_cols); + new_rows = (lines ? lines : vc->vc_rows); + +exception. Since cols and lines are calculated as + + cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres); + rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres); + cols /= vc->vc_font.width; + rows /= vc->vc_font.height; + vc_resize(vc, cols, rows); + +in fbcon_modechanged(), var.xres < vc->vc_font.width makes cols = 0 +and var.yres < vc->vc_font.height makes rows = 0. This means that + + const int fd = open("/dev/fb0", O_ACCMODE); + struct fb_var_screeninfo var = { }; + ioctl(fd, FBIOGET_VSCREENINFO, &var); + var.xres = var.yres = 1; + ioctl(fd, FBIOPUT_VSCREENINFO, &var); + +easily reproduces integer underflow bug explained above. + +Of course, callers of vc_resize() are not handling vc_do_resize() failure +is bad. But we can't avoid vc_resize(vc, 0, 0) which returns 0. Therefore, +as a band-aid workaround, this patch checks integer underflow in +"struct fbcon_ops"->clear_margins call, assuming that +vc->vc_cols * vc->vc_font.width and vc->vc_rows * vc->vc_font.heigh do not +cause integer overflow. + +[1] https://syzkaller.appspot.com/bug?id=a565882df74fa76f10d3a6fec4be31098dbb37c6 + +Reported-and-tested-by: syzbot +Signed-off-by: Tetsuo Handa +Acked-by: Daniel Vetter +Cc: stable +Link: https://lore.kernel.org/r/20200715015102.3814-1-penguin-kernel@I-love.SAKURA.ne.jp +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + drivers/video/console/bitblit.c | 4 ++-- + drivers/video/console/fbcon_ccw.c | 4 ++-- + drivers/video/console/fbcon_cw.c | 4 ++-- + drivers/video/console/fbcon_ud.c | 4 ++-- + 4 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c +index dbfe4eecf12e5..05d1d36a56654 100644 +--- a/drivers/video/console/bitblit.c ++++ b/drivers/video/console/bitblit.c +@@ -216,7 +216,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, + region.color = 0; + region.rop = ROP_COPY; + +- if (rw && !bottom_only) { ++ if ((int) rw > 0 && !bottom_only) { + region.dx = info->var.xoffset + rs; + region.dy = 0; + region.width = rw; +@@ -224,7 +224,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, + info->fbops->fb_fillrect(info, ®ion); + } + +- if (bh) { ++ if ((int) bh > 0) { + region.dx = info->var.xoffset; + region.dy = info->var.yoffset + bs; + region.width = rs; +diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c +index 5a3cbf6dff4d9..34da8bba9273a 100644 +--- a/drivers/video/console/fbcon_ccw.c ++++ b/drivers/video/console/fbcon_ccw.c +@@ -201,7 +201,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, + region.color = 0; + region.rop = ROP_COPY; + +- if (rw && !bottom_only) { ++ if ((int) rw > 0 && !bottom_only) { + region.dx = 0; + region.dy = info->var.yoffset; + region.height = rw; +@@ -209,7 +209,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, + info->fbops->fb_fillrect(info, ®ion); + } + +- if (bh) { ++ if ((int) bh > 0) { + region.dx = info->var.xoffset + bs; + region.dy = 0; + region.height = info->var.yres_virtual; +diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c +index e7ee44db4e98b..0b552b3fc22ab 100644 +--- a/drivers/video/console/fbcon_cw.c ++++ b/drivers/video/console/fbcon_cw.c +@@ -184,7 +184,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, + region.color = 0; + region.rop = ROP_COPY; + +- if (rw && !bottom_only) { ++ if ((int) rw > 0 && !bottom_only) { + region.dx = 0; + region.dy = info->var.yoffset + rs; + region.height = rw; +@@ -192,7 +192,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, + info->fbops->fb_fillrect(info, ®ion); + } + +- if (bh) { ++ if ((int) bh > 0) { + region.dx = info->var.xoffset; + region.dy = info->var.yoffset; + region.height = info->var.yres; +diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c +index 19e3714abfe8f..7f62efe2da526 100644 +--- a/drivers/video/console/fbcon_ud.c ++++ b/drivers/video/console/fbcon_ud.c +@@ -231,7 +231,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, + region.color = 0; + region.rop = ROP_COPY; + +- if (rw && !bottom_only) { ++ if ((int) rw > 0 && !bottom_only) { + region.dy = 0; + region.dx = info->var.xoffset; + region.width = rw; +@@ -239,7 +239,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, + info->fbops->fb_fillrect(info, ®ion); + } + +- if (bh) { ++ if ((int) bh > 0) { + region.dy = info->var.yoffset; + region.dx = info->var.xoffset; + region.height = bh; +-- +2.25.1 + diff --git a/queue-4.4/series b/queue-4.4/series index e2240b7f195..4169d437f9c 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -12,3 +12,7 @@ drm-hold-gem-reference-until-object-is-no-longer-accessed.patch arm-percpu.h-fix-build-error.patch f2fs-check-memory-boundary-by-insane-namelen.patch f2fs-check-if-file-namelen-exceeds-max-value.patch +arm-8986-1-hw_breakpoint-don-t-invoke-overflow-handl.patch +x86-build-lto-fix-truncated-.bss-with-fdata-sections.patch +x86-vmlinux.lds-page-align-end-of-.page_aligned-sect.patch +fbdev-detect-integer-underflow-at-struct-fbcon_ops-c.patch diff --git a/queue-4.4/x86-build-lto-fix-truncated-.bss-with-fdata-sections.patch b/queue-4.4/x86-build-lto-fix-truncated-.bss-with-fdata-sections.patch new file mode 100644 index 00000000000..ab12d8fdad6 --- /dev/null +++ b/queue-4.4/x86-build-lto-fix-truncated-.bss-with-fdata-sections.patch @@ -0,0 +1,54 @@ +From 08dfba9cb1d8b35c132726a0ab8adb8785832714 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 15 Apr 2019 09:49:56 -0700 +Subject: x86/build/lto: Fix truncated .bss with -fdata-sections + +From: Sami Tolvanen + +[ Upstream commit 6a03469a1edc94da52b65478f1e00837add869a3 ] + +With CONFIG_LD_DEAD_CODE_DATA_ELIMINATION=y, we compile the kernel with +-fdata-sections, which also splits the .bss section. + +The new section, with a new .bss.* name, which pattern gets missed by the +main x86 linker script which only expects the '.bss' name. This results +in the discarding of the second part and a too small, truncated .bss +section and an unhappy, non-working kernel. + +Use the common BSS_MAIN macro in the linker script to properly capture +and merge all the generated BSS sections. + +Signed-off-by: Sami Tolvanen +Reviewed-by: Nick Desaulniers +Reviewed-by: Kees Cook +Cc: Borislav Petkov +Cc: Kees Cook +Cc: Linus Torvalds +Cc: Nicholas Piggin +Cc: Nick Desaulniers +Cc: Peter Zijlstra +Cc: Thomas Gleixner +Link: http://lkml.kernel.org/r/20190415164956.124067-1-samitolvanen@google.com +[ Extended the changelog. ] +Signed-off-by: Ingo Molnar +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/vmlinux.lds.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index b05da220ea0a2..9b185142219b9 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -330,7 +330,7 @@ SECTIONS + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + __bss_start = .; + *(.bss..page_aligned) +- *(.bss) ++ *(BSS_MAIN) + . = ALIGN(PAGE_SIZE); + __bss_stop = .; + } +-- +2.25.1 + diff --git a/queue-4.4/x86-vmlinux.lds-page-align-end-of-.page_aligned-sect.patch b/queue-4.4/x86-vmlinux.lds-page-align-end-of-.page_aligned-sect.patch new file mode 100644 index 00000000000..688ff70971c --- /dev/null +++ b/queue-4.4/x86-vmlinux.lds-page-align-end-of-.page_aligned-sect.patch @@ -0,0 +1,84 @@ +From e1c399c0a0f5bc0f8cf762a8a9a4910d22e0304b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Jul 2020 11:34:48 +0200 +Subject: x86, vmlinux.lds: Page-align end of ..page_aligned sections + +From: Joerg Roedel + +[ Upstream commit de2b41be8fcccb2f5b6c480d35df590476344201 ] + +On x86-32 the idt_table with 256 entries needs only 2048 bytes. It is +page-aligned, but the end of the .bss..page_aligned section is not +guaranteed to be page-aligned. + +As a result, objects from other .bss sections may end up on the same 4k +page as the idt_table, and will accidentially get mapped read-only during +boot, causing unexpected page-faults when the kernel writes to them. + +This could be worked around by making the objects in the page aligned +sections page sized, but that's wrong. + +Explicit sections which store only page aligned objects have an implicit +guarantee that the object is alone in the page in which it is placed. That +works for all objects except the last one. That's inconsistent. + +Enforcing page sized objects for these sections would wreckage memory +sanitizers, because the object becomes artificially larger than it should +be and out of bound access becomes legit. + +Align the end of the .bss..page_aligned and .data..page_aligned section on +page-size so all objects places in these sections are guaranteed to have +their own page. + +[ tglx: Amended changelog ] + +Signed-off-by: Joerg Roedel +Signed-off-by: Thomas Gleixner +Reviewed-by: Kees Cook +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/20200721093448.10417-1-joro@8bytes.org +Signed-off-by: Sasha Levin +--- + arch/x86/kernel/vmlinux.lds.S | 1 + + include/asm-generic/vmlinux.lds.h | 5 ++++- + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S +index 9b185142219b9..5cdd7dc7b9941 100644 +--- a/arch/x86/kernel/vmlinux.lds.S ++++ b/arch/x86/kernel/vmlinux.lds.S +@@ -330,6 +330,7 @@ SECTIONS + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { + __bss_start = .; + *(.bss..page_aligned) ++ . = ALIGN(PAGE_SIZE); + *(BSS_MAIN) + . = ALIGN(PAGE_SIZE); + __bss_stop = .; +diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h +index a461b6604fd9d..49e373792fc15 100644 +--- a/include/asm-generic/vmlinux.lds.h ++++ b/include/asm-generic/vmlinux.lds.h +@@ -233,7 +233,8 @@ + + #define PAGE_ALIGNED_DATA(page_align) \ + . = ALIGN(page_align); \ +- *(.data..page_aligned) ++ *(.data..page_aligned) \ ++ . = ALIGN(page_align); + + #define READ_MOSTLY_DATA(align) \ + . = ALIGN(align); \ +@@ -572,7 +573,9 @@ + . = ALIGN(bss_align); \ + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { \ + BSS_FIRST_SECTIONS \ ++ . = ALIGN(PAGE_SIZE); \ + *(.bss..page_aligned) \ ++ . = ALIGN(PAGE_SIZE); \ + *(.dynbss) \ + *(.bss) \ + *(COMMON) \ +-- +2.25.1 + -- 2.47.3