Skip to content

R_X86_64_REX_GOTPCRELX emitted in a kernel module when compiling with -fsanitize-coverage=trace-pc-guard #132393

Open
@ramosian-glider

Description

@ramosian-glider

I am trying to bring support for -fsanitize-coverage=trace-pc-guard to the Linux kernel (draft patchset at ramosian-glider/linux#7)

The module looks as follows:

#include <linux/module.h>
MODULE_LICENSE("GPL");

static int __init testmod_init(void) {
    return 0;
}

module_init(testmod_init);

In the IR, the compiler declares two variables to reference the beginning and the end of the __sancov_guards section, @__start___sancov_guards and @__stop___sancov_guards:

...
$sancov.module_ctor_trace_pc_guard = comdat any 
...
@__sancov_gen_ = private global [1 x i32] zeroinitializer, section "__sancov_guards", comdat($init_module), align 4
@__start___sancov_guards = extern_weak hidden global i32 
@__stop___sancov_guards = extern_weak hidden global i32 
@llvm.used = appending global [2 x ptr] [ptr @sancov.module_ctor_trace_pc_guard, ptr @asan.module_ctor], section "llvm.metadata"
@llvm.compiler.used = appending global [3 x ptr] [ptr @__UNIQUE_ID___addressable_init_module564, ptr @__UNIQUE_ID_license563, ptr @__sancov_gen_], section "llvm.metadata"
@___asan_gen_module = private constant [17 x i8] c"kernel/testmod.c\00", align 1
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 2, ptr @sancov.module_ctor_trace_pc_guard, ptr @sancov.module_ctor_trace_pc_guard }]
...
declare void @__sanitizer_cov_trace_pc_guard_init(ptr, ptr)

; Function Attrs: fn_ret_thunk_extern nounwind
define internal void @sancov.module_ctor_trace_pc_guard() #1 comdat {
  call void @__asan_before_dynamic_init(i64 ptrtoint (ptr @___asan_gen_module to i64))
  call void @__sanitizer_cov_trace_pc_guard_init(ptr @__start___sancov_guards, ptr @__stop___sancov_guards)
  call void @__asan_after_dynamic_init()
  ret void 
}

(full IR: testmod.txt)

For the parameters of __sanitizer_cov_trace_pc_guard_init() the backend generates two R_X86_64_REX_GOTPCRELX in the object file:

0000000000000000 <sancov.module_ctor_trace_pc_guard>:
   0:	f3 0f 1e fa          	endbr64
   4:	48 c7 c7 00 00 00 00 	mov    $0x0,%rdi
			7: R_X86_64_32S	.rodata
   b:	e8 00 00 00 00       	call   10 <sancov.module_ctor_trace_pc_guard+0x10>
			c: R_X86_64_PLT32	__asan_before_dynamic_init-0x4
  10:	48 8b 3d 00 00 00 00 	mov    0x0(%rip),%rdi        # 17 <sancov.module_ctor_trace_pc_guard+0x17>
			13: R_X86_64_REX_GOTPCRELX	__start___sancov_guards-0x4
  17:	48 8b 35 00 00 00 00 	mov    0x0(%rip),%rsi        # 1e <sancov.module_ctor_trace_pc_guard+0x1e>
			1a: R_X86_64_REX_GOTPCRELX	__stop___sancov_guards-0x4
  1e:	e8 00 00 00 00       	call   23 <sancov.module_ctor_trace_pc_guard+0x23>
			1f: R_X86_64_PLT32	__sanitizer_cov_trace_pc_guard_init-0x4
  23:	e8 00 00 00 00       	call   28 <sancov.module_ctor_trace_pc_guard+0x28>
			24: R_X86_64_PLT32	__asan_after_dynamic_init-0x4
  28:	2e e9 00 00 00 00    	cs jmp 2e <init_module+0x1e>
			2a: R_X86_64_PLT32	__x86_return_thunk-0x4

, which remain in the resulting kernel module, making it unusable, as the kernel cannot process this relocation type:

$ objdump -r kernel/testmod.ko | grep PCREL
0000000000000013 R_X86_64_REX_GOTPCRELX  __start___sancov_guards-0x0000000000000004
000000000000001a R_X86_64_REX_GOTPCRELX  __stop___sancov_guards-0x0000000000000004

I am wondering if it is correct to declare the __start and __stop variables as extern_weak hidden global for the modules. Given that we want __sanitizer_cov_trace_pc_guard_init() in a module to be called for the contents of the __sancov_guards section of that module, not the vmlinux binary, shouldn't these variables be dso_local, or something alike?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions