Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions kpatch-build/create-diff-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -3240,19 +3240,35 @@ static bool is_expoline(struct kpatch_elf *kelf, char *name)
static int function_ptr_rela(const struct rela *rela, struct kpatch_elf *kelf)
{
const struct rela *rela_toc = toc_rela(rela);
static int entry_offset = -1;
bool funcptr = false;

if (entry_offset < 0) {
char *str = getenv("ENTRY_OFFSET_BYTES");
if (str)
entry_offset = atoi(str);
else
entry_offset = 0;
}

if (rela_toc && rela_toc->sym->type == STT_FUNC && !rela_toc->sym->parent) {
switch (kelf->arch) {
case X86_64:
if (rela_toc->addend == (int)rela_toc->sym->sym.st_value &&
if (rela_toc->addend + entry_offset == (int)rela_toc->sym->sym.st_value &&
rela->type == R_X86_64_32S)
funcptr = true;
break;
case PPC64:
if (rela_toc->addend == (int)rela_toc->sym->sym.st_value &&
(rela->type == R_PPC64_TOC16_HA || rela->type == R_PPC64_TOC16_LO_DS))
if ((rela->type == R_PPC64_TOC16_HA || rela->type == R_PPC64_TOC16_LO_DS) &&
(rela_toc->addend == (int)rela_toc->sym->sym.st_value)) {
funcptr = true;
} else if (rela->type == R_PPC64_ADDR64) {
struct rela *entry;
entry = find_rela_by_offset(rela_toc->sym->sec->rela,
(unsigned int) (rela_toc->addend + rela_toc->sym->sym.st_value));
if (entry && entry->type == R_PPC64_ENTRY)
funcptr = true;
}
break;
case S390:
if (rela->type == R_390_GOTENT)
Expand Down
26 changes: 26 additions & 0 deletions kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,31 @@ find_special_section_data() {
return
}

# Determine if this configuration uses the -fpatchable-function-entry=N[,M]
# compiler flag, for which create-diff-object will need to know any non-zero M
# NOPs value (i.e. to expect an entry point M NOPs instructions inside its
# function section.)
find_entry_offset() {
local entry_offset=0

case "$ARCH" in
"x86_64")
# arch/x86/Makefile: For CONFIG_CALL_PADDING, sets M=CONFIG_FUNCTION_PADDING_BYTES
if [[ -n "$CONFIG_CALL_PADDING" ]]; then
entry_offset="$CONFIG_FUNCTION_PADDING_BYTES"
fi
;;
"ppc64le")
# arch/powerpc/Makefile: N/A
;;
"s390x")
# arch/s390x/Makefile: N/A
;;
esac

export ENTRY_OFFSET_BYTES="$entry_offset"
}

# path of file, relative to dir
# adapted from https://stackoverflow.com/a/24848739
relpath() {
Expand Down Expand Up @@ -1262,6 +1287,7 @@ export KCFLAGS="-I$DATADIR/patch -ffunction-sections -fdata-sections \

echo "Reading special section data"
find_special_section_data
find_entry_offset

if [[ $DEBUG -ge 4 ]]; then
export KPATCH_GCC_DEBUG=1
Expand Down
17 changes: 17 additions & 0 deletions test/integration/rhel-7.9/func-ptr-klp_reloc.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--- src.old/fs/proc/uptime.c 2024-06-13 03:19:08.000000000 -0400
+++ src/fs/proc/uptime.c 2025-03-25 09:08:38.206910364 -0400
@@ -24,11 +24,12 @@ static int uptime_proc_show(struct seq_f
nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC;
idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
idle.tv_nsec = rem;
- seq_printf(m, "%lu.%02lu %lu.%02lu\n",
+ seq_printf(m, "%lu.%02lu %lu.%02lu uptime_proc_show=%p\n",
(unsigned long) uptime.tv_sec,
(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
(unsigned long) idle.tv_sec,
- (idle.tv_nsec / (NSEC_PER_SEC / 100)));
+ (idle.tv_nsec / (NSEC_PER_SEC / 100)),
+ uptime_proc_show);
return 0;
}

9 changes: 9 additions & 0 deletions test/integration/rhel-7.9/func-ptr-klp_reloc.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

kpatch_value=$(cat /proc/uptime | grep -o 'uptime_proc_show=.*' | awk -F= '{print $2}')
kernel_value=$(awk '$NF=="uptime_proc_show" { print $1 }' /proc/kallsyms)

if [[ "$kpatch_value" != "$kernel_value" ]]; then
echo "kpatch_value($kpatch_value) != kernel_value($kernel_value)"
exit 1
fi
17 changes: 17 additions & 0 deletions test/integration/rhel-8.10/func-ptr-klp_reloc.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--- src.old/fs/proc/uptime.c 2025-03-20 06:57:19.000000000 -0400
+++ src/fs/proc/uptime.c 2025-03-25 09:35:50.847697946 -0400
@@ -25,11 +25,12 @@ static int uptime_proc_show(struct seq_f

idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
idle.tv_nsec = rem;
- seq_printf(m, "%lu.%02lu %lu.%02lu\n",
+ seq_printf(m, "%lu.%02lu %lu.%02lu uptime_proc_show=%pK\n",
(unsigned long) uptime.tv_sec,
(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
(unsigned long) idle.tv_sec,
- (idle.tv_nsec / (NSEC_PER_SEC / 100)));
+ (idle.tv_nsec / (NSEC_PER_SEC / 100)),
+ uptime_proc_show);
return 0;
}

9 changes: 9 additions & 0 deletions test/integration/rhel-8.10/func-ptr-klp_reloc.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

kpatch_value=$(cat /proc/uptime | grep -o 'uptime_proc_show=.*' | awk -F= '{print $2}')
kernel_value=$(awk '$NF=="uptime_proc_show" { print $1 }' /proc/kallsyms)

if [[ "$kpatch_value" != "$kernel_value" ]]; then
echo "kpatch_value($kpatch_value) != kernel_value($kernel_value)"
exit 1
fi
17 changes: 17 additions & 0 deletions test/integration/rhel-9.5/func-ptr-klp_reloc.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--- src.old/fs/proc/uptime.c 2025-03-25 09:35:31.468574086 -0400
+++ src/fs/proc/uptime.c 2025-03-25 09:35:46.848570153 -0400
@@ -29,11 +29,12 @@ static int uptime_proc_show(struct seq_f

idle.tv_sec = div_u64_rem(idle_nsec, NSEC_PER_SEC, &rem);
idle.tv_nsec = rem;
- seq_printf(m, "%lu.%02lu %lu.%02lu\n",
+ seq_printf(m, "%lu.%02lu %lu.%02lu uptime_proc_show=%pK\n",
(unsigned long) uptime.tv_sec,
(uptime.tv_nsec / (NSEC_PER_SEC / 100)),
(unsigned long) idle.tv_sec,
- (idle.tv_nsec / (NSEC_PER_SEC / 100)));
+ (idle.tv_nsec / (NSEC_PER_SEC / 100)),
+ uptime_proc_show);
return 0;
}

9 changes: 9 additions & 0 deletions test/integration/rhel-9.5/func-ptr-klp_reloc.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

kpatch_value=$(cat /proc/uptime | grep -o 'uptime_proc_show=.*' | awk -F= '{print $2}')
kernel_value=$(awk '$NF=="uptime_proc_show" { print $1 }' /proc/kallsyms)

if [[ "$kpatch_value" != "$kernel_value" ]]; then
echo "kpatch_value($kpatch_value) != kernel_value($kernel_value)"
exit 1
fi