Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
This commit is still dirty, and is jumbling cut & pasted referring
to dynup#1010 and dynup#1203.
  • Loading branch information
keiya-nobuta committed Oct 6, 2021
1 parent 6ba8551 commit d3ed70b
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 25 deletions.
1 change: 1 addition & 0 deletions kpatch-build/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ GCC_PLUGINS_DIR := $(shell gcc -print-file-name=plugin)
PLUGIN_CFLAGS := $(filter-out -Wconversion, $(CFLAGS))
PLUGIN_CFLAGS += -shared -I$(GCC_PLUGINS_DIR)/include \
-Igcc-plugins -fPIC -fno-rtti -O2 -Wall
else ifeq ($(ARCH),aarch64)
else
$(error Unsupported architecture ${ARCH}, check https://github.com/dynup/kpatch/#supported-architectures)
endif
Expand Down
71 changes: 54 additions & 17 deletions kpatch-build/create-diff-object.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@

#ifdef __powerpc64__
#define ABSOLUTE_RELA_TYPE R_PPC64_ADDR64
#elif __aarch64__
#define ABSOLUTE_RELA_TYPE R_AARCH64_ABS64
#else
#define ABSOLUTE_RELA_TYPE R_X86_64_64
#endif
Expand Down Expand Up @@ -367,6 +369,15 @@ static bool is_special_static(struct symbol *sym)
return false;
}

#ifdef __aarch64__
static bool is_aarch64_mapping_symbol(struct symbol *sym)
{
return (sym->name && sym->name[0] == '$' &&
sym->type == STT_NOTYPE &&
sym->bind == STB_LOCAL);
}
#endif

static bool has_digit_tail(char *tail)
{
if (*tail != '.')
Expand Down Expand Up @@ -563,6 +574,12 @@ static void kpatch_compare_correlated_section(struct section *sec)
goto out;
}

if (!strcmp(sec->name, ".rela__patchable_function_entries") ||
!strcmp(sec->name, "__patchable_function_entries")) {
sec->status = SAME;
goto out;
}

if (sec1->sh.sh_size != sec2->sh.sh_size ||
sec1->data->d_size != sec2->data->d_size) {
sec->status = CHANGED;
Expand Down Expand Up @@ -1033,6 +1050,10 @@ static void kpatch_correlate_symbols(struct list_head *symlist_orig,
sym_orig->sec->twin != sym_patched->sec)
continue;

#ifdef __aarch64__
if (is_aarch64_mapping_symbol(sym_orig))
continue;
#endif
kpatch_correlate_symbol(sym_orig, sym_patched);
break;
}
Expand Down Expand Up @@ -1536,7 +1557,7 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
continue;
}

#ifdef __powerpc64__
#if defined(__powerpc64__) || defined(__aarch64__)
add_off = 0;
#else
if (rela->type == R_X86_64_PC32 ||
Expand Down Expand Up @@ -1568,7 +1589,11 @@ static void kpatch_replace_sections_syms(struct kpatch_elf *kelf)
end = sym->sym.st_value + sym->sym.st_size;

if (!is_text_section(sym->sec) &&
#if defined(__x86_64__)
rela->type == R_X86_64_32S &&
#elif defined(__aarch64__)
rela->type == R_AARCH64_ABS64 &&
#endif
rela->addend == (long)sym->sec->sh.sh_size &&
end == (long)sym->sec->sh.sh_size) {

Expand Down Expand Up @@ -1766,6 +1791,7 @@ static void kpatch_include_standard_elements(struct kpatch_elf *kelf)
!strcmp(sec->name, ".symtab") ||
!strcmp(sec->name, ".toc") ||
!strcmp(sec->name, ".rodata") ||
!strcmp(sec->name, ".rodata.str") ||
(!strncmp(sec->name, ".rodata.", 8) &&
strstr(sec->name, ".str1."))) {
kpatch_include_section(sec);
Expand Down Expand Up @@ -2044,35 +2070,36 @@ static int parainstructions_group_size(struct kpatch_elf *kelf, int offset)
return size;
}

static int altinstructions_group_size(struct kpatch_elf *kelf, int offset)
static int smp_locks_group_size(struct kpatch_elf *kelf, int offset)
{
return 4;
}

static int static_call_sites_group_size(struct kpatch_elf *kelf, int offset)
{
static int size = 0;
char *str;

if (!size) {
str = getenv("ALT_STRUCT_SIZE");
str = getenv("STATIC_CALL_STRUCT_SIZE");
if (!str)
ERROR("ALT_STRUCT_SIZE not set");
ERROR("STATIC_CALL_STRUCT_SIZE not set");
size = atoi(str);
}

return size;
}

static int smp_locks_group_size(struct kpatch_elf *kelf, int offset)
{
return 4;
}

static int static_call_sites_group_size(struct kpatch_elf *kelf, int offset)
#endif
#if defined(__s390__) || defined(__x86_64__) || defined(__aarch64__)
static int altinstructions_group_size(struct kpatch_elf *kelf, int offset)
{
static int size = 0;
char *str;

if (!size) {
str = getenv("STATIC_CALL_STRUCT_SIZE");
str = getenv("ALT_STRUCT_SIZE");
if (!str)
ERROR("STATIC_CALL_STRUCT_SIZE not set");
ERROR("ALT_STRUCT_SIZE not set");
size = atoi(str);
}

Expand Down Expand Up @@ -2216,6 +2243,12 @@ static struct special_section special_sections[] = {
.name = "__barrier_nospec_fixup",
.group_size = fixup_barrier_nospec_group_size,
},
#endif
#ifdef __aarch64__
{
.name = ".altinstructions",
.group_size = altinstructions_group_size,
},
#endif
{},
};
Expand Down Expand Up @@ -3404,7 +3437,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
int nr, index;
struct section *sec, *relasec;
struct symbol *sym;
struct rela *rela, *mcount_rela;
struct rela *mcount_rela;
void **funcs;
unsigned long insn_offset;

Expand All @@ -3415,7 +3448,7 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
nr++;

/* create text/rela section pair */
sec = create_section_pair(kelf, "__mcount_loc", sizeof(void*), nr);
sec = create_section_pair(kelf, MCOUNT_SECTION_NAME, sizeof(void*), nr);
relasec = sec->rela;

/* populate sections */
Expand All @@ -3430,7 +3463,8 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
continue;
}

#ifdef __x86_64__
#if defined(__x86_64__)
struct rela *rela;

rela = list_first_entry(&sym->sec->rela->relas, struct rela, list);

Expand Down Expand Up @@ -3473,8 +3507,9 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)
rela->type = R_X86_64_PC32;
}

#else /* __powerpc64__ */
#elif defined(__powerpc64__)
{
struct rela *rela;
bool found = false;

list_for_each_entry(rela, &sym->sec->rela->relas, list)
Expand All @@ -3488,6 +3523,8 @@ static void kpatch_create_mcount_sections(struct kpatch_elf *kelf)

insn_offset = rela->offset;
}
#else
insn_offset = sym->sym.st_value;
#endif
/*
* 'rela' points to the mcount/fentry call.
Expand Down
11 changes: 7 additions & 4 deletions kpatch-build/kpatch-build
Original file line number Diff line number Diff line change
Expand Up @@ -376,11 +376,12 @@ find_special_section_data() {
return
fi

[[ "$CONFIG_PARAVIRT" -eq 0 ]] && AWK_OPTIONS="-vskip_p=1"
[[ "$CONFIG_PARAVIRT" -eq 0 || "$ARCH" == "aarch64" ]] && AWK_OPTIONS="-vskip_p=1"
[[ "$CONFIG_UNWINDER_ORC" -eq 0 ]] && AWK_OPTIONS="$AWK_OPTIONS -vskip_o=1"
[[ "$CONFIG_JUMP_LABEL" -eq 0 ]] && AWK_OPTIONS="$AWK_OPTIONS -vskip_j=1"
[[ "$CONFIG_PRINTK_INDEX" -eq 0 ]] && AWK_OPTIONS="$AWK_OPTIONS -vskip_i=1"
! kernel_version_gte 5.10.0 && AWK_OPTIONS="$AWK_OPTIONS -vskip_s=1"
(! kernel_version_gte 5.10.0 || [[ "CONFIG_HAVE_STATIC_CALL" -eq 0 ]]) \
&& AWK_OPTIONS="$AWK_OPTIONS -vskip_s=1"

# If $AWK_OPTIONS are blank gawk would treat "" as a blank script
# shellcheck disable=SC2086
Expand Down Expand Up @@ -426,11 +427,12 @@ find_special_section_data() {
[[ -z "$ALT_STRUCT_SIZE" ]] && die "can't find special struct alt_instr size"
[[ -z "$BUG_STRUCT_SIZE" ]] && die "can't find special struct bug_entry size"
[[ -z "$EX_STRUCT_SIZE" ]] && die "can't find special struct paravirt_patch_site size"
[[ -z "$PARA_STRUCT_SIZE" && "$CONFIG_PARAVIRT" -ne 0 ]] && die "can't find special struct paravirt_patch_site size"
[[ -z "$PARA_STRUCT_SIZE" && "$CONFIG_PARAVIRT" -ne 0 && "$ARCH" != "aarch64" ]] \
&& die "can't find special struct paravirt_patch_site size"
[[ -z "$ORC_STRUCT_SIZE" && "$CONFIG_UNWINDER_ORC" -ne 0 ]] && die "can't find special struct orc_entry size"
[[ -z "$JUMP_STRUCT_SIZE" && "$CONFIG_JUMP_LABEL" -ne 0 ]] && die "can't find special struct jump_entry size"
[[ -z "$PRINTK_INDEX_STRUCT_SIZE" && "$CONFIG_PRINTK_INDEX" -ne 0 ]] && die "can't find special struct pi_entry size"
[[ -z "$STATIC_CALL_STRUCT_SIZE" ]] && kernel_version_gte 5.10.0 && die "can't find special struct static_call_site size"
[[ -z "$STATIC_CALL_STRUCT_SIZE" && "$CONFIG_HAVE_STATIC_CALL" -ne 0 ]] && kernel_version_gte 5.10.0 && die "can't find special struct static_call_site size"

return
}
Expand Down Expand Up @@ -869,6 +871,7 @@ grep -q "CONFIG_JUMP_LABEL=y" "$CONFIGFILE" && CONFIG_JUMP_LABEL=1
grep -q "CONFIG_MODVERSIONS=y" "$CONFIGFILE" && CONFIG_MODVERSIONS=1
grep -q "CONFIG_CC_IS_CLANG=y" "$CONFIGFILE" && CONFIG_CC_IS_CLANG=1
grep -q "CONFIG_LD_IS_LLD=y" "$CONFIGFILE" && CONFIG_LD_IS_LLD=1
grep -q "CONFIG_HAVE_STATIC_CALL=y" "$CONFIGFILE" && CONFIG_HAVE_STATIC_CALL=1

# unsupported kernel option checking
grep -q "CONFIG_DEBUG_INFO_SPLIT=y" "$CONFIGFILE" && die "kernel option 'CONFIG_DEBUG_INFO_SPLIT' not supported"
Expand Down
58 changes: 54 additions & 4 deletions kpatch-build/kpatch-elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,23 @@ int offset_of_string(struct list_head *list, char *name)
return index;
}

/*
* Check if the symbol name contains LC or L1^B.
*
* On s390x,
* .L1^B19 -> .rodata.str (bug_table)
* .LC0 -> .rodata.str1.2
*
* In these cases, return true and rela->string should point to
* rela->sym->sec->data->d_buf + value of the associated symbol.
*/
static bool lc_string(struct rela *rela) {
if (!strncmp(rela->sym->name, ".LC", 3) || !strncmp(rela->sym->name, ".L1", 3))
return true;
else
return false;
}

void kpatch_create_rela_list(struct kpatch_elf *kelf, struct section *sec)
{
int index = 0, skip = 0;
Expand Down Expand Up @@ -193,7 +210,10 @@ void kpatch_create_rela_list(struct kpatch_elf *kelf, struct section *sec)
ERROR("could not find rela entry symbol\n");
if (rela->sym->sec &&
(rela->sym->sec->sh.sh_flags & SHF_STRINGS)) {
rela->string = rela->sym->sec->data->d_buf + rela->addend;
if (lc_string(rela))
rela->string = rela->sym->sec->data->d_buf + rela->sym->sym.st_value;
else
rela->string = rela->sym->sec->data->d_buf + rela->addend;
if (!rela->string)
ERROR("could not lookup rela string for %s+%ld",
rela->sym->name, rela->addend);
Expand Down Expand Up @@ -317,22 +337,37 @@ void kpatch_create_symbol_list(struct kpatch_elf *kelf)

}

#if !defined(__powerpc64__) && !defined(__x86_64__)
static struct section *kpatch_find_profiling_section(struct list_head *seclist)
{
struct section *sec;

list_for_each_entry(sec, seclist, list) {
if (!strcmp(sec->name, MCOUNT_SECTION_NAME))
return sec;
}
return NULL;
}
#endif

/* Check which functions have fentry/mcount calls; save this info for later use. */
static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
{
struct symbol *sym;
struct rela *rela;

list_for_each_entry(sym, &kelf->symbols, list) {
if (sym->type != STT_FUNC || !sym->sec || !sym->sec->rela)
continue;
#ifdef __powerpc64__
#if defined(__powerpc64__)
struct rela *rela;
list_for_each_entry(rela, &sym->sec->rela->relas, list) {
if (!strcmp(rela->sym->name, "_mcount")) {
sym->has_func_profiling = 1;
break;
}
}
#else
#elif defined(__x86_64__)
struct rela *rela;
rela = list_first_entry(&sym->sec->rela->relas, struct rela,
list);
if ((rela->type != R_X86_64_NONE &&
Expand All @@ -342,6 +377,21 @@ static void kpatch_find_func_profiling_calls(struct kpatch_elf *kelf)
continue;

sym->has_func_profiling = 1;
#else
struct section *prof_sec;

prof_sec = kpatch_find_profiling_section(&kelf->sections);
if (!prof_sec)
break;

struct rela *rela;
list_for_each_entry(rela, &prof_sec->rela->relas, list) {
if (!strncmp(rela->sym->name, ".text.", 6) &&
!strcmp(rela->sym->name + 6, sym->name)) {
sym->has_func_profiling = 1;
break;
}
}
#endif
}
}
Expand Down
6 changes: 6 additions & 0 deletions kpatch-build/kpatch-elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
#define SHF_RELA_LIVEPATCH 0x00100000
#define SHN_LIVEPATCH 0xff20

#ifdef __aarch64__
#define MCOUNT_SECTION_NAME "__patchable_function_entries"
#else
#define MCOUN_SECTION_NAME "__mcount_loc"
#endif

/*******************
* Data structures
* ****************/
Expand Down

0 comments on commit d3ed70b

Please sign in to comment.