diff --git a/patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch b/patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch new file mode 100644 index 0000000..d5a517e --- /dev/null +++ b/patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch @@ -0,0 +1,63 @@ +From aba7bc914ab6839a4368119d640d5f5cd5e54c85 Mon Sep 17 00:00:00 2001 +From: Vlastimil Babka +Date: Fri, 2 Sep 2022 13:18:12 +0200 +Subject: [PATCH] kABI: Fix kABI after "mm/rmap: Fix anon_vma->degree ambiguity + leading to double-reuse" +Patch-mainline; Never, SUSE kABI +References: git-fixes, bsc#1203098 + +The patch changes struct anon_vma which is exposed, although should not be used +by any non-core code. Move the new fields to the end (hidden from KABI checker) +and restore the removed degree field so the layout doesn't change within the old +size. + +Signed-off-by: Vlastimil Babka +--- + include/linux/rmap.h | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +--- a/include/linux/rmap.h ++++ b/include/linux/rmap.h +@@ -37,16 +37,12 @@ struct anon_vma { + */ + atomic_t refcount; + +- /* +- * Count of child anon_vmas. Equals to the count of all anon_vmas that +- * have ->parent pointing to this one, including itself. +- * +- * This counter is used for making decision about reusing anon_vma +- * instead of forking new one. See comments in function anon_vma_clone. +- */ +- unsigned long num_children; +- /* Count of VMAs whose ->anon_vma pointer points to this object. */ +- unsigned long num_active_vmas; ++ /* SUSE KABI compatibility placeholder */ ++#ifndef __GENKSYMS__ ++ unsigned __unused_degree; ++#else ++ unsigned degree; ++#endif + + struct anon_vma *parent; /* Parent of this anon_vma */ + +@@ -59,6 +55,19 @@ struct anon_vma { + * mm_take_all_locks() (mm_all_locks_mutex). + */ + struct rb_root rb_root; /* Interval tree of private "related" vmas */ ++ ++#ifndef __GENKSYMS__ ++ /* ++ * Count of child anon_vmas. Equals to the count of all anon_vmas that ++ * have ->parent pointing to this one, including itself. ++ * ++ * This counter is used for making decision about reusing anon_vma ++ * instead of forking new one. See comments in function anon_vma_clone. ++ */ ++ unsigned long num_children; ++ /* Count of VMAs whose ->anon_vma pointer points to this object. */ ++ unsigned long num_active_vmas; ++#endif + }; + + /* diff --git a/patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch b/patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch new file mode 100644 index 0000000..18e1180 --- /dev/null +++ b/patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch @@ -0,0 +1,164 @@ +From: Jann Horn +Date: Wed, 31 Aug 2022 19:06:00 +0200 +Subject: mm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse +Git-commit: 2555283eb40df89945557273121e9393ef9b542b +Patch-mainline: v6.0-rc4 +References: git-fixes, bsc#1203098 + +anon_vma->degree tracks the combined number of child anon_vmas and VMAs +that use the anon_vma as their ->anon_vma. + +anon_vma_clone() then assumes that for any anon_vma attached to +src->anon_vma_chain other than src->anon_vma, it is impossible for it to +be a leaf node of the VMA tree, meaning that for such VMAs ->degree is +elevated by 1 because of a child anon_vma, meaning that if ->degree +equals 1 there are no VMAs that use the anon_vma as their ->anon_vma. + +This assumption is wrong because the ->degree optimization leads to leaf +nodes being abandoned on anon_vma_clone() - an existing anon_vma is +reused and no new parent-child relationship is created. So it is +possible to reuse an anon_vma for one VMA while it is still tied to +another VMA. + +This is an issue because is_mergeable_anon_vma() and its callers assume +that if two VMAs have the same ->anon_vma, the list of anon_vmas +attached to the VMAs is guaranteed to be the same. When this assumption +is violated, vma_merge() can merge pages into a VMA that is not attached +to the corresponding anon_vma, leading to dangling page->mapping +pointers that will be dereferenced during rmap walks. + +Fix it by separately tracking the number of child anon_vmas and the +number of VMAs using the anon_vma as their ->anon_vma. + +Fixes: 7a3ef208e662 ("mm: prevent endless growth of anon_vma hierarchy") +Cc: stable@kernel.org +Acked-by: Michal Hocko +Acked-by: Vlastimil Babka +Signed-off-by: Jann Horn +Signed-off-by: Linus Torvalds +--- + include/linux/rmap.h | 7 +++++-- + mm/rmap.c | 29 ++++++++++++++++------------- + 2 files changed, 21 insertions(+), 15 deletions(-) + +--- a/include/linux/rmap.h ++++ b/include/linux/rmap.h +@@ -38,12 +38,15 @@ struct anon_vma { + atomic_t refcount; + + /* +- * Count of child anon_vmas and VMAs which points to this anon_vma. ++ * Count of child anon_vmas. Equals to the count of all anon_vmas that ++ * have ->parent pointing to this one, including itself. + * + * This counter is used for making decision about reusing anon_vma + * instead of forking new one. See comments in function anon_vma_clone. + */ +- unsigned degree; ++ unsigned long num_children; ++ /* Count of VMAs whose ->anon_vma pointer points to this object. */ ++ unsigned long num_active_vmas; + + struct anon_vma *parent; /* Parent of this anon_vma */ + +--- a/mm/rmap.c ++++ b/mm/rmap.c +@@ -82,7 +82,8 @@ static inline struct anon_vma *anon_vma_ + anon_vma = kmem_cache_alloc(anon_vma_cachep, GFP_KERNEL); + if (anon_vma) { + atomic_set(&anon_vma->refcount, 1); +- anon_vma->degree = 1; /* Reference for first vma */ ++ anon_vma->num_children = 0; ++ anon_vma->num_active_vmas = 0; + anon_vma->parent = anon_vma; + /* + * Initialise the anon_vma root to point to itself. If called +@@ -190,6 +191,7 @@ int __anon_vma_prepare(struct vm_area_st + anon_vma = anon_vma_alloc(); + if (unlikely(!anon_vma)) + goto out_enomem_free_avc; ++ anon_vma->num_children++; /* self-parent link for new root */ + allocated = anon_vma; + } + +@@ -199,8 +201,7 @@ int __anon_vma_prepare(struct vm_area_st + if (likely(!vma->anon_vma)) { + vma->anon_vma = anon_vma; + anon_vma_chain_link(vma, avc, anon_vma); +- /* vma reference or self-parent link for new root */ +- anon_vma->degree++; ++ anon_vma->num_active_vmas++; + allocated = NULL; + avc = NULL; + } +@@ -285,19 +286,19 @@ int anon_vma_clone(struct vm_area_struct + anon_vma_chain_link(dst, avc, anon_vma); + + /* +- * Reuse existing anon_vma if its degree lower than two, +- * that means it has no vma and only one anon_vma child. ++ * Reuse existing anon_vma if it has no vma and only one ++ * anon_vma child. + * +- * Do not chose parent anon_vma, otherwise first child +- * will always reuse it. Root anon_vma is never reused: ++ * Root anon_vma is never reused: + * it has self-parent reference and at least one child. + */ + if (!dst->anon_vma && src->anon_vma && +- anon_vma != src->anon_vma && anon_vma->degree < 2) ++ anon_vma->num_children < 2 && ++ anon_vma->num_active_vmas == 0) + dst->anon_vma = anon_vma; + } + if (dst->anon_vma) +- dst->anon_vma->degree++; ++ dst->anon_vma->num_active_vmas++; + unlock_anon_vma_root(root); + return 0; + +@@ -347,6 +348,7 @@ int anon_vma_fork(struct vm_area_struct + anon_vma = anon_vma_alloc(); + if (!anon_vma) + goto out_error; ++ anon_vma->num_active_vmas++; + avc = anon_vma_chain_alloc(GFP_KERNEL); + if (!avc) + goto out_error_free_anon_vma; +@@ -367,7 +369,7 @@ int anon_vma_fork(struct vm_area_struct + vma->anon_vma = anon_vma; + anon_vma_lock_write(anon_vma); + anon_vma_chain_link(vma, avc, anon_vma); +- anon_vma->parent->degree++; ++ anon_vma->parent->num_children++; + anon_vma_unlock_write(anon_vma); + + return 0; +@@ -399,7 +401,7 @@ void unlink_anon_vmas(struct vm_area_str + * to free them outside the lock. + */ + if (RB_EMPTY_ROOT(&anon_vma->rb_root)) { +- anon_vma->parent->degree--; ++ anon_vma->parent->num_children--; + continue; + } + +@@ -407,7 +409,7 @@ void unlink_anon_vmas(struct vm_area_str + anon_vma_chain_free(avc); + } + if (vma->anon_vma) +- vma->anon_vma->degree--; ++ vma->anon_vma->num_active_vmas--; + unlock_anon_vma_root(root); + + /* +@@ -418,7 +420,8 @@ void unlink_anon_vmas(struct vm_area_str + list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) { + struct anon_vma *anon_vma = avc->anon_vma; + +- VM_WARN_ON(anon_vma->degree); ++ VM_WARN_ON(anon_vma->num_children); ++ VM_WARN_ON(anon_vma->num_active_vmas); + put_anon_vma(anon_vma); + + list_del(&avc->same_vma); diff --git a/series.conf b/series.conf index ee5c69d..cf330d0 100644 --- a/series.conf +++ b/series.conf @@ -61782,6 +61782,7 @@ patches.suse/xen-xenbus-fix-return-type-in-xenbus_file_read.patch patches.suse/net_sched-cls_route-disallow-handle-of-0.patch patches.suse/af_key-Do-not-call-xfrm_probe_algs-in-parallel.patch + patches.suse/mm-rmap-Fix-anon_vma-degree-ambiguity-leading-to-double-reuse.patch # dhowells/linux-fs keys-uefi patches.suse/0001-KEYS-Allow-unrestricted-boot-time-addition-of-keys-t.patch @@ -62795,6 +62796,7 @@ patches.kabi/kabi-return-type-change-of-secure_ipv-46-_port_ephem.patch patches.kabi/sctp-handle-kabi-change-in-struct-sctp_endpoint.patch patches.kabi/qed-fixup-kabi-for-qed_rdma_create_qp_in_params.patch + patches.kabi/kABI-Fix-kABI-after-mm-rmap-Fix-anon_vma-degree-ambi.patch ######################################################## # You'd better have a good reason for adding a patch