diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2014-03-16 23:35:46 -0400 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2014-03-17 00:25:27 -0400 |
| commit | c6bda7c988a57958108741cde9b1f12e9727a938 (patch) | |
| tree | 70d2e0c3806467b6689617a9cf1a6e472d9d29fa /scripts | |
| parent | 78eb71594b3265f3cfe871480235be158feebd0f (diff) | |
kallsyms: fix percpu vars on x86-64 with relocation.
x86-64 has a problem: per-cpu variables are actually represented by
their absolute offsets within the per-cpu area, but the symbols are
not emitted as absolute. Thus kallsyms naively creates them as offsets
from _text, meaning their values change if the kernel is relocated
(especially noticeable with CONFIG_RANDOMIZE_BASE):
$ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.nokaslr
0000000000000000 D __per_cpu_start
0000000000004000 D gdt_page
0000000000014280 D __per_cpu_end
ffffffff810001c8 T _stext
ffffffff81ee53c0 D __per_cpu_offset
$ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.kaslr1
000000001f200000 D __per_cpu_start
000000001f204000 D gdt_page
000000001f214280 D __per_cpu_end
ffffffffa02001c8 T _stext
ffffffffa10e53c0 D __per_cpu_offset
Making them absolute symbols is the Right Thing, but requires fixes to
the relocs tool. So for the moment, we add a --absolute-percpu option
which makes them absolute from a kallsyms perspective:
$ egrep ' (gdt_|_(stext|_per_cpu_))' /proc/kallsyms # no KASLR
0000000000000000 A __per_cpu_start
000000000000a000 A gdt_page
0000000000013040 A __per_cpu_end
ffffffff802001c8 T _stext
ffffffff8099b180 D __per_cpu_offset
ffffffff809a3000 D __per_cpu_load
$ egrep ' (gdt_|_(stext|_per_cpu_))' /proc/kallsyms # With KASLR
0000000000000000 A __per_cpu_start
000000000000a000 A gdt_page
0000000000013040 A __per_cpu_end
ffffffff89c001c8 T _stext
ffffffff8a39d180 D __per_cpu_offset
ffffffff8a3a5000 D __per_cpu_load
Based-on-the-original-screenplay-by: Andy Honig <ahonig@google.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Kees Cook <keescook@chromium.org>
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/kallsyms.c | 21 | ||||
| -rw-r--r-- | scripts/link-vmlinux.sh | 4 |
2 files changed, 25 insertions, 0 deletions
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 3df15f5e7c55..1237dd7fb4ca 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c | |||
| @@ -51,9 +51,14 @@ static struct addr_range text_ranges[] = { | |||
| 51 | #define text_range_text (&text_ranges[0]) | 51 | #define text_range_text (&text_ranges[0]) |
| 52 | #define text_range_inittext (&text_ranges[1]) | 52 | #define text_range_inittext (&text_ranges[1]) |
| 53 | 53 | ||
| 54 | static struct addr_range percpu_range = { | ||
| 55 | "__per_cpu_start", "__per_cpu_end", -1ULL, 0 | ||
| 56 | }; | ||
| 57 | |||
| 54 | static struct sym_entry *table; | 58 | static struct sym_entry *table; |
| 55 | static unsigned int table_size, table_cnt; | 59 | static unsigned int table_size, table_cnt; |
| 56 | static int all_symbols = 0; | 60 | static int all_symbols = 0; |
| 61 | static int absolute_percpu = 0; | ||
| 57 | static char symbol_prefix_char = '\0'; | 62 | static char symbol_prefix_char = '\0'; |
| 58 | static unsigned long long kernel_start_addr = 0; | 63 | static unsigned long long kernel_start_addr = 0; |
| 59 | 64 | ||
| @@ -166,6 +171,9 @@ static int read_symbol(FILE *in, struct sym_entry *s) | |||
| 166 | strcpy((char *)s->sym + 1, str); | 171 | strcpy((char *)s->sym + 1, str); |
| 167 | s->sym[0] = stype; | 172 | s->sym[0] = stype; |
| 168 | 173 | ||
| 174 | /* Record if we've found __per_cpu_start/end. */ | ||
| 175 | check_symbol_range(sym, s->addr, &percpu_range, 1); | ||
| 176 | |||
| 169 | return 0; | 177 | return 0; |
| 170 | } | 178 | } |
| 171 | 179 | ||
| @@ -657,6 +665,15 @@ static void sort_symbols(void) | |||
| 657 | qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); | 665 | qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); |
| 658 | } | 666 | } |
| 659 | 667 | ||
| 668 | static void make_percpus_absolute(void) | ||
| 669 | { | ||
| 670 | unsigned int i; | ||
| 671 | |||
| 672 | for (i = 0; i < table_cnt; i++) | ||
| 673 | if (symbol_in_range(&table[i], &percpu_range, 1)) | ||
| 674 | table[i].sym[0] = 'A'; | ||
| 675 | } | ||
| 676 | |||
| 660 | int main(int argc, char **argv) | 677 | int main(int argc, char **argv) |
| 661 | { | 678 | { |
| 662 | if (argc >= 2) { | 679 | if (argc >= 2) { |
| @@ -664,6 +681,8 @@ int main(int argc, char **argv) | |||
| 664 | for (i = 1; i < argc; i++) { | 681 | for (i = 1; i < argc; i++) { |
| 665 | if(strcmp(argv[i], "--all-symbols") == 0) | 682 | if(strcmp(argv[i], "--all-symbols") == 0) |
| 666 | all_symbols = 1; | 683 | all_symbols = 1; |
| 684 | else if (strcmp(argv[i], "--absolute-percpu") == 0) | ||
| 685 | absolute_percpu = 1; | ||
| 667 | else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { | 686 | else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { |
| 668 | char *p = &argv[i][16]; | 687 | char *p = &argv[i][16]; |
| 669 | /* skip quote */ | 688 | /* skip quote */ |
| @@ -680,6 +699,8 @@ int main(int argc, char **argv) | |||
| 680 | usage(); | 699 | usage(); |
| 681 | 700 | ||
| 682 | read_map(stdin); | 701 | read_map(stdin); |
| 702 | if (absolute_percpu) | ||
| 703 | make_percpus_absolute(); | ||
| 683 | sort_symbols(); | 704 | sort_symbols(); |
| 684 | optimize_token_table(); | 705 | optimize_token_table(); |
| 685 | write_src(); | 706 | write_src(); |
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index 2dcb37736d84..86a4fe75f453 100644 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh | |||
| @@ -86,6 +86,10 @@ kallsyms() | |||
| 86 | kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET" | 86 | kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET" |
| 87 | fi | 87 | fi |
| 88 | 88 | ||
| 89 | if [ -n "${CONFIG_X86_64}" ]; then | ||
| 90 | kallsymopt="${kallsymopt} --absolute-percpu" | ||
| 91 | fi | ||
| 92 | |||
| 89 | local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ | 93 | local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ |
| 90 | ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" | 94 | ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" |
| 91 | 95 | ||
