Skip to content

Function pointer translation to klp-relocations broken? #1440

@joe-lawrence

Description

@joe-lawrence

For a simple patch like:

diff -Nupr src.orig/fs/proc/cmdline.c src/fs/proc/cmdline.c
--- src.orig/fs/proc/cmdline.c	2022-10-24 15:41:08.858760066 -0400
+++ src/fs/proc/cmdline.c	2022-10-24 15:41:11.698715352 -0400
@@ -6,8 +6,7 @@
 
 static int cmdline_proc_show(struct seq_file *m, void *v)
 {
-	seq_puts(m, saved_command_line);
-	seq_putc(m, '\n');
+	seq_printf(m, "%s cmdline_proc_show=%p\n", saved_command_line, cmdline_proc_show);
 	return 0;
 }

kpatch-build used to create a dynrela / klp-relocation for the cmdline_proc_show function pointer so that its value it resolved at runtime to the original function and not the kpatch instance. (See #755 and #789.)

This behavior is no longer true for both RHEL-9.6 x86 and ppc64le arches. For example, from the generated livepatch .ko on power:

  Disassembly of section .text.cmdline_proc_show:
  
  0000000000000000 <cmdline_proc_show-0x8>:
          ...
                          0: R_PPC64_REL64        .TOC.-0x8
  
  0000000000000008 <cmdline_proc_show>:
     8:   f8 ff 4c e8     ld      r2,-8(r12)
                          8: R_PPC64_ENTRY        *ABS*
     c:   14 62 42 7c     add     r2,r2,r12
    10:   a6 02 08 7c     mflr    r0
    14:   01 00 00 48     bl      14 <cmdline_proc_show+0xc>
                          14: R_PPC64_REL24       _mcount
    18:   a6 02 08 7c     mflr    r0
    1c:   00 00 22 3d     addis   r9,r2,0
                          1c: R_PPC64_TOC16_HA    .toc+0xa0
    20:   00 00 42 3d     addis   r10,r2,0
>                         20: R_PPC64_TOC16_HA    .toc+0x90
    24:   00 00 29 e9     ld      r9,0(r9)
                          24: R_PPC64_TOC16_LO_DS .toc+0xa0
    28:   00 00 ca e8     ld      r6,0(r10)
>                         28: R_PPC64_TOC16_LO_DS .toc+0x90
    2c:   00 00 42 3d     addis   r10,r2,0
                          2c: R_PPC64_TOC16_HA    .toc+0xa8
    30:   00 00 8a e8     ld      r4,0(r10)
                          30: R_PPC64_TOC16_LO_DS .toc+0xa8
    34:   10 00 01 f8     std     r0,16(r1)
    38:   a1 ff 21 f8     stdu    r1,-96(r1)
    3c:   00 00 a9 e8     ld      r5,0(r9)
    40:   01 00 00 48     bl      40 <cmdline_proc_show+0x38>
                          40: R_PPC64_REL24       seq_printf
    44:   00 00 00 60     nop
    48:   00 00 60 38     li      r3,0
    4c:   60 00 21 38     addi    r1,r1,96
    50:   10 00 01 e8     ld      r0,16(r1)
    54:   a6 03 08 7c     mtlr    r0
    58:   20 00 80 4e     blr

  Relocation section '.rela.text.cmdline_proc_show' at offset 0x1420 contains 10 entries:
      Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
  0000000000000000  0000005a0000002c R_PPC64_REL64          0000000000000000 .TOC. - 8
  0000000000000008  0000000000000076 R_PPC64_ENTRY                             0
  0000000000000014  000000640000000a R_PPC64_REL24          0000000000000000 _mcount + 0
  000000000000001c  0000001100000032 R_PPC64_TOC16_HA       0000000000000000 .toc + a0
> 0000000000000020  0000001100000032 R_PPC64_TOC16_HA       0000000000000000 .toc + 90
  0000000000000024  0000001100000040 R_PPC64_TOC16_LO_DS    0000000000000000 .toc + a0
> 0000000000000028  0000001100000040 R_PPC64_TOC16_LO_DS    0000000000000000 .toc + 90
  000000000000002c  0000001100000032 R_PPC64_TOC16_HA       0000000000000000 .toc + a8
  0000000000000030  0000001100000040 R_PPC64_TOC16_LO_DS    0000000000000000 .toc + a8
  0000000000000040  000000630000000a R_PPC64_REL24          0000000000000000 seq_printf + 0

  Relocation section '.klp.rela.vmlinux..toc' at offset 0x6afe0 contains 1 entry:
      Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
  00000000000000a0  0000006600000026 R_PPC64_ADDR64         0000000000000000 .klp.sym.vmlinux.saved_command_line,0 + 0

The current function pointer detection code looks like:

static int function_ptr_rela(const struct rela *rela)
{
	const struct rela *rela_toc = toc_rela(rela);

	return (rela_toc && rela_toc->sym->type == STT_FUNC &&
		!rela_toc->sym->parent &&
		rela_toc->addend == (int)rela_toc->sym->sym.st_value &&
		(rela->type == R_X86_64_32S ||
		rela->type == R_PPC64_TOC16_HA ||
		rela->type == R_PPC64_TOC16_LO_DS));
}

For x86_64, if I de-tangle the rela_toc->* checks from the R_X86_64_32S check (effectively reducing the condition to only verify the relocation type on x86), then this architecture passes.

For ppc64le, I believe the expectation that rela_toc->addend == (int)rela_toc->sym->sym.st_value is failing. If I hack in an 8-byte offset to the addend, then the klp-relocation is created once again.

This issue is a Friday brain dump. I don't have PowerPC arch paged into my brain, so I'm wondering if the fact that on RHEL-9, the function symbol is set 8-bytes into section (rather than at the beginning as on RHEL-7) is messing with this addend check.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions