From: Jann Horn <jannh(a)google.com>
stable inclusion
from stable-v6.6.51
commit 3c6b4bcf37845c9359aed926324bed66bdd2448d
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IARWOX
CVE: CVE-2024-46787
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id…
--------------------------------
commit 71c186efc1b2cf1aeabfeff3b9bd5ac4c5ac14d8 upstream.
Patch series "userfaultfd: fix races around pmd_trans_huge() check", v2.
The pmd_trans_huge() code in mfill_atomic() is wrong in three different
ways depending on kernel version:
1. The pmd_trans_huge() check is racy and can lead to a BUG_ON() (if you hit
the right two race windows) - I've tested this in a kernel build with
some extra mdelay() calls. See the commit message for a description
of the race scenario.
On older kernels (before 6.5), I think the same bug can even
theoretically lead to accessing transhuge page contents as a page table
if you hit the right 5 narrow race windows (I haven't tested this case).
2. As pointed out by Qi Zheng, pmd_trans_huge() is not sufficient for
detecting PMDs that don't point to page tables.
On older kernels (before 6.5), you'd just have to win a single fairly
wide race to hit this.
I've tested this on 6.1 stable by racing migration (with a mdelay()
patched into try_to_migrate()) against UFFDIO_ZEROPAGE - on my x86
VM, that causes a kernel oops in ptlock_ptr().
3. On newer kernels (>=6.5), for shmem mappings, khugepaged is allowed
to yank page tables out from under us (though I haven't tested that),
so I think the BUG_ON() checks in mfill_atomic() are just wrong.
I decided to write two separate fixes for these (one fix for bugs 1+2, one
fix for bug 3), so that the first fix can be backported to kernels
affected by bugs 1+2.
This patch (of 2):
This fixes two issues.
I discovered that the following race can occur:
mfill_atomic other thread
============ ============
<zap PMD>
pmdp_get_lockless() [reads none pmd]
<bail if trans_huge>
<if none:>
<pagefault creates transhuge zeropage>
__pte_alloc [no-op]
<zap PMD>
<bail if pmd_trans_huge(*dst_pmd)>
BUG_ON(pmd_none(*dst_pmd))
I have experimentally verified this in a kernel with extra mdelay() calls;
the BUG_ON(pmd_none(*dst_pmd)) triggers.
On kernels newer than commit 0d940a9b270b ("mm/pgtable: allow
pte_offset_map[_lock]() to fail"), this can't lead to anything worse than
a BUG_ON(), since the page table access helpers are actually designed to
deal with page tables concurrently disappearing; but on older kernels
(<=6.4), I think we could probably theoretically race past the two
BUG_ON() checks and end up treating a hugepage as a page table.
The second issue is that, as Qi Zheng pointed out, there are other types
of huge PMDs that pmd_trans_huge() can't catch: devmap PMDs and swap PMDs
(in particular, migration PMDs).
On <=6.4, this is worse than the first issue: If mfill_atomic() runs on a
PMD that contains a migration entry (which just requires winning a single,
fairly wide race), it will pass the PMD to pte_offset_map_lock(), which
assumes that the PMD points to a page table.
Breakage follows: First, the kernel tries to take the PTE lock (which will
crash or maybe worse if there is no "struct page" for the address bits in
the migration entry PMD - I think at least on X86 there usually is no
corresponding "struct page" thanks to the PTE inversion mitigation, amd64
looks different).
If that didn't crash, the kernel would next try to write a PTE into what
it wrongly thinks is a page table.
As part of fixing these issues, get rid of the check for pmd_trans_huge()
before __pte_alloc() - that's redundant, we're going to have to check for
that after the __pte_alloc() anyway.
Backport note: pmdp_get_lockless() is pmd_read_atomic() in older kernels.
Link: https://lkml.kernel.org/r/20240813-uffd-thp-flip-fix-v2-0-5efa61078a41@goog…
Link: https://lkml.kernel.org/r/20240813-uffd-thp-flip-fix-v2-1-5efa61078a41@goog…
Fixes: c1a4de99fada ("userfaultfd: mcopy_atomic|mfill_zeropage: UFFDIO_COPY|UFFDIO_ZEROPAGE preparation")
Signed-off-by: Jann Horn <jannh(a)google.com>
Acked-by: David Hildenbrand <david(a)redhat.com>
Cc: Andrea Arcangeli <aarcange(a)redhat.com>
Cc: Hugh Dickins <hughd(a)google.com>
Cc: Jann Horn <jannh(a)google.com>
Cc: Pavel Emelyanov <xemul(a)virtuozzo.com>
Cc: Qi Zheng <zhengqi.arch(a)bytedance.com>
Cc: <stable(a)vger.kernel.org>
Signed-off-by: Andrew Morton <akpm(a)linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org>
Signed-off-by: Liu Shixin <liushixin2(a)huawei.com>
---
mm/userfaultfd.c | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 8c22dd4e5e15..b7562e6847b2 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -704,21 +704,23 @@ static __always_inline ssize_t mfill_atomic(struct mm_struct *dst_mm,
}
dst_pmdval = pmdp_get_lockless(dst_pmd);
- /*
- * If the dst_pmd is mapped as THP don't
- * override it and just be strict.
- */
- if (unlikely(pmd_trans_huge(dst_pmdval))) {
- err = -EEXIST;
- break;
- }
if (unlikely(pmd_none(dst_pmdval)) &&
unlikely(__pte_alloc(dst_mm, dst_pmd))) {
err = -ENOMEM;
break;
}
- /* If an huge pmd materialized from under us fail */
- if (unlikely(pmd_trans_huge(*dst_pmd))) {
+ dst_pmdval = pmdp_get_lockless(dst_pmd);
+ /*
+ * If the dst_pmd is THP don't override it and just be strict.
+ * (This includes the case where the PMD used to be THP and
+ * changed back to none after __pte_alloc().)
+ */
+ if (unlikely(!pmd_present(dst_pmdval) || pmd_trans_huge(dst_pmdval) ||
+ pmd_devmap(dst_pmdval))) {
+ err = -EEXIST;
+ break;
+ }
+ if (unlikely(pmd_bad(dst_pmdval))) {
err = -EFAULT;
break;
}
--
2.34.1
From: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
mainline inclusion
from mainline-v6.11-rc7
commit 48b9a8dabcc3cf5f961b2ebcd8933bf9204babb7
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IARY1L
CVE: CVE-2024-46738
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
When removing a resource from vmci_resource_table in
vmci_resource_remove(), the search is performed using the resource
handle by comparing context and resource fields.
It is possible though to create two resources with different types
but same handle (same context and resource fields).
When trying to remove one of the resources, vmci_resource_remove()
may not remove the intended one, but the object will still be freed
as in the case of the datagram type in vmci_datagram_destroy_handle().
vmci_resource_table will still hold a pointer to this freed resource
leading to a use-after-free vulnerability.
BUG: KASAN: use-after-free in vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
BUG: KASAN: use-after-free in vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
Read of size 4 at addr ffff88801c16d800 by task syz-executor197/1592
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x82/0xa9 lib/dump_stack.c:106
print_address_description.constprop.0+0x21/0x366 mm/kasan/report.c:239
__kasan_report.cold+0x7f/0x132 mm/kasan/report.c:425
kasan_report+0x38/0x51 mm/kasan/report.c:442
vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
vmci_qp_broker_detach+0x89a/0x11b9 drivers/misc/vmw_vmci/vmci_queue_pair.c:2182
ctx_free_ctx+0x473/0xbe1 drivers/misc/vmw_vmci/vmci_context.c:444
kref_put include/linux/kref.h:65 [inline]
vmci_ctx_put drivers/misc/vmw_vmci/vmci_context.c:497 [inline]
vmci_ctx_destroy+0x170/0x1d6 drivers/misc/vmw_vmci/vmci_context.c:195
vmci_host_close+0x125/0x1ac drivers/misc/vmw_vmci/vmci_host.c:143
__fput+0x261/0xa34 fs/file_table.c:282
task_work_run+0xf0/0x194 kernel/task_work.c:164
tracehook_notify_resume include/linux/tracehook.h:189 [inline]
exit_to_user_mode_loop+0x184/0x189 kernel/entry/common.c:187
exit_to_user_mode_prepare+0x11b/0x123 kernel/entry/common.c:220
__syscall_exit_to_user_mode_work kernel/entry/common.c:302 [inline]
syscall_exit_to_user_mode+0x18/0x42 kernel/entry/common.c:313
do_syscall_64+0x41/0x85 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x6e/0x0
This change ensures the type is also checked when removing
the resource from vmci_resource_table in vmci_resource_remove().
Fixes: bc63dedb7d46 ("VMCI: resource object implementation.")
Cc: stable(a)vger.kernel.org
Reported-by: George Kennedy <george.kennedy(a)oracle.com>
Signed-off-by: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
Signed-off-by: Zhang Kunbo <zhangkunbo(a)huawei.com>
---
drivers/misc/vmw_vmci/vmci_resource.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/vmw_vmci/vmci_resource.c b/drivers/misc/vmw_vmci/vmci_resource.c
index da1ee2e1ba99..2779704e128a 100644
--- a/drivers/misc/vmw_vmci/vmci_resource.c
+++ b/drivers/misc/vmw_vmci/vmci_resource.c
@@ -152,7 +152,8 @@ void vmci_resource_remove(struct vmci_resource *resource)
spin_lock(&vmci_resource_table.lock);
hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) {
- if (vmci_handle_is_equal(r->handle, resource->handle)) {
+ if (vmci_handle_is_equal(r->handle, resource->handle) &&
+ resource->type == r->type) {
hlist_del_init_rcu(&r->node);
break;
}
--
2.34.1
From: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
mainline inclusion
from mainline-v6.11-rc7
commit 48b9a8dabcc3cf5f961b2ebcd8933bf9204babb7
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IARY1L
CVE: CVE-2024-46738
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
When removing a resource from vmci_resource_table in
vmci_resource_remove(), the search is performed using the resource
handle by comparing context and resource fields.
It is possible though to create two resources with different types
but same handle (same context and resource fields).
When trying to remove one of the resources, vmci_resource_remove()
may not remove the intended one, but the object will still be freed
as in the case of the datagram type in vmci_datagram_destroy_handle().
vmci_resource_table will still hold a pointer to this freed resource
leading to a use-after-free vulnerability.
BUG: KASAN: use-after-free in vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
BUG: KASAN: use-after-free in vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
Read of size 4 at addr ffff88801c16d800 by task syz-executor197/1592
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x82/0xa9 lib/dump_stack.c:106
print_address_description.constprop.0+0x21/0x366 mm/kasan/report.c:239
__kasan_report.cold+0x7f/0x132 mm/kasan/report.c:425
kasan_report+0x38/0x51 mm/kasan/report.c:442
vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
vmci_qp_broker_detach+0x89a/0x11b9 drivers/misc/vmw_vmci/vmci_queue_pair.c:2182
ctx_free_ctx+0x473/0xbe1 drivers/misc/vmw_vmci/vmci_context.c:444
kref_put include/linux/kref.h:65 [inline]
vmci_ctx_put drivers/misc/vmw_vmci/vmci_context.c:497 [inline]
vmci_ctx_destroy+0x170/0x1d6 drivers/misc/vmw_vmci/vmci_context.c:195
vmci_host_close+0x125/0x1ac drivers/misc/vmw_vmci/vmci_host.c:143
__fput+0x261/0xa34 fs/file_table.c:282
task_work_run+0xf0/0x194 kernel/task_work.c:164
tracehook_notify_resume include/linux/tracehook.h:189 [inline]
exit_to_user_mode_loop+0x184/0x189 kernel/entry/common.c:187
exit_to_user_mode_prepare+0x11b/0x123 kernel/entry/common.c:220
__syscall_exit_to_user_mode_work kernel/entry/common.c:302 [inline]
syscall_exit_to_user_mode+0x18/0x42 kernel/entry/common.c:313
do_syscall_64+0x41/0x85 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x6e/0x0
This change ensures the type is also checked when removing
the resource from vmci_resource_table in vmci_resource_remove().
Fixes: bc63dedb7d46 ("VMCI: resource object implementation.")
Cc: stable(a)vger.kernel.org
Reported-by: George Kennedy <george.kennedy(a)oracle.com>
Signed-off-by: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
Signed-off-by: Zhang Kunbo <zhangkunbo(a)huawei.com>
---
drivers/misc/vmw_vmci/vmci_resource.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/vmw_vmci/vmci_resource.c b/drivers/misc/vmw_vmci/vmci_resource.c
index 692daa9eff34..19c9d2cdd277 100644
--- a/drivers/misc/vmw_vmci/vmci_resource.c
+++ b/drivers/misc/vmw_vmci/vmci_resource.c
@@ -144,7 +144,8 @@ void vmci_resource_remove(struct vmci_resource *resource)
spin_lock(&vmci_resource_table.lock);
hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) {
- if (vmci_handle_is_equal(r->handle, resource->handle)) {
+ if (vmci_handle_is_equal(r->handle, resource->handle) &&
+ resource->type == r->type) {
hlist_del_init_rcu(&r->node);
break;
}
--
2.34.1
From: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
mainline inclusion
from mainline-v6.11-rc7
commit 48b9a8dabcc3cf5f961b2ebcd8933bf9204babb7
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IARY1L
CVE: CVE-2024-46738
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
When removing a resource from vmci_resource_table in
vmci_resource_remove(), the search is performed using the resource
handle by comparing context and resource fields.
It is possible though to create two resources with different types
but same handle (same context and resource fields).
When trying to remove one of the resources, vmci_resource_remove()
may not remove the intended one, but the object will still be freed
as in the case of the datagram type in vmci_datagram_destroy_handle().
vmci_resource_table will still hold a pointer to this freed resource
leading to a use-after-free vulnerability.
BUG: KASAN: use-after-free in vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
BUG: KASAN: use-after-free in vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
Read of size 4 at addr ffff88801c16d800 by task syz-executor197/1592
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x82/0xa9 lib/dump_stack.c:106
print_address_description.constprop.0+0x21/0x366 mm/kasan/report.c:239
__kasan_report.cold+0x7f/0x132 mm/kasan/report.c:425
kasan_report+0x38/0x51 mm/kasan/report.c:442
vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
vmci_qp_broker_detach+0x89a/0x11b9 drivers/misc/vmw_vmci/vmci_queue_pair.c:2182
ctx_free_ctx+0x473/0xbe1 drivers/misc/vmw_vmci/vmci_context.c:444
kref_put include/linux/kref.h:65 [inline]
vmci_ctx_put drivers/misc/vmw_vmci/vmci_context.c:497 [inline]
vmci_ctx_destroy+0x170/0x1d6 drivers/misc/vmw_vmci/vmci_context.c:195
vmci_host_close+0x125/0x1ac drivers/misc/vmw_vmci/vmci_host.c:143
__fput+0x261/0xa34 fs/file_table.c:282
task_work_run+0xf0/0x194 kernel/task_work.c:164
tracehook_notify_resume include/linux/tracehook.h:189 [inline]
exit_to_user_mode_loop+0x184/0x189 kernel/entry/common.c:187
exit_to_user_mode_prepare+0x11b/0x123 kernel/entry/common.c:220
__syscall_exit_to_user_mode_work kernel/entry/common.c:302 [inline]
syscall_exit_to_user_mode+0x18/0x42 kernel/entry/common.c:313
do_syscall_64+0x41/0x85 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x6e/0x0
This change ensures the type is also checked when removing
the resource from vmci_resource_table in vmci_resource_remove().
Fixes: bc63dedb7d46 ("VMCI: resource object implementation.")
Cc: stable(a)vger.kernel.org
Reported-by: George Kennedy <george.kennedy(a)oracle.com>
Signed-off-by: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
Signed-off-by: Zhang Kunbo <zhangkunbo(a)huawei.com>
---
drivers/misc/vmw_vmci/vmci_resource.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/vmw_vmci/vmci_resource.c b/drivers/misc/vmw_vmci/vmci_resource.c
index 692daa9eff34..19c9d2cdd277 100644
--- a/drivers/misc/vmw_vmci/vmci_resource.c
+++ b/drivers/misc/vmw_vmci/vmci_resource.c
@@ -144,7 +144,8 @@ void vmci_resource_remove(struct vmci_resource *resource)
spin_lock(&vmci_resource_table.lock);
hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) {
- if (vmci_handle_is_equal(r->handle, resource->handle)) {
+ if (vmci_handle_is_equal(r->handle, resource->handle) &&
+ resource->type == r->type) {
hlist_del_init_rcu(&r->node);
break;
}
--
2.34.1
From: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
mainline inclusion
from mainline-v6.11-rc7
commit 48b9a8dabcc3cf5f961b2ebcd8933bf9204babb7
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IARY1L
CVE: CVE-2024-46738
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?…
--------------------------------
When removing a resource from vmci_resource_table in
vmci_resource_remove(), the search is performed using the resource
handle by comparing context and resource fields.
It is possible though to create two resources with different types
but same handle (same context and resource fields).
When trying to remove one of the resources, vmci_resource_remove()
may not remove the intended one, but the object will still be freed
as in the case of the datagram type in vmci_datagram_destroy_handle().
vmci_resource_table will still hold a pointer to this freed resource
leading to a use-after-free vulnerability.
BUG: KASAN: use-after-free in vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
BUG: KASAN: use-after-free in vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
Read of size 4 at addr ffff88801c16d800 by task syz-executor197/1592
Call Trace:
<TASK>
__dump_stack lib/dump_stack.c:88 [inline]
dump_stack_lvl+0x82/0xa9 lib/dump_stack.c:106
print_address_description.constprop.0+0x21/0x366 mm/kasan/report.c:239
__kasan_report.cold+0x7f/0x132 mm/kasan/report.c:425
kasan_report+0x38/0x51 mm/kasan/report.c:442
vmci_handle_is_equal include/linux/vmw_vmci_defs.h:142 [inline]
vmci_resource_remove+0x3a1/0x410 drivers/misc/vmw_vmci/vmci_resource.c:147
vmci_qp_broker_detach+0x89a/0x11b9 drivers/misc/vmw_vmci/vmci_queue_pair.c:2182
ctx_free_ctx+0x473/0xbe1 drivers/misc/vmw_vmci/vmci_context.c:444
kref_put include/linux/kref.h:65 [inline]
vmci_ctx_put drivers/misc/vmw_vmci/vmci_context.c:497 [inline]
vmci_ctx_destroy+0x170/0x1d6 drivers/misc/vmw_vmci/vmci_context.c:195
vmci_host_close+0x125/0x1ac drivers/misc/vmw_vmci/vmci_host.c:143
__fput+0x261/0xa34 fs/file_table.c:282
task_work_run+0xf0/0x194 kernel/task_work.c:164
tracehook_notify_resume include/linux/tracehook.h:189 [inline]
exit_to_user_mode_loop+0x184/0x189 kernel/entry/common.c:187
exit_to_user_mode_prepare+0x11b/0x123 kernel/entry/common.c:220
__syscall_exit_to_user_mode_work kernel/entry/common.c:302 [inline]
syscall_exit_to_user_mode+0x18/0x42 kernel/entry/common.c:313
do_syscall_64+0x41/0x85 arch/x86/entry/common.c:86
entry_SYSCALL_64_after_hwframe+0x6e/0x0
This change ensures the type is also checked when removing
the resource from vmci_resource_table in vmci_resource_remove().
Fixes: bc63dedb7d46 ("VMCI: resource object implementation.")
Cc: stable(a)vger.kernel.org
Reported-by: George Kennedy <george.kennedy(a)oracle.com>
Signed-off-by: David Fernandez Gonzalez <david.fernandez.gonzalez(a)oracle.com>
Signed-off-by: Zhang Kunbo <zhangkunbo(a)huawei.com>
---
drivers/misc/vmw_vmci/vmci_resource.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/vmw_vmci/vmci_resource.c b/drivers/misc/vmw_vmci/vmci_resource.c
index 692daa9eff34..19c9d2cdd277 100644
--- a/drivers/misc/vmw_vmci/vmci_resource.c
+++ b/drivers/misc/vmw_vmci/vmci_resource.c
@@ -144,7 +144,8 @@ void vmci_resource_remove(struct vmci_resource *resource)
spin_lock(&vmci_resource_table.lock);
hlist_for_each_entry(r, &vmci_resource_table.entries[idx], node) {
- if (vmci_handle_is_equal(r->handle, resource->handle)) {
+ if (vmci_handle_is_equal(r->handle, resource->handle) &&
+ resource->type == r->type) {
hlist_del_init_rcu(&r->node);
break;
}
--
2.34.1