From: Greg Kroah-Hartman Date: Sun, 5 Feb 2017 10:45:12 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v3.18.48~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=60f4c2b57e626b0e242b566ed06abccba5fabbd1;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: fs-break-out-of-iomap_file_buffered_write-on-fatal-signals.patch --- diff --git a/queue-4.9/firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch b/queue-4.9/firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch deleted file mode 100644 index 2d6bc4bbb31..00000000000 --- a/queue-4.9/firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 191e885a2e130e639bb0c8ee350d7047294f2ce6 Mon Sep 17 00:00:00 2001 -From: "Luis R. Rodriguez" -Date: Wed, 25 Jan 2017 10:31:52 -0800 -Subject: firmware: fix NULL pointer dereference in __fw_load_abort() - -From: Luis R. Rodriguez - -commit 191e885a2e130e639bb0c8ee350d7047294f2ce6 upstream. - -Since commit 5d47ec02c37ea6 ("firmware: Correct handling of -fw_state_wait() return value") fw_load_abort() could be called twice and -lead us to a kernel crash. This happens only when the firmware fallback -mechanism (regular or custom) is used. The fallback mechanism exposes a -sysfs interface for userspace to upload a file and notify the kernel -when the file is loaded and ready, or to cancel an upload by echo'ing -1 -into on the loading file: - -echo -n "-1" > /sys/$DEVPATH/loading - -This will call fw_load_abort(). Some distributions actually have a udev -rule in place to *always* immediately cancel all firmware fallback -mechanism requests (Debian), they have: - - $ cat /lib/udev/rules.d/50-firmware.rules - # stub for immediately telling the kernel that userspace firmware loading - # failed; necessary to avoid long timeouts with CONFIG_FW_LOADER_USER_HELPER=y - SUBSYSTEM=="firmware", ACTION=="add", ATTR{loading}="-1 - -Distributions with this udev rule would run into this crash only if the -fallback mechanism is used. Since most distributions disable by default -using the fallback mechanism (CONFIG_FW_LOADER_USER_HELPER_FALLBACK), -this would typicaly mean only 2 drivers which *require* the fallback -mechanism could typically incur a crash: drivers/firmware/dell_rbu.c and -the drivers/leds/leds-lp55xx-common.c driver. Distributions enabling -CONFIG_FW_LOADER_USER_HELPER_FALLBACK by default are obviously more -exposed to this crash. - -The crash happens because after commit 5b029624948d ("firmware: do not -use fw_lock for fw_state protection") and subsequent fix commit -5d47ec02c37ea6 ("firmware: Correct handling of fw_state_wait() return -value") a race can happen between this cancelation and the firmware -fw_state_wait_timeout() being woken up after a state change with which -fw_load_abort() as that calls swake_up(). Upon error -fw_state_wait_timeout() will also again call fw_load_abort() and trigger -a null reference. - -At first glance we could just fix this with a !buf check on -fw_load_abort() before accessing buf->fw_st, however there is a logical -issue in having a state machine used for the fallback mechanism and -preventing access from it once we abort as its inside the buf -(buf->fw_st). - -The firmware_class.c code is setting the buf to NULL to annotate an -abort has occurred. Replace this mechanism by simply using the state -check instead. All the other code in place already uses similar checks -for aborting as well so no further changes are needed. - -An oops can be reproduced with the new fw_fallback.sh fallback mechanism -cancellation test. Either cancelling the fallback mechanism or the -custom fallback mechanism triggers a crash. - -mcgrof@piggy ~/linux-next/tools/testing/selftests/firmware -(git::20170111-fw-fixes)$ sudo ./fw_fallback.sh - -./fw_fallback.sh: timeout works -./fw_fallback.sh: firmware comparison works -./fw_fallback.sh: fallback mechanism works - -[ this then sits here when it is trying the cancellation test ] - -Kernel log: - -test_firmware: loading 'nope-test-firmware.bin' -misc test_firmware: Direct firmware load for nope-test-firmware.bin failed with error -2 -misc test_firmware: Falling back to user helper -BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 -IP: _request_firmware+0xa27/0xad0 -PGD 0 - -Oops: 0000 [#1] SMP -Modules linked in: test_firmware(E) ... etc ... -CPU: 1 PID: 1396 Comm: fw_fallback.sh Tainted: G W E 4.10.0-rc3-next-20170111+ #30 -Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.10.1-0-g8891697-prebuilt.qemu-project.org 04/01/2014 -task: ffff9740b27f4340 task.stack: ffffbb15c0bc8000 -RIP: 0010:_request_firmware+0xa27/0xad0 -RSP: 0018:ffffbb15c0bcbd10 EFLAGS: 00010246 -RAX: 00000000fffffffe RBX: ffff9740afe5aa80 RCX: 0000000000000000 -RDX: ffff9740b27f4340 RSI: 0000000000000283 RDI: 0000000000000000 -RBP: ffffbb15c0bcbd90 R08: ffffbb15c0bcbcd8 R09: 0000000000000000 -R10: 0000000894a0d4b1 R11: 000000000000008c R12: ffffffffc0312480 -R13: 0000000000000005 R14: ffff9740b1c32400 R15: 00000000000003e8 -FS: 00007f8604422700(0000) GS:ffff9740bfc80000(0000) knlGS:0000000000000000 -CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 -CR2: 0000000000000038 CR3: 000000012164c000 CR4: 00000000000006e0 -Call Trace: - request_firmware+0x37/0x50 - trigger_request_store+0x79/0xd0 [test_firmware] - dev_attr_store+0x18/0x30 - sysfs_kf_write+0x37/0x40 - kernfs_fop_write+0x110/0x1a0 - __vfs_write+0x37/0x160 - ? _cond_resched+0x1a/0x50 - vfs_write+0xb5/0x1a0 - SyS_write+0x55/0xc0 - ? trace_do_page_fault+0x37/0xd0 - entry_SYSCALL_64_fastpath+0x1e/0xad -RIP: 0033:0x7f8603f49620 -RSP: 002b:00007fff6287b788 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 -RAX: ffffffffffffffda RBX: 000055c307b110a0 RCX: 00007f8603f49620 -RDX: 0000000000000016 RSI: 000055c3084d8a90 RDI: 0000000000000001 -RBP: 0000000000000016 R08: 000000000000c0ff R09: 000055c3084d6336 -R10: 000055c307b108b0 R11: 0000000000000246 R12: 000055c307b13c80 -R13: 000055c3084d6320 R14: 0000000000000000 R15: 00007fff6287b950 -Code: 9f 64 84 e8 9c 61 fe ff b8 f4 ff ff ff e9 6b f9 ff -ff 48 c7 c7 40 6b 8d 84 89 45 a8 e8 43 84 18 00 49 8b be 00 03 00 00 8b -45 a8 <83> 7f 38 02 74 08 e8 6e ec ff ff 8b 45 a8 49 c7 86 00 03 00 00 -RIP: _request_firmware+0xa27/0xad0 RSP: ffffbb15c0bcbd10 -CR2: 0000000000000038 ----[ end trace 6d94ac339c133e6f ]--- - -Fixes: 5d47ec02c37e ("firmware: Correct handling of fw_state_wait() return value") -Reported-and-Tested-by: Jakub Kicinski -Reported-and-Tested-by: Patrick Bruenn -Reported-by: Chris Wilson -Signed-off-by: Luis R. Rodriguez -Signed-off-by: Greg Kroah-Hartman - ---- - drivers/base/firmware_class.c | 5 +---- - 1 file changed, 1 insertion(+), 4 deletions(-) - ---- a/drivers/base/firmware_class.c -+++ b/drivers/base/firmware_class.c -@@ -491,9 +491,6 @@ static void fw_load_abort(struct firmwar - struct firmware_buf *buf = fw_priv->buf; - - __fw_load_abort(buf); -- -- /* avoid user action after loading abort */ -- fw_priv->buf = NULL; - } - - #define is_fw_load_aborted(buf) \ -@@ -647,7 +644,7 @@ static ssize_t firmware_loading_store(st - - mutex_lock(&fw_lock); - fw_buf = fw_priv->buf; -- if (!fw_buf) -+ if (fw_state_is_aborted(&fw_buf->fw_st)) - goto out; - - switch (loading) { diff --git a/queue-4.9/fs-break-out-of-iomap_file_buffered_write-on-fatal-signals.patch b/queue-4.9/fs-break-out-of-iomap_file_buffered_write-on-fatal-signals.patch new file mode 100644 index 00000000000..bb9c2cb9ec0 --- /dev/null +++ b/queue-4.9/fs-break-out-of-iomap_file_buffered_write-on-fatal-signals.patch @@ -0,0 +1,88 @@ +From d1908f52557b3230fbd63c0429f3b4b748bf2b6d Mon Sep 17 00:00:00 2001 +From: Michal Hocko +Date: Fri, 3 Feb 2017 13:13:26 -0800 +Subject: fs: break out of iomap_file_buffered_write on fatal signals + +From: Michal Hocko + +commit d1908f52557b3230fbd63c0429f3b4b748bf2b6d upstream. + +Tetsuo has noticed that an OOM stress test which performs large write +requests can cause the full memory reserves depletion. He has tracked +this down to the following path + + __alloc_pages_nodemask+0x436/0x4d0 + alloc_pages_current+0x97/0x1b0 + __page_cache_alloc+0x15d/0x1a0 mm/filemap.c:728 + pagecache_get_page+0x5a/0x2b0 mm/filemap.c:1331 + grab_cache_page_write_begin+0x23/0x40 mm/filemap.c:2773 + iomap_write_begin+0x50/0xd0 fs/iomap.c:118 + iomap_write_actor+0xb5/0x1a0 fs/iomap.c:190 + ? iomap_write_end+0x80/0x80 fs/iomap.c:150 + iomap_apply+0xb3/0x130 fs/iomap.c:79 + iomap_file_buffered_write+0x68/0xa0 fs/iomap.c:243 + ? iomap_write_end+0x80/0x80 + xfs_file_buffered_aio_write+0x132/0x390 [xfs] + ? remove_wait_queue+0x59/0x60 + xfs_file_write_iter+0x90/0x130 [xfs] + __vfs_write+0xe5/0x140 + vfs_write+0xc7/0x1f0 + ? syscall_trace_enter+0x1d0/0x380 + SyS_write+0x58/0xc0 + do_syscall_64+0x6c/0x200 + entry_SYSCALL64_slow_path+0x25/0x25 + +the oom victim has access to all memory reserves to make a forward +progress to exit easier. But iomap_file_buffered_write and other +callers of iomap_apply loop to complete the full request. We need to +check for fatal signals and back off with a short write instead. + +As the iomap_apply delegates all the work down to the actor we have to +hook into those. All callers that work with the page cache are calling +iomap_write_begin so we will check for signals there. dax_iomap_actor +has to handle the situation explicitly because it copies data to the +userspace directly. Other callers like iomap_page_mkwrite work on a +single page or iomap_fiemap_actor do not allocate memory based on the +given len. + +Fixes: 68a9f5e7007c ("xfs: implement iomap based buffered write path") +Link: http://lkml.kernel.org/r/20170201092706.9966-2-mhocko@kernel.org +Signed-off-by: Michal Hocko +Reported-by: Tetsuo Handa +Reviewed-by: Christoph Hellwig +Cc: Al Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/dax.c | 5 +++++ + fs/iomap.c | 3 +++ + 2 files changed, 8 insertions(+) + +--- a/fs/dax.c ++++ b/fs/dax.c +@@ -1270,6 +1270,11 @@ iomap_dax_actor(struct inode *inode, lof + struct blk_dax_ctl dax = { 0 }; + ssize_t map_len; + ++ if (fatal_signal_pending(current)) { ++ ret = -EINTR; ++ break; ++ } ++ + dax.sector = iomap->blkno + + (((pos & PAGE_MASK) - iomap->offset) >> 9); + dax.size = (length + offset + PAGE_SIZE - 1) & PAGE_MASK; +--- a/fs/iomap.c ++++ b/fs/iomap.c +@@ -113,6 +113,9 @@ iomap_write_begin(struct inode *inode, l + + BUG_ON(pos + len > iomap->offset + iomap->length); + ++ if (fatal_signal_pending(current)) ++ return -EINTR; ++ + page = grab_cache_page_write_begin(inode->i_mapping, index, flags); + if (!page) + return -ENOMEM; diff --git a/queue-4.9/series b/queue-4.9/series index ebbc630ccf9..31f9525b6c3 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -61,5 +61,5 @@ iio-dht11-use-usleep_range-instead-of-msleep-for-start-signal.patch iio-health-max30100-fixed-parenthesis-around-fifo-count-check.patch irqdomain-avoid-activating-interrupts-more-than-once.patch x86-irq-make-irq-activate-operations-symmetric.patch -firmware-fix-null-pointer-dereference-in-__fw_load_abort.patch iw_cxgb4-set-correct-fetchburstmax-for-qps.patch +fs-break-out-of-iomap_file_buffered_write-on-fatal-signals.patch