From: Greg Kroah-Hartman Date: Thu, 2 May 2019 12:13:30 +0000 (+0200) Subject: 5.0-stable patches X-Git-Tag: v4.9.173~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=43381ca3fa3f26f5ca6e04d3337eab802bd337b5;p=thirdparty%2Fkernel%2Fstable-queue.git 5.0-stable patches added patches: drm-i915-do-not-enable-fec-without-dsc.patch fs-prevent-page-refcount-overflow-in-pipe_buf_get.patch mm-add-try_get_page-helper-function.patch mm-make-page-ref-count-overflow-check-tighter-and-more-explicit.patch mm-prevent-get_user_pages-from-overflowing-page-refcount.patch revert-acpica-clear-status-of-gpes-before-enabling-them.patch --- diff --git a/queue-5.0/drm-i915-do-not-enable-fec-without-dsc.patch b/queue-5.0/drm-i915-do-not-enable-fec-without-dsc.patch new file mode 100644 index 00000000000..3bc8391f22f --- /dev/null +++ b/queue-5.0/drm-i915-do-not-enable-fec-without-dsc.patch @@ -0,0 +1,56 @@ +From 5aae7832d1b4ec614996ea0f4fafc4d9855ec0b0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= +Date: Tue, 26 Mar 2019 16:49:02 +0200 +Subject: drm/i915: Do not enable FEC without DSC +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Ville Syrjälä + +commit 5aae7832d1b4ec614996ea0f4fafc4d9855ec0b0 upstream. + +Currently we enable FEC even when DSC is no used. While that is +theoretically valid supposedly there isn't much of a benefit from +this. But more importantly we do not account for the FEC link +bandwidth overhead (2.4%) in the non-DSC link bandwidth computations. +So the code may think we have enough bandwidth when we in fact +do not. + +Cc: stable@vger.kernel.org +Cc: Anusha Srivatsa +Cc: Manasi Navare +Fixes: 240999cf339f ("i915/dp/fec: Add fec_enable to the crtc state.") +Signed-off-by: Ville Syrjälä +Link: https://patchwork.freedesktop.org/patch/msgid/20190326144903.6617-1-ville.syrjala@linux.intel.com +Reviewed-by: Manasi Navare +(cherry picked from commit 6fd3134ae3551d4802a04669c0f39f2f5c56f77d) +Signed-off-by: Rodrigo Vivi +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/gpu/drm/i915/intel_dp.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/gpu/drm/i915/intel_dp.c ++++ b/drivers/gpu/drm/i915/intel_dp.c +@@ -1871,6 +1871,9 @@ static bool intel_dp_dsc_compute_config( + u8 dsc_max_bpc; + int pipe_bpp; + ++ pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && ++ intel_dp_supports_fec(intel_dp, pipe_config); ++ + if (!intel_dp_supports_dsc(intel_dp, pipe_config)) + return false; + +@@ -2097,9 +2100,6 @@ intel_dp_compute_config(struct intel_enc + if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) + return false; + +- pipe_config->fec_enable = !intel_dp_is_edp(intel_dp) && +- intel_dp_supports_fec(intel_dp, pipe_config); +- + if (!intel_dp_compute_link_config(encoder, pipe_config, conn_state)) + return false; + diff --git a/queue-5.0/fs-prevent-page-refcount-overflow-in-pipe_buf_get.patch b/queue-5.0/fs-prevent-page-refcount-overflow-in-pipe_buf_get.patch new file mode 100644 index 00000000000..b8869b70c86 --- /dev/null +++ b/queue-5.0/fs-prevent-page-refcount-overflow-in-pipe_buf_get.patch @@ -0,0 +1,158 @@ +From 15fab63e1e57be9fdb5eec1bbc5916e9825e9acb Mon Sep 17 00:00:00 2001 +From: Matthew Wilcox +Date: Fri, 5 Apr 2019 14:02:10 -0700 +Subject: fs: prevent page refcount overflow in pipe_buf_get + +From: Matthew Wilcox + +commit 15fab63e1e57be9fdb5eec1bbc5916e9825e9acb upstream. + +Change pipe_buf_get() to return a bool indicating whether it succeeded +in raising the refcount of the page (if the thing in the pipe is a page). +This removes another mechanism for overflowing the page refcount. All +callers converted to handle a failure. + +Reported-by: Jann Horn +Signed-off-by: Matthew Wilcox +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/fuse/dev.c | 12 ++++++------ + fs/pipe.c | 4 ++-- + fs/splice.c | 12 ++++++++++-- + include/linux/pipe_fs_i.h | 10 ++++++---- + kernel/trace/trace.c | 4 ++++ + 5 files changed, 28 insertions(+), 14 deletions(-) + +--- a/fs/fuse/dev.c ++++ b/fs/fuse/dev.c +@@ -2034,10 +2034,8 @@ static ssize_t fuse_dev_splice_write(str + rem += pipe->bufs[(pipe->curbuf + idx) & (pipe->buffers - 1)].len; + + ret = -EINVAL; +- if (rem < len) { +- pipe_unlock(pipe); +- goto out; +- } ++ if (rem < len) ++ goto out_free; + + rem = len; + while (rem) { +@@ -2055,7 +2053,9 @@ static ssize_t fuse_dev_splice_write(str + pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1); + pipe->nrbufs--; + } else { +- pipe_buf_get(pipe, ibuf); ++ if (!pipe_buf_get(pipe, ibuf)) ++ goto out_free; ++ + *obuf = *ibuf; + obuf->flags &= ~PIPE_BUF_FLAG_GIFT; + obuf->len = rem; +@@ -2078,11 +2078,11 @@ static ssize_t fuse_dev_splice_write(str + ret = fuse_dev_do_write(fud, &cs, len); + + pipe_lock(pipe); ++out_free: + for (idx = 0; idx < nbuf; idx++) + pipe_buf_release(pipe, &bufs[idx]); + pipe_unlock(pipe); + +-out: + kvfree(bufs); + return ret; + } +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -189,9 +189,9 @@ EXPORT_SYMBOL(generic_pipe_buf_steal); + * in the tee() system call, when we duplicate the buffers in one + * pipe into another. + */ +-void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) ++bool generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) + { +- get_page(buf->page); ++ return try_get_page(buf->page); + } + EXPORT_SYMBOL(generic_pipe_buf_get); + +--- a/fs/splice.c ++++ b/fs/splice.c +@@ -1588,7 +1588,11 @@ retry: + * Get a reference to this pipe buffer, + * so we can copy the contents over. + */ +- pipe_buf_get(ipipe, ibuf); ++ if (!pipe_buf_get(ipipe, ibuf)) { ++ if (ret == 0) ++ ret = -EFAULT; ++ break; ++ } + *obuf = *ibuf; + + /* +@@ -1662,7 +1666,11 @@ static int link_pipe(struct pipe_inode_i + * Get a reference to this pipe buffer, + * so we can copy the contents over. + */ +- pipe_buf_get(ipipe, ibuf); ++ if (!pipe_buf_get(ipipe, ibuf)) { ++ if (ret == 0) ++ ret = -EFAULT; ++ break; ++ } + + obuf = opipe->bufs + nbuf; + *obuf = *ibuf; +--- a/include/linux/pipe_fs_i.h ++++ b/include/linux/pipe_fs_i.h +@@ -108,18 +108,20 @@ struct pipe_buf_operations { + /* + * Get a reference to the pipe buffer. + */ +- void (*get)(struct pipe_inode_info *, struct pipe_buffer *); ++ bool (*get)(struct pipe_inode_info *, struct pipe_buffer *); + }; + + /** + * pipe_buf_get - get a reference to a pipe_buffer + * @pipe: the pipe that the buffer belongs to + * @buf: the buffer to get a reference to ++ * ++ * Return: %true if the reference was successfully obtained. + */ +-static inline void pipe_buf_get(struct pipe_inode_info *pipe, ++static inline __must_check bool pipe_buf_get(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) + { +- buf->ops->get(pipe, buf); ++ return buf->ops->get(pipe, buf); + } + + /** +@@ -178,7 +180,7 @@ struct pipe_inode_info *alloc_pipe_info( + void free_pipe_info(struct pipe_inode_info *); + + /* Generic pipe buffer ops functions */ +-void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); ++bool generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); + int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *); + int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *); + int generic_pipe_buf_nosteal(struct pipe_inode_info *, struct pipe_buffer *); +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -6848,7 +6848,11 @@ static void buffer_pipe_buf_get(struct p + { + struct buffer_ref *ref = (struct buffer_ref *)buf->private; + ++ if (refcount_read(&ref->refcount) > INT_MAX/2) ++ return false; ++ + refcount_inc(&ref->refcount); ++ return true; + } + + /* Pipe buffer operations for a buffer. */ diff --git a/queue-5.0/mm-add-try_get_page-helper-function.patch b/queue-5.0/mm-add-try_get_page-helper-function.patch new file mode 100644 index 00000000000..c7803ca04ab --- /dev/null +++ b/queue-5.0/mm-add-try_get_page-helper-function.patch @@ -0,0 +1,56 @@ +From 88b1a17dfc3ed7728316478fae0f5ad508f50397 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Thu, 11 Apr 2019 10:14:59 -0700 +Subject: mm: add 'try_get_page()' helper function + +From: Linus Torvalds + +commit 88b1a17dfc3ed7728316478fae0f5ad508f50397 upstream. + +This is the same as the traditional 'get_page()' function, but instead +of unconditionally incrementing the reference count of the page, it only +does so if the count was "safe". It returns whether the reference count +was incremented (and is marked __must_check, since the caller obviously +has to be aware of it). + +Also like 'get_page()', you can't use this function unless you already +had a reference to the page. The intent is that you can use this +exactly like get_page(), but in situations where you want to limit the +maximum reference count. + +The code currently does an unconditional WARN_ON_ONCE() if we ever hit +the reference count issues (either zero or negative), as a notification +that the conditional non-increment actually happened. + +NOTE! The count access for the "safety" check is inherently racy, but +that doesn't matter since the buffer we use is basically half the range +of the reference count (ie we look at the sign of the count). + +Acked-by: Matthew Wilcox +Cc: Jann Horn +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/mm.h | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -980,6 +980,15 @@ static inline void get_page(struct page + page_ref_inc(page); + } + ++static inline __must_check bool try_get_page(struct page *page) ++{ ++ page = compound_head(page); ++ if (WARN_ON_ONCE(page_ref_count(page) <= 0)) ++ return false; ++ page_ref_inc(page); ++ return true; ++} ++ + static inline void put_page(struct page *page) + { + page = compound_head(page); diff --git a/queue-5.0/mm-make-page-ref-count-overflow-check-tighter-and-more-explicit.patch b/queue-5.0/mm-make-page-ref-count-overflow-check-tighter-and-more-explicit.patch new file mode 100644 index 00000000000..aa4c1fa3bb9 --- /dev/null +++ b/queue-5.0/mm-make-page-ref-count-overflow-check-tighter-and-more-explicit.patch @@ -0,0 +1,52 @@ +From f958d7b528b1b40c44cfda5eabe2d82760d868c3 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Thu, 11 Apr 2019 10:06:20 -0700 +Subject: mm: make page ref count overflow check tighter and more explicit + +From: Linus Torvalds + +commit f958d7b528b1b40c44cfda5eabe2d82760d868c3 upstream. + +We have a VM_BUG_ON() to check that the page reference count doesn't +underflow (or get close to overflow) by checking the sign of the count. + +That's all fine, but we actually want to allow people to use a "get page +ref unless it's already very high" helper function, and we want that one +to use the sign of the page ref (without triggering this VM_BUG_ON). + +Change the VM_BUG_ON to only check for small underflows (or _very_ close +to overflowing), and ignore overflows which have strayed into negative +territory. + +Acked-by: Matthew Wilcox +Cc: Jann Horn +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/mm.h | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -965,6 +965,10 @@ static inline bool is_pci_p2pdma_page(co + } + #endif /* CONFIG_DEV_PAGEMAP_OPS */ + ++/* 127: arbitrary random number, small enough to assemble well */ ++#define page_ref_zero_or_close_to_overflow(page) \ ++ ((unsigned int) page_ref_count(page) + 127u <= 127u) ++ + static inline void get_page(struct page *page) + { + page = compound_head(page); +@@ -972,7 +976,7 @@ static inline void get_page(struct page + * Getting a normal page or the head of a compound page + * requires to already have an elevated page->_refcount. + */ +- VM_BUG_ON_PAGE(page_ref_count(page) <= 0, page); ++ VM_BUG_ON_PAGE(page_ref_zero_or_close_to_overflow(page), page); + page_ref_inc(page); + } + diff --git a/queue-5.0/mm-prevent-get_user_pages-from-overflowing-page-refcount.patch b/queue-5.0/mm-prevent-get_user_pages-from-overflowing-page-refcount.patch new file mode 100644 index 00000000000..aa1e2858955 --- /dev/null +++ b/queue-5.0/mm-prevent-get_user_pages-from-overflowing-page-refcount.patch @@ -0,0 +1,156 @@ +From 8fde12ca79aff9b5ba951fce1a2641901b8d8e64 Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +Date: Thu, 11 Apr 2019 10:49:19 -0700 +Subject: mm: prevent get_user_pages() from overflowing page refcount + +From: Linus Torvalds + +commit 8fde12ca79aff9b5ba951fce1a2641901b8d8e64 upstream. + +If the page refcount wraps around past zero, it will be freed while +there are still four billion references to it. One of the possible +avenues for an attacker to try to make this happen is by doing direct IO +on a page multiple times. This patch makes get_user_pages() refuse to +take a new page reference if there are already more than two billion +references to the page. + +Reported-by: Jann Horn +Acked-by: Matthew Wilcox +Cc: stable@kernel.org +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + mm/gup.c | 48 ++++++++++++++++++++++++++++++++++++------------ + mm/hugetlb.c | 13 +++++++++++++ + 2 files changed, 49 insertions(+), 12 deletions(-) + +--- a/mm/gup.c ++++ b/mm/gup.c +@@ -157,8 +157,12 @@ retry: + goto retry; + } + +- if (flags & FOLL_GET) +- get_page(page); ++ if (flags & FOLL_GET) { ++ if (unlikely(!try_get_page(page))) { ++ page = ERR_PTR(-ENOMEM); ++ goto out; ++ } ++ } + if (flags & FOLL_TOUCH) { + if ((flags & FOLL_WRITE) && + !pte_dirty(pte) && !PageDirty(page)) +@@ -295,7 +299,10 @@ retry_locked: + if (pmd_trans_unstable(pmd)) + ret = -EBUSY; + } else { +- get_page(page); ++ if (unlikely(!try_get_page(page))) { ++ spin_unlock(ptl); ++ return ERR_PTR(-ENOMEM); ++ } + spin_unlock(ptl); + lock_page(page); + ret = split_huge_page(page); +@@ -497,7 +504,10 @@ static int get_gate_page(struct mm_struc + if (is_device_public_page(*page)) + goto unmap; + } +- get_page(*page); ++ if (unlikely(!try_get_page(*page))) { ++ ret = -ENOMEM; ++ goto unmap; ++ } + out: + ret = 0; + unmap: +@@ -1393,6 +1403,20 @@ static void undo_dev_pagemap(int *nr, in + } + } + ++/* ++ * Return the compund head page with ref appropriately incremented, ++ * or NULL if that failed. ++ */ ++static inline struct page *try_get_compound_head(struct page *page, int refs) ++{ ++ struct page *head = compound_head(page); ++ if (WARN_ON_ONCE(page_ref_count(head) < 0)) ++ return NULL; ++ if (unlikely(!page_cache_add_speculative(head, refs))) ++ return NULL; ++ return head; ++} ++ + #ifdef CONFIG_ARCH_HAS_PTE_SPECIAL + static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, + int write, struct page **pages, int *nr) +@@ -1427,9 +1451,9 @@ static int gup_pte_range(pmd_t pmd, unsi + + VM_BUG_ON(!pfn_valid(pte_pfn(pte))); + page = pte_page(pte); +- head = compound_head(page); + +- if (!page_cache_get_speculative(head)) ++ head = try_get_compound_head(page, 1); ++ if (!head) + goto pte_unmap; + + if (unlikely(pte_val(pte) != pte_val(*ptep))) { +@@ -1568,8 +1592,8 @@ static int gup_huge_pmd(pmd_t orig, pmd_ + refs++; + } while (addr += PAGE_SIZE, addr != end); + +- head = compound_head(pmd_page(orig)); +- if (!page_cache_add_speculative(head, refs)) { ++ head = try_get_compound_head(pmd_page(orig), refs); ++ if (!head) { + *nr -= refs; + return 0; + } +@@ -1606,8 +1630,8 @@ static int gup_huge_pud(pud_t orig, pud_ + refs++; + } while (addr += PAGE_SIZE, addr != end); + +- head = compound_head(pud_page(orig)); +- if (!page_cache_add_speculative(head, refs)) { ++ head = try_get_compound_head(pud_page(orig), refs); ++ if (!head) { + *nr -= refs; + return 0; + } +@@ -1643,8 +1667,8 @@ static int gup_huge_pgd(pgd_t orig, pgd_ + refs++; + } while (addr += PAGE_SIZE, addr != end); + +- head = compound_head(pgd_page(orig)); +- if (!page_cache_add_speculative(head, refs)) { ++ head = try_get_compound_head(pgd_page(orig), refs); ++ if (!head) { + *nr -= refs; + return 0; + } +--- a/mm/hugetlb.c ++++ b/mm/hugetlb.c +@@ -4298,6 +4298,19 @@ long follow_hugetlb_page(struct mm_struc + + pfn_offset = (vaddr & ~huge_page_mask(h)) >> PAGE_SHIFT; + page = pte_page(huge_ptep_get(pte)); ++ ++ /* ++ * Instead of doing 'try_get_page()' below in the same_page ++ * loop, just check the count once here. ++ */ ++ if (unlikely(page_count(page) <= 0)) { ++ if (pages) { ++ spin_unlock(ptl); ++ remainder = 0; ++ err = -ENOMEM; ++ break; ++ } ++ } + same_page: + if (pages) { + pages[i] = mem_map_offset(page, pfn_offset); diff --git a/queue-5.0/revert-acpica-clear-status-of-gpes-before-enabling-them.patch b/queue-5.0/revert-acpica-clear-status-of-gpes-before-enabling-them.patch new file mode 100644 index 00000000000..4f31fd4ec13 --- /dev/null +++ b/queue-5.0/revert-acpica-clear-status-of-gpes-before-enabling-them.patch @@ -0,0 +1,48 @@ +From 2c2a2fb1e2a9256714338875bede6b7cbd4b9542 Mon Sep 17 00:00:00 2001 +From: "Rafael J. Wysocki" +Date: Tue, 30 Apr 2019 11:18:21 +0200 +Subject: Revert "ACPICA: Clear status of GPEs before enabling them" + +From: Rafael J. Wysocki + +commit 2c2a2fb1e2a9256714338875bede6b7cbd4b9542 upstream. + +Revert commit c8b1917c8987 ("ACPICA: Clear status of GPEs before +enabling them") that causes problems with Thunderbolt controllers +to occur if a dock device is connected at init time (the xhci_hcd +and thunderbolt modules crash which prevents peripherals connected +through them from working). + +Commit c8b1917c8987 effectively causes commit ecc1165b8b74 ("ACPICA: +Dispatch active GPEs at init time") to get undone, so the problem +addressed by commit ecc1165b8b74 appears again as a result of it. + +Fixes: c8b1917c8987 ("ACPICA: Clear status of GPEs before enabling them") +Link: https://lore.kernel.org/lkml/s5hy33siofw.wl-tiwai@suse.de/T/#u +Link: https://bugzilla.opensuse.org/show_bug.cgi?id=1132943 +Reported-by: Michael Hirmke +Reported-by: Takashi Iwai +Cc: 4.17+ # 4.17+ +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/acpica/evgpe.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +--- a/drivers/acpi/acpica/evgpe.c ++++ b/drivers/acpi/acpica/evgpe.c +@@ -81,12 +81,8 @@ acpi_status acpi_ev_enable_gpe(struct ac + + ACPI_FUNCTION_TRACE(ev_enable_gpe); + +- /* Clear the GPE status */ +- status = acpi_hw_clear_gpe(gpe_event_info); +- if (ACPI_FAILURE(status)) +- return_ACPI_STATUS(status); +- + /* Enable the requested GPE */ ++ + status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE); + return_ACPI_STATUS(status); + } diff --git a/queue-5.0/series b/queue-5.0/series index 8495c3ed8e5..5a197a1d4c7 100644 --- a/queue-5.0/series +++ b/queue-5.0/series @@ -1 +1,7 @@ selinux-use-kernel-linux-socket.h-for-genheaders-and-mdp.patch +revert-acpica-clear-status-of-gpes-before-enabling-them.patch +drm-i915-do-not-enable-fec-without-dsc.patch +mm-make-page-ref-count-overflow-check-tighter-and-more-explicit.patch +mm-add-try_get_page-helper-function.patch +mm-prevent-get_user_pages-from-overflowing-page-refcount.patch +fs-prevent-page-refcount-overflow-in-pipe_buf_get.patch