Skip to contentSkip to conversation

aarch64: always map VDSO at worst case alignment

PATCH In review Kyle McMartin 2 participants 5 messages Jan 15, 2014 – Jan 16, 2014 arm64

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 aarch64: always map VDSO at worst case alignment

Currently on ARM64 with 4K pages set, GDB fails to load the VDSO with the error "Failed to read a valid object file image from memory" as it is applying the phdr alignment to the vma, and attempting to read below where the VDSO is mapped. This is because our segment alignment is 64K in the ELF headers, but the VDSO only has PAGE_SIZE alignment from get_unmapped_area.

Work around this by calling vm_unmapped_area directly, and specifying the worst case alignment (64K) directly.

With this patch applied, I no longer have issues loading the VDSO in gdb (and no more error message every time I run a program inside it.)

arch/arm64/kernel/vdso.c +12 -1
@@ -163,7 +163,18 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
 	vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
 
 	down_write(&mm->mmap_sem);
-	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+	{
+		/* the VDSO must be worst-case aligned to 64K */
+		struct vm_unmapped_area_info info =
+			{
+				.flags = 0,
+				.length = vdso_mapping_len,
+				.low_limit = mm->mmap_base,
+				.high_limit = TASK_SIZE,
+				.align_mask = (1 << 16) - 1,
+			};
+		vdso_base = vm_unmapped_area(&info);
+	}
 	if (IS_ERR_VALUE(vdso_base)) {
 		ret = vdso_base;
 		goto up_fail;
#1 lore raw

Hi Kyle,

Quoted 24 lines · Kyle McMartin

Currently on ARM64 with 4K pages set, GDB fails to load the VDSO with the error "Failed to read a valid object file image from memory" as it is applying the phdr alignment to the vma, and attempting to read below where the VDSO is mapped. This is because our segment alignment is 64K in the ELF headers, but the VDSO only has PAGE_SIZE alignment from get_unmapped_area.

Work around this by calling vm_unmapped_area directly, and specifying the worst case alignment (64K) directly.

With this patch applied, I no longer have issues loading the VDSO in gdb (and no more error message every time I run a program inside it.)

arch/arm64/kernel/vdso.c +2 -1
@@ -163,7 +163,18 @@ int arch_setup_additional_pages(struct linux_binprm *bprm,
 	vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
 
 	down_write(&mm->mmap_sem);
-	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+	{
+		/* the VDSO must be worst-case aligned to 64K */

arch/arm64/kernel/vdso.c int arch_setup_additional_pages(struct linux_binprm *bprm, · line 177

Quoted 10 lines
arch/arm64/kernel/vdso.c +10 -0
+		struct vm_unmapped_area_info info =
+			{
+				.flags = 0,
+				.length = vdso_mapping_len,
+				.low_limit = mm->mmap_base,
+				.high_limit = TASK_SIZE,
+				.align_mask = (1 << 16) - 1,
+			};
+		vdso_base = vm_unmapped_area(&info);
+	}

I don't like this fix. The kernel is perfectly alright mapping the vdso at the actual page size, as opposed to the maximum. Since the vdso isn't demand-paged, we can actually just tell the linker not to bother forcing 64k (worst case) alignment for PT_LOAD segments. Please can you try the patch below?

Will

--->8

arch/arm64/kernel/vdso/Makefile +1 -1
index d8064af42e62..6d20b7d162d8 100644
@@ -48,7 +48,7 @@ $(obj-vdso): %.o: %.S
 
 # Actual build commands
 quiet_cmd_vdsold = VDSOL $@
-      cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@
+      cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@
 quiet_cmd_vdsoas = VDSOA $@
       cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
 
author Acked-by
#2 lore raw
Quoted 8 lines · Will Deacon
Quoted 8 lines
(quoted diff) +8 -0
+		struct vm_unmapped_area_info info =
+			{
+				.flags = 0,
+				.length = vdso_mapping_len,
+				.low_limit = mm->mmap_base,
+				.high_limit = TASK_SIZE,
+				.align_mask = (1 << 16) - 1,
+			};
Quoted 9 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+		vdso_base = vm_unmapped_area(&info);
+	}

I don't like this fix. The kernel is perfectly alright mapping the vdso at the actual page size, as opposed to the maximum. Since the vdso isn't demand-paged, we can actually just tell the linker not to bother forcing 64k (worst case) alignment for PT_LOAD segments. Please can you try the patch below?

Me either, tbh. ;-)

I was testing out using -Wl,-z,max-page-size for the !CONFIG_ARM64_64K_PAGES case, and that seemed to work. A quick compile check shows the segment alignment being 0x10 with -Wl,-n:

kmcmarti ~/linux $ eu-readelf -l
arch/arm64/kernel/vdso/vdso.so
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz
MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000700
0x000700 R E 0x10

so I think that should work nicely!

I'll reboot a machine with this fix to test it as soon as possible.

Quoted 11 lines
arch/arm64/kernel/vdso/Makefile +1 -1
@@ -48,7 +48,7 @@ $(obj-vdso): %.o: %.S
 
 # Actual build commands
 quiet_cmd_vdsold = VDSOL $@
-      cmd_vdsold = $(CC) $(c_flags) -Wl,-T $^ -o $@
+      cmd_vdsold = $(CC) $(c_flags) -Wl,-n -Wl,-T $^ -o $@
 quiet_cmd_vdsoas = VDSOA $@
       cmd_vdsoas = $(CC) $(a_flags) -c -o $@ $<
 
#3 lore raw
Quoted 4 lines · Kyle McMartin

I'll reboot a machine with this fix to test it as soon as possible.

Yeah, looks to work properly, although I didn't test 64K pages in the simulator.

--Kyle

#4 lore raw
Quoted 8 lines · Kyle McMartin
Quoted 4 lines · Kyle McMartin

I'll reboot a machine with this fix to test it as soon as possible.

Yeah, looks to work properly, although I didn't test 64K pages in the simulator.

No problem. I did try testing 64k pages in the simulator, and found that earlyprintk is broken (now fixed).

Cheers,

Will