From: Greg Kroah-Hartman Date: Sat, 1 Sep 2018 21:36:54 +0000 (-0700) Subject: 4.4-stable patches X-Git-Tag: v3.18.121~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f7a9c07c3425ff113f98f8a214891c7734af3521;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: fuse-add-missed-unlock_page-to-fuse_readpages_fill.patch fuse-don-t-access-pipe-buffers-without-pipe_lock.patch fuse-fix-double-request_end.patch fuse-fix-oops-at-process_init_reply.patch fuse-fix-unlocked-access-to-processing-queue.patch fuse-umount-should-wait-for-all-requests.patch x86-process-re-export-start_thread.patch x86-speculation-l1tf-fix-off-by-one-error-when-warning-that-system-has-too-much-ram.patch x86-speculation-l1tf-fix-overflow-in-l1tf_pfn_limit-on-32bit.patch x86-speculation-l1tf-suggest-what-to-do-on-systems-with-too-much-ram.patch --- diff --git a/queue-4.4/fuse-add-missed-unlock_page-to-fuse_readpages_fill.patch b/queue-4.4/fuse-add-missed-unlock_page-to-fuse_readpages_fill.patch new file mode 100644 index 00000000000..48ce7b15280 --- /dev/null +++ b/queue-4.4/fuse-add-missed-unlock_page-to-fuse_readpages_fill.patch @@ -0,0 +1,31 @@ +From 109728ccc5933151c68d1106e4065478a487a323 Mon Sep 17 00:00:00 2001 +From: Kirill Tkhai +Date: Thu, 19 Jul 2018 15:49:39 +0300 +Subject: fuse: Add missed unlock_page() to fuse_readpages_fill() + +From: Kirill Tkhai + +commit 109728ccc5933151c68d1106e4065478a487a323 upstream. + +The above error path returns with page unlocked, so this place seems also +to behave the same. + +Fixes: f8dbdf81821b ("fuse: rework fuse_readpages()") +Signed-off-by: Kirill Tkhai +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/file.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -879,6 +879,7 @@ static int fuse_readpages_fill(void *_da + } + + if (WARN_ON(req->num_pages >= req->max_pages)) { ++ unlock_page(page); + fuse_put_request(fc, req); + return -EIO; + } diff --git a/queue-4.4/fuse-don-t-access-pipe-buffers-without-pipe_lock.patch b/queue-4.4/fuse-don-t-access-pipe-buffers-without-pipe_lock.patch new file mode 100644 index 00000000000..60fb81e6955 --- /dev/null +++ b/queue-4.4/fuse-don-t-access-pipe-buffers-without-pipe_lock.patch @@ -0,0 +1,45 @@ +From a2477b0e67c52f4364a47c3ad70902bc2a61bd4c Mon Sep 17 00:00:00 2001 +From: Andrey Ryabinin +Date: Tue, 17 Jul 2018 19:00:33 +0300 +Subject: fuse: Don't access pipe->buffers without pipe_lock() + +From: Andrey Ryabinin + +commit a2477b0e67c52f4364a47c3ad70902bc2a61bd4c upstream. + +fuse_dev_splice_write() reads pipe->buffers to determine the size of +'bufs' array before taking the pipe_lock(). This is not safe as +another thread might change the 'pipe->buffers' between the allocation +and taking the pipe_lock(). So we end up with too small 'bufs' array. + +Move the bufs allocations inside pipe_lock()/pipe_unlock() to fix this. + +Fixes: dd3bb14f44a6 ("fuse: support splice() writing to fuse device") +Signed-off-by: Andrey Ryabinin +Cc: # v2.6.35 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dev.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -1991,11 +1991,14 @@ static ssize_t fuse_dev_splice_write(str + if (!fud) + return -EPERM; + ++ pipe_lock(pipe); ++ + bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); +- if (!bufs) ++ if (!bufs) { ++ pipe_unlock(pipe); + return -ENOMEM; ++ } + +- pipe_lock(pipe); + nbuf = 0; + rem = 0; + for (idx = 0; idx < pipe->nrbufs && rem < len; idx++) diff --git a/queue-4.4/fuse-fix-double-request_end.patch b/queue-4.4/fuse-fix-double-request_end.patch new file mode 100644 index 00000000000..bec92d0abe2 --- /dev/null +++ b/queue-4.4/fuse-fix-double-request_end.patch @@ -0,0 +1,59 @@ +From 87114373ea507895a62afb10d2910bd9adac35a8 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Thu, 26 Jul 2018 16:13:11 +0200 +Subject: fuse: fix double request_end() + +From: Miklos Szeredi + +commit 87114373ea507895a62afb10d2910bd9adac35a8 upstream. + +Refcounting of request is broken when fuse_abort_conn() is called and +request is on the fpq->io list: + + - ref is taken too late + - then it is not dropped + +Fixes: 0d8e84b0432b ("fuse: simplify request abort") +Cc: # v4.2 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dev.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -382,7 +382,7 @@ static void request_end(struct fuse_conn + struct fuse_iqueue *fiq = &fc->iq; + + if (test_and_set_bit(FR_FINISHED, &req->flags)) +- return; ++ goto out_put_req; + + spin_lock(&fiq->waitq.lock); + list_del_init(&req->intr_entry); +@@ -412,6 +412,7 @@ static void request_end(struct fuse_conn + wake_up(&req->waitq); + if (req->end) + req->end(fc, req); ++out_put_req: + fuse_put_request(fc, req); + } + +@@ -2154,6 +2155,7 @@ void fuse_abort_conn(struct fuse_conn *f + set_bit(FR_ABORTED, &req->flags); + if (!test_bit(FR_LOCKED, &req->flags)) { + set_bit(FR_PRIVATE, &req->flags); ++ __fuse_get_request(req); + list_move(&req->list, &to_end1); + } + spin_unlock(&req->waitq.lock); +@@ -2180,7 +2182,6 @@ void fuse_abort_conn(struct fuse_conn *f + + while (!list_empty(&to_end1)) { + req = list_first_entry(&to_end1, struct fuse_req, list); +- __fuse_get_request(req); + list_del_init(&req->list); + request_end(fc, req); + } diff --git a/queue-4.4/fuse-fix-oops-at-process_init_reply.patch b/queue-4.4/fuse-fix-oops-at-process_init_reply.patch new file mode 100644 index 00000000000..a7abf1477c8 --- /dev/null +++ b/queue-4.4/fuse-fix-oops-at-process_init_reply.patch @@ -0,0 +1,85 @@ +From e8f3bd773d22f488724dffb886a1618da85c2966 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Thu, 26 Jul 2018 16:13:11 +0200 +Subject: fuse: Fix oops at process_init_reply() + +From: Miklos Szeredi + +commit e8f3bd773d22f488724dffb886a1618da85c2966 upstream. + +syzbot is hitting NULL pointer dereference at process_init_reply(). +This is because deactivate_locked_super() is called before response for +initial request is processed. + +Fix this by aborting and waiting for all requests (including FUSE_INIT) +before resetting fc->sb. + +Original patch by Tetsuo Handa . + +Reported-by: syzbot +Fixes: e27c9d3877a0 ("fuse: fuse: add time_gran to INIT_OUT") +Cc: # v3.19 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/inode.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -379,11 +379,6 @@ static void fuse_put_super(struct super_ + { + struct fuse_conn *fc = get_fuse_conn_super(sb); + +- fuse_send_destroy(fc); +- +- fuse_abort_conn(fc); +- fuse_wait_aborted(fc); +- + mutex_lock(&fuse_mutex); + list_del(&fc->entry); + fuse_ctl_remove_conn(fc); +@@ -1174,16 +1169,25 @@ static struct dentry *fuse_mount(struct + return mount_nodev(fs_type, flags, raw_data, fuse_fill_super); + } + +-static void fuse_kill_sb_anon(struct super_block *sb) ++static void fuse_sb_destroy(struct super_block *sb) + { + struct fuse_conn *fc = get_fuse_conn_super(sb); + + if (fc) { ++ fuse_send_destroy(fc); ++ ++ fuse_abort_conn(fc); ++ fuse_wait_aborted(fc); ++ + down_write(&fc->killsb); + fc->sb = NULL; + up_write(&fc->killsb); + } ++} + ++static void fuse_kill_sb_anon(struct super_block *sb) ++{ ++ fuse_sb_destroy(sb); + kill_anon_super(sb); + } + +@@ -1206,14 +1210,7 @@ static struct dentry *fuse_mount_blk(str + + static void fuse_kill_sb_blk(struct super_block *sb) + { +- struct fuse_conn *fc = get_fuse_conn_super(sb); +- +- if (fc) { +- down_write(&fc->killsb); +- fc->sb = NULL; +- up_write(&fc->killsb); +- } +- ++ fuse_sb_destroy(sb); + kill_block_super(sb); + } + diff --git a/queue-4.4/fuse-fix-unlocked-access-to-processing-queue.patch b/queue-4.4/fuse-fix-unlocked-access-to-processing-queue.patch new file mode 100644 index 00000000000..6c0b0d6674c --- /dev/null +++ b/queue-4.4/fuse-fix-unlocked-access-to-processing-queue.patch @@ -0,0 +1,41 @@ +From 45ff350bbd9d0f0977ff270a0d427c71520c0c37 Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Thu, 26 Jul 2018 16:13:11 +0200 +Subject: fuse: fix unlocked access to processing queue + +From: Miklos Szeredi + +commit 45ff350bbd9d0f0977ff270a0d427c71520c0c37 upstream. + +fuse_dev_release() assumes that it's the only one referencing the +fpq->processing list, but that's not true, since fuse_abort_conn() can be +doing the same without any serialization between the two. + +Fixes: c3696046beb3 ("fuse: separate pqueue for clones") +Cc: # v4.2 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dev.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -2199,9 +2199,15 @@ int fuse_dev_release(struct inode *inode + if (fud) { + struct fuse_conn *fc = fud->fc; + struct fuse_pqueue *fpq = &fud->pq; ++ LIST_HEAD(to_end); + ++ spin_lock(&fpq->lock); + WARN_ON(!list_empty(&fpq->io)); +- end_requests(fc, &fpq->processing); ++ list_splice_init(&fpq->processing, &to_end); ++ spin_unlock(&fpq->lock); ++ ++ end_requests(fc, &to_end); ++ + /* Are we the last open device? */ + if (atomic_dec_and_test(&fc->dev_count)) { + WARN_ON(fc->iq.fasync != NULL); diff --git a/queue-4.4/fuse-umount-should-wait-for-all-requests.patch b/queue-4.4/fuse-umount-should-wait-for-all-requests.patch new file mode 100644 index 00000000000..f4545bb80a0 --- /dev/null +++ b/queue-4.4/fuse-umount-should-wait-for-all-requests.patch @@ -0,0 +1,116 @@ +From b8f95e5d13f5f0191dcb4b9113113d241636e7cb Mon Sep 17 00:00:00 2001 +From: Miklos Szeredi +Date: Thu, 26 Jul 2018 16:13:11 +0200 +Subject: fuse: umount should wait for all requests + +From: Miklos Szeredi + +commit b8f95e5d13f5f0191dcb4b9113113d241636e7cb upstream. + +fuse_abort_conn() does not guarantee that all async requests have actually +finished aborting (i.e. their ->end() function is called). This could +actually result in still used inodes after umount. + +Add a helper to wait until all requests are fully done. This is done by +looking at the "num_waiting" counter. When this counter drops to zero, we +can be sure that no more requests are outstanding. + +Fixes: 0d8e84b0432b ("fuse: simplify request abort") +Cc: # v4.2 +Signed-off-by: Miklos Szeredi +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dev.c | 23 +++++++++++++++++++---- + fs/fuse/fuse_i.h | 1 + + fs/fuse/inode.c | 2 ++ + 3 files changed, 22 insertions(+), 4 deletions(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -143,6 +143,16 @@ static bool fuse_block_alloc(struct fuse + return !fc->initialized || (for_background && fc->blocked); + } + ++static void fuse_drop_waiting(struct fuse_conn *fc) ++{ ++ if (fc->connected) { ++ atomic_dec(&fc->num_waiting); ++ } else if (atomic_dec_and_test(&fc->num_waiting)) { ++ /* wake up aborters */ ++ wake_up_all(&fc->blocked_waitq); ++ } ++} ++ + static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages, + bool for_background) + { +@@ -189,7 +199,7 @@ static struct fuse_req *__fuse_get_req(s + return req; + + out: +- atomic_dec(&fc->num_waiting); ++ fuse_drop_waiting(fc); + return ERR_PTR(err); + } + +@@ -296,7 +306,7 @@ void fuse_put_request(struct fuse_conn * + + if (test_bit(FR_WAITING, &req->flags)) { + __clear_bit(FR_WAITING, &req->flags); +- atomic_dec(&fc->num_waiting); ++ fuse_drop_waiting(fc); + } + + if (req->stolen_file) +@@ -382,7 +392,7 @@ static void request_end(struct fuse_conn + struct fuse_iqueue *fiq = &fc->iq; + + if (test_and_set_bit(FR_FINISHED, &req->flags)) +- goto out_put_req; ++ goto put_request; + + spin_lock(&fiq->waitq.lock); + list_del_init(&req->intr_entry); +@@ -412,7 +422,7 @@ static void request_end(struct fuse_conn + wake_up(&req->waitq); + if (req->end) + req->end(fc, req); +-out_put_req: ++put_request: + fuse_put_request(fc, req); + } + +@@ -2192,6 +2202,11 @@ void fuse_abort_conn(struct fuse_conn *f + } + EXPORT_SYMBOL_GPL(fuse_abort_conn); + ++void fuse_wait_aborted(struct fuse_conn *fc) ++{ ++ wait_event(fc->blocked_waitq, atomic_read(&fc->num_waiting) == 0); ++} ++ + int fuse_dev_release(struct inode *inode, struct file *file) + { + struct fuse_dev *fud = fuse_get_dev(file); +--- a/fs/fuse/fuse_i.h ++++ b/fs/fuse/fuse_i.h +@@ -842,6 +842,7 @@ void fuse_request_send_background_locked + + /* Abort all requests */ + void fuse_abort_conn(struct fuse_conn *fc); ++void fuse_wait_aborted(struct fuse_conn *fc); + + /** + * Invalidate inode attributes +--- a/fs/fuse/inode.c ++++ b/fs/fuse/inode.c +@@ -382,6 +382,8 @@ static void fuse_put_super(struct super_ + fuse_send_destroy(fc); + + fuse_abort_conn(fc); ++ fuse_wait_aborted(fc); ++ + mutex_lock(&fuse_mutex); + list_del(&fc->entry); + fuse_ctl_remove_conn(fc); diff --git a/queue-4.4/series b/queue-4.4/series index 5410de38402..ad9a9c5e615 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -50,3 +50,13 @@ ext4-reset-error-code-in-ext4_find_entry-in-fallback.patch arm64-mm-check-for-upper-page_shift-bits-in-pfn_valid.patch kvm-arm-arm64-skip-updating-pte-entry-if-no-change.patch kvm-arm-arm64-skip-updating-pmd-entry-if-no-change.patch +x86-speculation-l1tf-fix-overflow-in-l1tf_pfn_limit-on-32bit.patch +x86-speculation-l1tf-fix-off-by-one-error-when-warning-that-system-has-too-much-ram.patch +x86-speculation-l1tf-suggest-what-to-do-on-systems-with-too-much-ram.patch +x86-process-re-export-start_thread.patch +fuse-don-t-access-pipe-buffers-without-pipe_lock.patch +fuse-fix-double-request_end.patch +fuse-fix-unlocked-access-to-processing-queue.patch +fuse-umount-should-wait-for-all-requests.patch +fuse-fix-oops-at-process_init_reply.patch +fuse-add-missed-unlock_page-to-fuse_readpages_fill.patch diff --git a/queue-4.4/x86-process-re-export-start_thread.patch b/queue-4.4/x86-process-re-export-start_thread.patch new file mode 100644 index 00000000000..a4b6db69cc7 --- /dev/null +++ b/queue-4.4/x86-process-re-export-start_thread.patch @@ -0,0 +1,42 @@ +From dc76803e57cc86589c4efcb5362918f9b0c0436f Mon Sep 17 00:00:00 2001 +From: Rian Hunter +Date: Sun, 19 Aug 2018 16:08:53 -0700 +Subject: x86/process: Re-export start_thread() + +From: Rian Hunter + +commit dc76803e57cc86589c4efcb5362918f9b0c0436f upstream. + +The consolidation of the start_thread() functions removed the export +unintentionally. This breaks binfmt handlers built as a module. + +Add it back. + +Fixes: e634d8fc792c ("x86-64: merge the standard and compat start_thread() functions") +Signed-off-by: Rian Hunter +Signed-off-by: Thomas Gleixner +Cc: "H. Peter Anvin" +Cc: Andy Lutomirski +Cc: Borislav Petkov +Cc: Vitaly Kuznetsov +Cc: Joerg Roedel +Cc: Dmitry Safonov +Cc: Josh Poimboeuf +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/20180819230854.7275-1-rian@alum.mit.edu +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/process_64.c | 1 + + 1 file changed, 1 insertion(+) + +--- a/arch/x86/kernel/process_64.c ++++ b/arch/x86/kernel/process_64.c +@@ -250,6 +250,7 @@ start_thread(struct pt_regs *regs, unsig + start_thread_common(regs, new_ip, new_sp, + __USER_CS, __USER_DS, 0); + } ++EXPORT_SYMBOL_GPL(start_thread); + + #ifdef CONFIG_COMPAT + void compat_start_thread(struct pt_regs *regs, u32 new_ip, u32 new_sp) diff --git a/queue-4.4/x86-speculation-l1tf-fix-off-by-one-error-when-warning-that-system-has-too-much-ram.patch b/queue-4.4/x86-speculation-l1tf-fix-off-by-one-error-when-warning-that-system-has-too-much-ram.patch new file mode 100644 index 00000000000..5008739a438 --- /dev/null +++ b/queue-4.4/x86-speculation-l1tf-fix-off-by-one-error-when-warning-that-system-has-too-much-ram.patch @@ -0,0 +1,82 @@ +From b0a182f875689647b014bc01d36b340217792852 Mon Sep 17 00:00:00 2001 +From: Vlastimil Babka +Date: Thu, 23 Aug 2018 15:44:18 +0200 +Subject: x86/speculation/l1tf: Fix off-by-one error when warning that system has too much RAM + +From: Vlastimil Babka + +commit b0a182f875689647b014bc01d36b340217792852 upstream. + +Two users have reported [1] that they have an "extremely unlikely" system +with more than MAX_PA/2 memory and L1TF mitigation is not effective. In +fact it's a CPU with 36bits phys limit (64GB) and 32GB memory, but due to +holes in the e820 map, the main region is almost 500MB over the 32GB limit: + +[ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000081effffff] usable + +Suggestions to use 'mem=32G' to enable the L1TF mitigation while losing the +500MB revealed, that there's an off-by-one error in the check in +l1tf_select_mitigation(). + +l1tf_pfn_limit() returns the last usable pfn (inclusive) and the range +check in the mitigation path does not take this into account. + +Instead of amending the range check, make l1tf_pfn_limit() return the first +PFN which is over the limit which is less error prone. Adjust the other +users accordingly. + +[1] https://bugzilla.suse.com/show_bug.cgi?id=1105536 + +Fixes: 17dbca119312 ("x86/speculation/l1tf: Add sysfs reporting for l1tf") +Reported-by: George Anchev +Reported-by: Christopher Snowhill +Signed-off-by: Vlastimil Babka +Signed-off-by: Thomas Gleixner +Cc: "H . Peter Anvin" +Cc: Linus Torvalds +Cc: Andi Kleen +Cc: Dave Hansen +Cc: Michal Hocko +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/20180823134418.17008-1-vbabka@suse.cz +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/include/asm/processor.h | 2 +- + arch/x86/mm/init.c | 2 +- + arch/x86/mm/mmap.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -174,7 +174,7 @@ extern void cpu_detect(struct cpuinfo_x8 + + static inline unsigned long long l1tf_pfn_limit(void) + { +- return BIT_ULL(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT) - 1; ++ return BIT_ULL(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT); + } + + extern void early_cpu_init(void); +--- a/arch/x86/mm/init.c ++++ b/arch/x86/mm/init.c +@@ -779,7 +779,7 @@ unsigned long max_swapfile_size(void) + + if (boot_cpu_has_bug(X86_BUG_L1TF)) { + /* Limit the swap file size to MAX_PA/2 for L1TF workaround */ +- unsigned long long l1tf_limit = l1tf_pfn_limit() + 1; ++ unsigned long long l1tf_limit = l1tf_pfn_limit(); + /* + * We encode swap offsets also with 3 bits below those for pfn + * which makes the usable limit higher. +--- a/arch/x86/mm/mmap.c ++++ b/arch/x86/mm/mmap.c +@@ -138,7 +138,7 @@ bool pfn_modify_allowed(unsigned long pf + /* If it's real memory always allow */ + if (pfn_valid(pfn)) + return true; +- if (pfn > l1tf_pfn_limit() && !capable(CAP_SYS_ADMIN)) ++ if (pfn >= l1tf_pfn_limit() && !capable(CAP_SYS_ADMIN)) + return false; + return true; + } diff --git a/queue-4.4/x86-speculation-l1tf-fix-overflow-in-l1tf_pfn_limit-on-32bit.patch b/queue-4.4/x86-speculation-l1tf-fix-overflow-in-l1tf_pfn_limit-on-32bit.patch new file mode 100644 index 00000000000..18fb11dd183 --- /dev/null +++ b/queue-4.4/x86-speculation-l1tf-fix-overflow-in-l1tf_pfn_limit-on-32bit.patch @@ -0,0 +1,75 @@ +From 9df9516940a61d29aedf4d91b483ca6597e7d480 Mon Sep 17 00:00:00 2001 +From: Vlastimil Babka +Date: Mon, 20 Aug 2018 11:58:35 +0200 +Subject: x86/speculation/l1tf: Fix overflow in l1tf_pfn_limit() on 32bit + +From: Vlastimil Babka + +commit 9df9516940a61d29aedf4d91b483ca6597e7d480 upstream. + +On 32bit PAE kernels on 64bit hardware with enough physical bits, +l1tf_pfn_limit() will overflow unsigned long. This in turn affects +max_swapfile_size() and can lead to swapon returning -EINVAL. This has been +observed in a 32bit guest with 42 bits physical address size, where +max_swapfile_size() overflows exactly to 1 << 32, thus zero, and produces +the following warning to dmesg: + +[ 6.396845] Truncating oversized swap area, only using 0k out of 2047996k + +Fix this by using unsigned long long instead. + +Fixes: 17dbca119312 ("x86/speculation/l1tf: Add sysfs reporting for l1tf") +Fixes: 377eeaa8e11f ("x86/speculation/l1tf: Limit swap file size to MAX_PA/2") +Reported-by: Dominique Leuenberger +Reported-by: Adrian Schroeter +Signed-off-by: Vlastimil Babka +Signed-off-by: Thomas Gleixner +Acked-by: Andi Kleen +Acked-by: Michal Hocko +Cc: "H . Peter Anvin" +Cc: Linus Torvalds +Cc: Dave Hansen +Cc: Michal Hocko +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/20180820095835.5298-1-vbabka@suse.cz +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/include/asm/processor.h | 4 ++-- + arch/x86/mm/init.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -172,9 +172,9 @@ extern const struct seq_operations cpuin + + extern void cpu_detect(struct cpuinfo_x86 *c); + +-static inline unsigned long l1tf_pfn_limit(void) ++static inline unsigned long long l1tf_pfn_limit(void) + { +- return BIT(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT) - 1; ++ return BIT_ULL(boot_cpu_data.x86_phys_bits - 1 - PAGE_SHIFT) - 1; + } + + extern void early_cpu_init(void); +--- a/arch/x86/mm/init.c ++++ b/arch/x86/mm/init.c +@@ -779,7 +779,7 @@ unsigned long max_swapfile_size(void) + + if (boot_cpu_has_bug(X86_BUG_L1TF)) { + /* Limit the swap file size to MAX_PA/2 for L1TF workaround */ +- unsigned long l1tf_limit = l1tf_pfn_limit() + 1; ++ unsigned long long l1tf_limit = l1tf_pfn_limit() + 1; + /* + * We encode swap offsets also with 3 bits below those for pfn + * which makes the usable limit higher. +@@ -787,7 +787,7 @@ unsigned long max_swapfile_size(void) + #if CONFIG_PGTABLE_LEVELS > 2 + l1tf_limit <<= PAGE_SHIFT - SWP_OFFSET_FIRST_BIT; + #endif +- pages = min_t(unsigned long, l1tf_limit, pages); ++ pages = min_t(unsigned long long, l1tf_limit, pages); + } + return pages; + } diff --git a/queue-4.4/x86-speculation-l1tf-suggest-what-to-do-on-systems-with-too-much-ram.patch b/queue-4.4/x86-speculation-l1tf-suggest-what-to-do-on-systems-with-too-much-ram.patch new file mode 100644 index 00000000000..2796e81072d --- /dev/null +++ b/queue-4.4/x86-speculation-l1tf-suggest-what-to-do-on-systems-with-too-much-ram.patch @@ -0,0 +1,46 @@ +From 6a012288d6906fee1dbc244050ade1dafe4a9c8d Mon Sep 17 00:00:00 2001 +From: Vlastimil Babka +Date: Thu, 23 Aug 2018 16:21:29 +0200 +Subject: x86/speculation/l1tf: Suggest what to do on systems with too much RAM + +From: Vlastimil Babka + +commit 6a012288d6906fee1dbc244050ade1dafe4a9c8d upstream. + +Two users have reported [1] that they have an "extremely unlikely" system +with more than MAX_PA/2 memory and L1TF mitigation is not effective. + +Make the warning more helpful by suggesting the proper mem=X kernel boot +parameter to make it effective and a link to the L1TF document to help +decide if the mitigation is worth the unusable RAM. + +[1] https://bugzilla.suse.com/show_bug.cgi?id=1105536 + +Suggested-by: Michal Hocko +Signed-off-by: Vlastimil Babka +Acked-by: Michal Hocko +Cc: "H . Peter Anvin" +Cc: Linus Torvalds +Cc: Andi Kleen +Cc: Dave Hansen +Cc: stable@vger.kernel.org +Link: https://lkml.kernel.org/r/966571f0-9d7f-43dc-92c6-a10eec7a1254@suse.cz +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/kernel/cpu/bugs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -654,6 +654,10 @@ static void __init l1tf_select_mitigatio + half_pa = (u64)l1tf_pfn_limit() << PAGE_SHIFT; + if (e820_any_mapped(half_pa, ULLONG_MAX - half_pa, E820_RAM)) { + pr_warn("System has more than MAX_PA/2 memory. L1TF mitigation not effective.\n"); ++ pr_info("You may make it effective by booting the kernel with mem=%llu parameter.\n", ++ half_pa); ++ pr_info("However, doing so will make a part of your RAM unusable.\n"); ++ pr_info("Reading https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html might help you decide.\n"); + return; + } +