* [PATCH 1/3] arm64: mte: Fix double-freeing of the temporary tag storage during coredump
2022-12-22 18:12 [PATCH 0/3] arm64: mte: Coredump fixes Catalin Marinas
@ 2022-12-22 18:12 ` Catalin Marinas
2022-12-22 18:12 ` [PATCH 2/3] elfcore: Add a cprm parameter to elf_core_extra_{phdrs,data_size} Catalin Marinas
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2022-12-22 18:12 UTC (permalink / raw)
To: Will Deacon, Seth Jenkins
Cc: Eric Biederman, Kees Cook, Greg Kroah-Hartman, linux-arm-kernel,
linux-mm
Commit 16decce22efa ("arm64: mte: Fix the stack frame size warning in
mte_dump_tag_range()") moved the temporary tag storage array from the
stack to slab but it also introduced an error in double freeing this
object. Remove the in-loop freeing.
Fixes: 16decce22efa ("arm64: mte: Fix the stack frame size warning in mte_dump_tag_range()")
Cc: <stable@vger.kernel.org> # 5.18.x
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reported-by: Seth Jenkins <sethjenkins@google.com>
Cc: Will Deacon <will@kernel.org>
---
arch/arm64/kernel/elfcore.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/arch/arm64/kernel/elfcore.c b/arch/arm64/kernel/elfcore.c
index 27ef7ad3ffd2..4e3f84799669 100644
--- a/arch/arm64/kernel/elfcore.c
+++ b/arch/arm64/kernel/elfcore.c
@@ -65,7 +65,6 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
mte_save_page_tags(page_address(page), tags);
put_page(page);
if (!dump_emit(cprm, tags, MTE_PAGE_TAG_STORAGE)) {
- mte_free_tag_storage(tags);
ret = 0;
break;
}
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/3] elfcore: Add a cprm parameter to elf_core_extra_{phdrs,data_size}
2022-12-22 18:12 [PATCH 0/3] arm64: mte: Coredump fixes Catalin Marinas
2022-12-22 18:12 ` [PATCH 1/3] arm64: mte: Fix double-freeing of the temporary tag storage during coredump Catalin Marinas
@ 2022-12-22 18:12 ` Catalin Marinas
2023-01-24 21:36 ` Kees Cook
2022-12-22 18:12 ` [PATCH 3/3] arm64: mte: Avoid the racy walk of the vma list during core dump Catalin Marinas
2023-01-05 18:03 ` [PATCH 0/3] arm64: mte: Coredump fixes Will Deacon
3 siblings, 1 reply; 6+ messages in thread
From: Catalin Marinas @ 2022-12-22 18:12 UTC (permalink / raw)
To: Will Deacon, Seth Jenkins
Cc: Eric Biederman, Kees Cook, Greg Kroah-Hartman, linux-arm-kernel,
linux-mm
A subsequent fix for arm64 will use this parameter to parse the vma
information from the snapshot created by dump_vma_snapshot() rather than
traversing the vma list without the mmap_lock.
Fixes: 6dd8b1a0b6cb ("arm64: mte: Dump the MTE tags in the core file")
Cc: <stable@vger.kernel.org> # 5.18.x
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reported-by: Seth Jenkins <sethjenkins@google.com>
Suggested-by: Seth Jenkins <sethjenkins@google.com>
Cc: Will Deacon <will@kernel.org>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Kees Cook <keescook@chromium.org>
---
arch/arm64/kernel/elfcore.c | 4 ++--
arch/ia64/kernel/elfcore.c | 4 ++--
arch/x86/um/elfcore.c | 4 ++--
fs/binfmt_elf.c | 4 ++--
fs/binfmt_elf_fdpic.c | 4 ++--
include/linux/elfcore.h | 8 ++++----
6 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/arch/arm64/kernel/elfcore.c b/arch/arm64/kernel/elfcore.c
index 4e3f84799669..b2388f15223e 100644
--- a/arch/arm64/kernel/elfcore.c
+++ b/arch/arm64/kernel/elfcore.c
@@ -76,7 +76,7 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
return ret;
}
-Elf_Half elf_core_extra_phdrs(void)
+Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
{
struct vm_area_struct *vma;
int vma_count = 0;
@@ -113,7 +113,7 @@ int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
return 1;
}
-size_t elf_core_extra_data_size(void)
+size_t elf_core_extra_data_size(struct coredump_params *cprm)
{
struct vm_area_struct *vma;
size_t data_size = 0;
diff --git a/arch/ia64/kernel/elfcore.c b/arch/ia64/kernel/elfcore.c
index 94680521fbf9..8895df121540 100644
--- a/arch/ia64/kernel/elfcore.c
+++ b/arch/ia64/kernel/elfcore.c
@@ -7,7 +7,7 @@
#include <asm/elf.h>
-Elf64_Half elf_core_extra_phdrs(void)
+Elf64_Half elf_core_extra_phdrs(struct coredump_params *cprm)
{
return GATE_EHDR->e_phnum;
}
@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
return 1;
}
-size_t elf_core_extra_data_size(void)
+size_t elf_core_extra_data_size(struct coredump_params *cprm)
{
const struct elf_phdr *const gate_phdrs =
(const struct elf_phdr *) (GATE_ADDR + GATE_EHDR->e_phoff);
diff --git a/arch/x86/um/elfcore.c b/arch/x86/um/elfcore.c
index 48a3eb09d951..650cdbbdaf45 100644
--- a/arch/x86/um/elfcore.c
+++ b/arch/x86/um/elfcore.c
@@ -7,7 +7,7 @@
#include <asm/elf.h>
-Elf32_Half elf_core_extra_phdrs(void)
+Elf32_Half elf_core_extra_phdrs(struct coredump_params *cprm)
{
return vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0;
}
@@ -60,7 +60,7 @@ int elf_core_write_extra_data(struct coredump_params *cprm)
return 1;
}
-size_t elf_core_extra_data_size(void)
+size_t elf_core_extra_data_size(struct coredump_params *cprm)
{
if ( vsyscall_ehdr ) {
const struct elfhdr *const ehdrp =
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 6a11025e5850..444302afc673 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -2209,7 +2209,7 @@ static int elf_core_dump(struct coredump_params *cprm)
* The number of segs are recored into ELF header as 16bit value.
* Please check DEFAULT_MAX_MAP_COUNT definition when you modify here.
*/
- segs = cprm->vma_count + elf_core_extra_phdrs();
+ segs = cprm->vma_count + elf_core_extra_phdrs(cprm);
/* for notes section */
segs++;
@@ -2249,7 +2249,7 @@ static int elf_core_dump(struct coredump_params *cprm)
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
offset += cprm->vma_data_size;
- offset += elf_core_extra_data_size();
+ offset += elf_core_extra_data_size(cprm);
e_shoff = offset;
if (e_phnum == PN_XNUM) {
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 08d0c8797828..2855f19ae3af 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1508,7 +1508,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
tmp->next = thread_list;
thread_list = tmp;
- segs = cprm->vma_count + elf_core_extra_phdrs();
+ segs = cprm->vma_count + elf_core_extra_phdrs(cprm);
/* for notes section */
segs++;
@@ -1554,7 +1554,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
offset += cprm->vma_data_size;
- offset += elf_core_extra_data_size();
+ offset += elf_core_extra_data_size(cprm);
e_shoff = offset;
if (e_phnum == PN_XNUM) {
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
index 346a8b56cdc8..79e26b18bf0e 100644
--- a/include/linux/elfcore.h
+++ b/include/linux/elfcore.h
@@ -114,14 +114,14 @@ static inline int elf_core_copy_task_fpregs(struct task_struct *t, struct pt_reg
* Dumping its extra ELF program headers includes all the other information
* a debugger needs to easily find how the gate DSO was being used.
*/
-extern Elf_Half elf_core_extra_phdrs(void);
+extern Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm);
extern int
elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset);
extern int
elf_core_write_extra_data(struct coredump_params *cprm);
-extern size_t elf_core_extra_data_size(void);
+extern size_t elf_core_extra_data_size(struct coredump_params *cprm);
#else
-static inline Elf_Half elf_core_extra_phdrs(void)
+static inline Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
{
return 0;
}
@@ -136,7 +136,7 @@ static inline int elf_core_write_extra_data(struct coredump_params *cprm)
return 1;
}
-static inline size_t elf_core_extra_data_size(void)
+static inline size_t elf_core_extra_data_size(struct coredump_params *cprm)
{
return 0;
}
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 2/3] elfcore: Add a cprm parameter to elf_core_extra_{phdrs,data_size}
2022-12-22 18:12 ` [PATCH 2/3] elfcore: Add a cprm parameter to elf_core_extra_{phdrs,data_size} Catalin Marinas
@ 2023-01-24 21:36 ` Kees Cook
0 siblings, 0 replies; 6+ messages in thread
From: Kees Cook @ 2023-01-24 21:36 UTC (permalink / raw)
To: Catalin Marinas
Cc: Will Deacon, Seth Jenkins, Eric Biederman, Greg Kroah-Hartman,
linux-arm-kernel, linux-mm
On Thu, Dec 22, 2022 at 06:12:50PM +0000, Catalin Marinas wrote:
> A subsequent fix for arm64 will use this parameter to parse the vma
> information from the snapshot created by dump_vma_snapshot() rather than
> traversing the vma list without the mmap_lock.
>
> Fixes: 6dd8b1a0b6cb ("arm64: mte: Dump the MTE tags in the core file")
> Cc: <stable@vger.kernel.org> # 5.18.x
> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Acked-by: Kees Cook <keescook@chromium.org>
--
Kees Cook
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 3/3] arm64: mte: Avoid the racy walk of the vma list during core dump
2022-12-22 18:12 [PATCH 0/3] arm64: mte: Coredump fixes Catalin Marinas
2022-12-22 18:12 ` [PATCH 1/3] arm64: mte: Fix double-freeing of the temporary tag storage during coredump Catalin Marinas
2022-12-22 18:12 ` [PATCH 2/3] elfcore: Add a cprm parameter to elf_core_extra_{phdrs,data_size} Catalin Marinas
@ 2022-12-22 18:12 ` Catalin Marinas
2023-01-05 18:03 ` [PATCH 0/3] arm64: mte: Coredump fixes Will Deacon
3 siblings, 0 replies; 6+ messages in thread
From: Catalin Marinas @ 2022-12-22 18:12 UTC (permalink / raw)
To: Will Deacon, Seth Jenkins
Cc: Eric Biederman, Kees Cook, Greg Kroah-Hartman, linux-arm-kernel,
linux-mm
The MTE coredump code in arch/arm64/kernel/elfcore.c iterates over the
vma list without the mmap_lock held. This can race with another process
or userfaultfd concurrently modifying the vma list. Change the
for_each_mte_vma macro and its callers to instead use the vma snapshot
taken by dump_vma_snapshot() and stored in the cprm object.
Fixes: 6dd8b1a0b6cb ("arm64: mte: Dump the MTE tags in the core file")
Cc: <stable@vger.kernel.org> # 5.18.x
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Reported-by: Seth Jenkins <sethjenkins@google.com>
Suggested-by: Seth Jenkins <sethjenkins@google.com>
Cc: Will Deacon <will@kernel.org>
---
arch/arm64/kernel/elfcore.c | 56 +++++++++++++++++--------------------
1 file changed, 26 insertions(+), 30 deletions(-)
diff --git a/arch/arm64/kernel/elfcore.c b/arch/arm64/kernel/elfcore.c
index b2388f15223e..662a61e5e75e 100644
--- a/arch/arm64/kernel/elfcore.c
+++ b/arch/arm64/kernel/elfcore.c
@@ -8,28 +8,27 @@
#include <asm/cpufeature.h>
#include <asm/mte.h>
-#define for_each_mte_vma(vmi, vma) \
+#define for_each_mte_vma(cprm, i, m) \
if (system_supports_mte()) \
- for_each_vma(vmi, vma) \
- if (vma->vm_flags & VM_MTE)
+ for (i = 0, m = cprm->vma_meta; \
+ i < cprm->vma_count; \
+ i++, m = cprm->vma_meta + i) \
+ if (m->flags & VM_MTE)
-static unsigned long mte_vma_tag_dump_size(struct vm_area_struct *vma)
+static unsigned long mte_vma_tag_dump_size(struct core_vma_metadata *m)
{
- if (vma->vm_flags & VM_DONTDUMP)
- return 0;
-
- return vma_pages(vma) * MTE_PAGE_TAG_STORAGE;
+ return (m->dump_size >> PAGE_SHIFT) * MTE_PAGE_TAG_STORAGE;
}
/* Derived from dump_user_range(); start/end must be page-aligned */
static int mte_dump_tag_range(struct coredump_params *cprm,
- unsigned long start, unsigned long end)
+ unsigned long start, unsigned long len)
{
int ret = 1;
unsigned long addr;
void *tags = NULL;
- for (addr = start; addr < end; addr += PAGE_SIZE) {
+ for (addr = start; addr < start + len; addr += PAGE_SIZE) {
struct page *page = get_dump_page(addr);
/*
@@ -78,11 +77,11 @@ static int mte_dump_tag_range(struct coredump_params *cprm,
Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
{
- struct vm_area_struct *vma;
+ int i;
+ struct core_vma_metadata *m;
int vma_count = 0;
- VMA_ITERATOR(vmi, current->mm, 0);
- for_each_mte_vma(vmi, vma)
+ for_each_mte_vma(cprm, i, m)
vma_count++;
return vma_count;
@@ -90,18 +89,18 @@ Elf_Half elf_core_extra_phdrs(struct coredump_params *cprm)
int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
{
- struct vm_area_struct *vma;
- VMA_ITERATOR(vmi, current->mm, 0);
+ int i;
+ struct core_vma_metadata *m;
- for_each_mte_vma(vmi, vma) {
+ for_each_mte_vma(cprm, i, m) {
struct elf_phdr phdr;
phdr.p_type = PT_AARCH64_MEMTAG_MTE;
phdr.p_offset = offset;
- phdr.p_vaddr = vma->vm_start;
+ phdr.p_vaddr = m->start;
phdr.p_paddr = 0;
- phdr.p_filesz = mte_vma_tag_dump_size(vma);
- phdr.p_memsz = vma->vm_end - vma->vm_start;
+ phdr.p_filesz = mte_vma_tag_dump_size(m);
+ phdr.p_memsz = m->end - m->start;
offset += phdr.p_filesz;
phdr.p_flags = 0;
phdr.p_align = 0;
@@ -115,26 +114,23 @@ int elf_core_write_extra_phdrs(struct coredump_params *cprm, loff_t offset)
size_t elf_core_extra_data_size(struct coredump_params *cprm)
{
- struct vm_area_struct *vma;
+ int i;
+ struct core_vma_metadata *m;
size_t data_size = 0;
- VMA_ITERATOR(vmi, current->mm, 0);
- for_each_mte_vma(vmi, vma)
- data_size += mte_vma_tag_dump_size(vma);
+ for_each_mte_vma(cprm, i, m)
+ data_size += mte_vma_tag_dump_size(m);
return data_size;
}
int elf_core_write_extra_data(struct coredump_params *cprm)
{
- struct vm_area_struct *vma;
- VMA_ITERATOR(vmi, current->mm, 0);
-
- for_each_mte_vma(vmi, vma) {
- if (vma->vm_flags & VM_DONTDUMP)
- continue;
+ int i;
+ struct core_vma_metadata *m;
- if (!mte_dump_tag_range(cprm, vma->vm_start, vma->vm_end))
+ for_each_mte_vma(cprm, i, m) {
+ if (!mte_dump_tag_range(cprm, m->start, m->dump_size))
return 0;
}
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH 0/3] arm64: mte: Coredump fixes
2022-12-22 18:12 [PATCH 0/3] arm64: mte: Coredump fixes Catalin Marinas
` (2 preceding siblings ...)
2022-12-22 18:12 ` [PATCH 3/3] arm64: mte: Avoid the racy walk of the vma list during core dump Catalin Marinas
@ 2023-01-05 18:03 ` Will Deacon
3 siblings, 0 replies; 6+ messages in thread
From: Will Deacon @ 2023-01-05 18:03 UTC (permalink / raw)
To: Seth Jenkins, Catalin Marinas
Cc: kernel-team, Will Deacon, Kees Cook, linux-arm-kernel,
Greg Kroah-Hartman, linux-mm, Eric Biederman
On Thu, 22 Dec 2022 18:12:48 +0000, Catalin Marinas wrote:
> As reported by Seth, there are two bugs in the arm64 MTE coredump code.
> The first is a double freeing of the temporary tag storage object on an
> error condition. The second is the racy traversing of the vma list and
> fixing it required adding a struct coredump_params * parameter to the
> elf_core_extra_phdrs() and elf_core_extra_data_size() functions. This
> way the arm64 code can use the vma snapshot saved in cprm rather than
> iterating over the vma list.
>
> [...]
Applied to arm64 (for-next/fixes), thanks!
[1/3] arm64: mte: Fix double-freeing of the temporary tag storage during coredump
https://git.kernel.org/arm64/c/736eedc974ea
[2/3] elfcore: Add a cprm parameter to elf_core_extra_{phdrs,data_size}
https://git.kernel.org/arm64/c/19e183b54528
[3/3] arm64: mte: Avoid the racy walk of the vma list during core dump
https://git.kernel.org/arm64/c/4f4c549feb4e
Cheers,
--
Will
https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev
^ permalink raw reply [flat|nested] 6+ messages in thread