From 97783e169a7096848e0d4e983d1f9e8292c637ee Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 18 Dec 2023 08:23:27 +0100 Subject: [PATCH] 5.4-stable patches added patches: arm64-mm-always-make-sw-dirty-ptes-hw-dirty-in-pte_modify.patch team-fix-use-after-free-when-an-option-instance-allocation-fails.patch --- ...sw-dirty-ptes-hw-dirty-in-pte_modify.patch | 76 +++++++++++++++++++ queue-5.4/series | 2 + ...-an-option-instance-allocation-fails.patch | 51 +++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 queue-5.4/arm64-mm-always-make-sw-dirty-ptes-hw-dirty-in-pte_modify.patch create mode 100644 queue-5.4/team-fix-use-after-free-when-an-option-instance-allocation-fails.patch diff --git a/queue-5.4/arm64-mm-always-make-sw-dirty-ptes-hw-dirty-in-pte_modify.patch b/queue-5.4/arm64-mm-always-make-sw-dirty-ptes-hw-dirty-in-pte_modify.patch new file mode 100644 index 00000000000..563d2c1cb04 --- /dev/null +++ b/queue-5.4/arm64-mm-always-make-sw-dirty-ptes-hw-dirty-in-pte_modify.patch @@ -0,0 +1,76 @@ +From 3c0696076aad60a2f04c019761921954579e1b0e Mon Sep 17 00:00:00 2001 +From: James Houghton +Date: Mon, 4 Dec 2023 17:26:46 +0000 +Subject: arm64: mm: Always make sw-dirty PTEs hw-dirty in pte_modify + +From: James Houghton + +commit 3c0696076aad60a2f04c019761921954579e1b0e upstream. + +It is currently possible for a userspace application to enter an +infinite page fault loop when using HugeTLB pages implemented with +contiguous PTEs when HAFDBS is not available. This happens because: + +1. The kernel may sometimes write PTEs that are sw-dirty but hw-clean + (PTE_DIRTY | PTE_RDONLY | PTE_WRITE). + +2. If, during a write, the CPU uses a sw-dirty, hw-clean PTE in handling + the memory access on a system without HAFDBS, we will get a page + fault. + +3. HugeTLB will check if it needs to update the dirty bits on the PTE. + For contiguous PTEs, it will check to see if the pgprot bits need + updating. In this case, HugeTLB wants to write a sequence of + sw-dirty, hw-dirty PTEs, but it finds that all the PTEs it is about + to overwrite are all pte_dirty() (pte_sw_dirty() => pte_dirty()), + so it thinks no update is necessary. + +We can get the kernel to write a sw-dirty, hw-clean PTE with the +following steps (showing the relevant VMA flags and pgprot bits): + +i. Create a valid, writable contiguous PTE. + VMA vmflags: VM_SHARED | VM_READ | VM_WRITE + VMA pgprot bits: PTE_RDONLY | PTE_WRITE + PTE pgprot bits: PTE_DIRTY | PTE_WRITE + +ii. mprotect the VMA to PROT_NONE. + VMA vmflags: VM_SHARED + VMA pgprot bits: PTE_RDONLY + PTE pgprot bits: PTE_DIRTY | PTE_RDONLY + +iii. mprotect the VMA back to PROT_READ | PROT_WRITE. + VMA vmflags: VM_SHARED | VM_READ | VM_WRITE + VMA pgprot bits: PTE_RDONLY | PTE_WRITE + PTE pgprot bits: PTE_DIRTY | PTE_WRITE | PTE_RDONLY + +Make it impossible to create a writeable sw-dirty, hw-clean PTE with +pte_modify(). Such a PTE should be impossible to create, and there may +be places that assume that pte_dirty() implies pte_hw_dirty(). + +Signed-off-by: James Houghton +Fixes: 031e6e6b4e12 ("arm64: hugetlb: Avoid unnecessary clearing in huge_ptep_set_access_flags") +Cc: +Acked-by: Will Deacon +Reviewed-by: Ryan Roberts +Link: https://lore.kernel.org/r/20231204172646.2541916-3-jthoughton@google.com +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman +--- + arch/arm64/include/asm/pgtable.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/arch/arm64/include/asm/pgtable.h ++++ b/arch/arm64/include/asm/pgtable.h +@@ -679,6 +679,12 @@ static inline pte_t pte_modify(pte_t pte + if (pte_hw_dirty(pte)) + pte = pte_mkdirty(pte); + pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); ++ /* ++ * If we end up clearing hw dirtiness for a sw-dirty PTE, set hardware ++ * dirtiness again. ++ */ ++ if (pte_sw_dirty(pte)) ++ pte = pte_mkdirty(pte); + return pte; + } + diff --git a/queue-5.4/series b/queue-5.4/series index bef5197657b..37f460ecba3 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -32,3 +32,5 @@ hid-hid-asus-add-const-to-read-only-outgoing-usb-buf.patch perf-fix-perf_event_validate_size-lockdep-splat.patch soundwire-stream-fix-null-pointer-dereference-for-multi_link.patch ext4-prevent-the-normalized-size-from-exceeding-ext_max_blocks.patch +arm64-mm-always-make-sw-dirty-ptes-hw-dirty-in-pte_modify.patch +team-fix-use-after-free-when-an-option-instance-allocation-fails.patch diff --git a/queue-5.4/team-fix-use-after-free-when-an-option-instance-allocation-fails.patch b/queue-5.4/team-fix-use-after-free-when-an-option-instance-allocation-fails.patch new file mode 100644 index 00000000000..940756188f9 --- /dev/null +++ b/queue-5.4/team-fix-use-after-free-when-an-option-instance-allocation-fails.patch @@ -0,0 +1,51 @@ +From c12296bbecc488623b7d1932080e394d08f3226b Mon Sep 17 00:00:00 2001 +From: Florent Revest +Date: Wed, 6 Dec 2023 13:37:18 +0100 +Subject: team: Fix use-after-free when an option instance allocation fails + +From: Florent Revest + +commit c12296bbecc488623b7d1932080e394d08f3226b upstream. + +In __team_options_register, team_options are allocated and appended to +the team's option_list. +If one option instance allocation fails, the "inst_rollback" cleanup +path frees the previously allocated options but doesn't remove them from +the team's option_list. +This leaves dangling pointers that can be dereferenced later by other +parts of the team driver that iterate over options. + +This patch fixes the cleanup path to remove the dangling pointers from +the list. + +As far as I can tell, this uaf doesn't have much security implications +since it would be fairly hard to exploit (an attacker would need to make +the allocation of that specific small object fail) but it's still nice +to fix. + +Cc: stable@vger.kernel.org +Fixes: 80f7c6683fe0 ("team: add support for per-port options") +Signed-off-by: Florent Revest +Reviewed-by: Jiri Pirko +Reviewed-by: Hangbin Liu +Link: https://lore.kernel.org/r/20231206123719.1963153-1-revest@chromium.org +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/team/team.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/drivers/net/team/team.c ++++ b/drivers/net/team/team.c +@@ -284,8 +284,10 @@ static int __team_options_register(struc + return 0; + + inst_rollback: +- for (i--; i >= 0; i--) ++ for (i--; i >= 0; i--) { + __team_option_inst_del_option(team, dst_opts[i]); ++ list_del(&dst_opts[i]->list); ++ } + + i = option_count; + alloc_rollback: -- 2.47.3