Skip to content

Instantly share code, notes, and snippets.

@jpidancet

jpidancet/x.md Secret

Created August 31, 2022 10:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jpidancet/1ee457623426f3e3902a28edaf2c80d0 to your computer and use it in GitHub Desktop.
Save jpidancet/1ee457623426f3e3902a28edaf2c80d0 to your computer and use it in GitHub Desktop.
  1. Compile test module:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/atomic.h>

MODULE_LICENSE("GPL");

static atomic_t count = ATOMIC_INIT(0);

#define __hot __section(".text.hot")

int __hot do_something_likely(void)
{
	atomic_inc(&count);
	return 0;
}

int __cold do_something_unlikely(void)
{
	atomic_inc(&count);
	return 0;
}

int __section(".text") do_something(void)
{
	atomic_inc(&count);
 	return 0;
}

static int __init m_init(void)
{
	atomic_inc(&count);
	return 0;
}

static void __exit m_exit(void)
{
}

module_init(m_init);
module_exit(m_exit);
  1. Check content of the .smplocks section:
$ objdump -j .smp_locks -rs m.ko

m.ko:     file format elf64-x86-64

RELOCATION RECORDS FOR [.smp_locks]:
OFFSET           TYPE              VALUE 
0000000000000000 R_X86_64_PC32     .text.hot+0x0000000000000005
0000000000000004 R_X86_64_PC32     .text.unlikely+0x0000000000000005
0000000000000008 R_X86_64_PC32     .text+0x0000000000000005
000000000000000c R_X86_64_PC32     .init.text+0x0000000000000005


Contents of section .smp_locks:
 0000 00000000 00000000 00000000 00000000  ................

  1. Attach debugger to a VM with only 1 vCPU, running an unpatched kernel and insmod the test module:
$ gdb vmlinux
GNU gdb (GDB) Fedora 12.1-1.fc36
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
warning: Remote gdbserver does not support determining executable automatically.
RHEL <=6.8 and <=7.2 versions of gdbserver do not support such automatic executable detection.
The following versions of gdbserver support it:
- Upstream version of gdbserver (unsupported) 7.10 or later
- Red Hat Developer Toolset (DTS) version of gdbserver from DTS 4.0 or later (only on x86_64)
- RHEL-7.3 versions of gdbserver (on any architecture)
0xffffffff81d61c0b in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:52
52	}
(gdb) lx-symbols ~/smplocks_test
loading vmlinux
(gdb) b alternatives_smp_module_add
Breakpoint 1 at 0xffffffff81032f40: file arch/x86/kernel/alternative.c, line 677.
(gdb) c
Continuing.

Breakpoint 1, alternatives_smp_module_add (mod=mod@entry=0xffffffffa0203000, name=name@entry=0xffffffffa0203018 "m", locks=0xffffffffa0202020, locks_end=0xffffffffa0202030, text=0xffffffffa0201000, text_end=0xffffffffa0201013) at arch/x86/kernel/alternative.c:677
677	{
(gdb) p text
$1 = (void *) 0xffffffffa0201000
(gdb) p text_end
$2 = (void *) 0xffffffffa0201013
(gdb) p mod->core_layout.base
$3 = (void *) 0xffffffffa0201000
(gdb) p mod->core_layout.base + mod->core_layout.text_size
$4 = (void *) 0xffffffffa0202000
(gdb) b m_init
Function "m_init" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (m_init) pending.
(gdb) c
Continuing.
scanning for modules in /home/x/smplocks_test
scanning for modules in /home/x/linux-upstream
loading @0xffffffffa0201000: /home/x/smplocks_test/m.ko

Breakpoint 2, m_init () at /home/x/smplocks_test/m.c:31
31	{
(gdb) disassemble m_init
Dump of assembler code for function m_init:
=> 0xffffffffa0206000 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0206005 <+5>:	lock incl -0x2c8c(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020600c <+12>:	xor    %eax,%eax
   0xffffffffa020600e <+14>:	ret    
   0xffffffffa020600f <+15>:	int3   
   0xffffffffa0206010 <+16>:	int3   
   0xffffffffa0206011 <+17>:	int3   
   0xffffffffa0206012 <+18>:	int3   
End of assembler dump.
(gdb) disassemble do_something
Dump of assembler code for function do_something:
   0xffffffffa0201000 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0201005 <+5>:	ds incl 0x2374(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020100c <+12>:	xor    %eax,%eax
   0xffffffffa020100e <+14>:	ret    
   0xffffffffa020100f <+15>:	int3   
   0xffffffffa0201010 <+16>:	int3   
   0xffffffffa0201011 <+17>:	int3   
   0xffffffffa0201012 <+18>:	int3   
End of assembler dump.
(gdb) disassemble do_something_likely
Dump of assembler code for function do_something_likely:
   0xffffffffa0201020 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0201025 <+5>:	lock incl 0x2354(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020102c <+12>:	xor    %eax,%eax
   0xffffffffa020102e <+14>:	ret    
   0xffffffffa020102f <+15>:	int3   
   0xffffffffa0201030 <+16>:	int3   
   0xffffffffa0201031 <+17>:	int3   
   0xffffffffa0201032 <+18>:	int3   
End of assembler dump.
(gdb) disassemble do_something_unlikely
Dump of assembler code for function do_something_unlikely:
   0xffffffffa0201033 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0201038 <+5>:	lock incl 0x2341(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020103f <+12>:	xor    %eax,%eax
   0xffffffffa0201041 <+14>:	ret    
   0xffffffffa0201042 <+15>:	int3   
   0xffffffffa0201043 <+16>:	int3   
   0xffffffffa0201044 <+17>:	int3   
   0xffffffffa0201045 <+18>:	int3   
End of assembler dump.

As you can see, the lock prefix in do_something() was changed to a DS segment override prefix, but not in do_something_likely() nor in do_something_unlikely().

  1. Apply the patch and check that the lock prefixes in are getting changed properly in all of the required sections:
$ gdb vmlinux
GNU gdb (GDB) Fedora 12.1-1.fc36
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
warning: Remote gdbserver does not support determining executable automatically.
RHEL <=6.8 and <=7.2 versions of gdbserver do not support such automatic executable detection.
The following versions of gdbserver support it:
- Upstream version of gdbserver (unsupported) 7.10 or later
- Red Hat Developer Toolset (DTS) version of gdbserver from DTS 4.0 or later (only on x86_64)
- RHEL-7.3 versions of gdbserver (on any architecture)
0xffffffff81d61c0b in native_safe_halt () at ./arch/x86/include/asm/irqflags.h:52
52	}
(gdb) lx-symbols ~/smplocks_test
loading vmlinux
(gdb) b alternatives_smp_module_add
Breakpoint 1 at 0xffffffff81032f40: file arch/x86/kernel/alternative.c, line 677.
(gdb) c
Continuing.

Breakpoint 1, alternatives_smp_module_add (mod=mod@entry=0xffffffffa0203000, name=name@entry=0xffffffffa0203018 "m", locks=0xffffffffa0202020, locks_end=0xffffffffa0202030, text=0xffffffffa0201000, text_end=0xffffffffa0202000) at arch/x86/kernel/alternative.c:677
677	{
(gdb) p text
$1 = (void *) 0xffffffffa0201000
(gdb) p text_end
$2 = (void *) 0xffffffffa0202000
(gdb) b m_init
Function "m_init" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 2 (m_init) pending.
(gdb) c
Continuing.
scanning for modules in /home/x/smplocks_test
scanning for modules in /home/x/linux-upstream
loading @0xffffffffa0201000: /home/x/smplocks_test/m.ko

Breakpoint 2, m_init () at /home/x/smplocks_test/m.c:31
31	{
(gdb) disassemble m_init
Dump of assembler code for function m_init:
=> 0xffffffffa0206000 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0206005 <+5>:	lock incl -0x2c8c(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020600c <+12>:	xor    %eax,%eax
   0xffffffffa020600e <+14>:	ret    
   0xffffffffa020600f <+15>:	int3   
   0xffffffffa0206010 <+16>:	int3   
   0xffffffffa0206011 <+17>:	int3   
   0xffffffffa0206012 <+18>:	int3   
End of assembler dump.
(gdb) disassemble do_something
Dump of assembler code for function do_something:
   0xffffffffa0201000 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0201005 <+5>:	ds incl 0x2374(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020100c <+12>:	xor    %eax,%eax
   0xffffffffa020100e <+14>:	ret    
   0xffffffffa020100f <+15>:	int3   
   0xffffffffa0201010 <+16>:	int3   
   0xffffffffa0201011 <+17>:	int3   
   0xffffffffa0201012 <+18>:	int3   
End of assembler dump.
(gdb) disassemble do_something_likely
Dump of assembler code for function do_something_likely:
   0xffffffffa0201020 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0201025 <+5>:	ds incl 0x2354(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020102c <+12>:	xor    %eax,%eax
   0xffffffffa020102e <+14>:	ret    
   0xffffffffa020102f <+15>:	int3   
   0xffffffffa0201030 <+16>:	int3   
   0xffffffffa0201031 <+17>:	int3   
   0xffffffffa0201032 <+18>:	int3   
End of assembler dump.
(gdb) disassemble do_something_unlikely
Dump of assembler code for function do_something_unlikely:
   0xffffffffa0201033 <+0>:	nopl   0x0(%rax,%rax,1)
   0xffffffffa0201038 <+5>:	ds incl 0x2341(%rip)        # 0xffffffffa0203380 <count>
   0xffffffffa020103f <+12>:	xor    %eax,%eax
   0xffffffffa0201041 <+14>:	ret    
   0xffffffffa0201042 <+15>:	int3   
   0xffffffffa0201043 <+16>:	int3   
   0xffffffffa0201044 <+17>:	int3   
   0xffffffffa0201045 <+18>:	int3   
End of assembler dump.

Note that the lock prefix in m_init() has been left untouched because it is located in the .init.text section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment