All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rusty Russell <rusty@rustcorp.com.au>
To: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Andrew Honig <ahonig@google.com>, Michal Marek <mmarek@suse.cz>,
	"x86@kernel.org" <x86@kernel.org>, Tejun Heo <tj@kernel.org>,
	Tony Luck <tony.luck@intel.com>,
	Fenghua Yu <fenghua.yu@intel.com>,
	linux-ia64@vger.kernel.org, Kees Cook <keescook@chromium.org>,
	LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 2/2] kallsyms: handle special absolute symbols
Date: Thu, 13 Mar 2014 00:42:10 +0000	[thread overview]
Message-ID: <87y50fuei5.fsf@rustcorp.com.au> (raw)
In-Reply-To: <CAGXu5j+QoHH004usCiCfJU6DPQFnQ2gt3P4GDLS7Gx8Tz_gK+A@mail.gmail.com>

Kees Cook <keescook@chromium.org> writes:
> On Fri, Mar 7, 2014 at 5:00 PM, Kees Cook <keescook@chromium.org> wrote:
>> This forces the entire per_cpu range to be reported as absolute
>> without losing their linker symbol types, when the per_cpu area is
>> 0-based. Without this, the variables are incorrectly shown as relocated
>> under kASLR on x86_64.
>>
>> Several kallsyms output in different boot states for comparison of
>> various symbols:
>>
>> $ 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
>> $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.kaslr2
>> 000000000d400000 D __per_cpu_start
>> 000000000d404000 D gdt_page
>> 000000000d414280 D __per_cpu_end
>> ffffffff8e4001c8 T _stext
>> ffffffff8f2e53c0 D __per_cpu_offset
>> $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.kaslr-fixed
>> 0000000000000000 D __per_cpu_start
>> 0000000000004000 D gdt_page
>> 0000000000014280 D __per_cpu_end
>> ffffffffadc001c8 T _stext
>> ffffffffaeae53c0 D __per_cpu_offset
>>
>> Signed-off-by: Kees Cook <keescook@chromium.org>
>> ---
>> v2:
>>  - only force absolute when per_cpu starts at 0.
>> ---
>>  scripts/kallsyms.c |   20 +++++++++++++++++++-
>>  1 file changed, 19 insertions(+), 1 deletion(-)
>>
>> diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
>> index 08f30ac5b07d..d3f93b8eb277 100644
>> --- a/scripts/kallsyms.c
>> +++ b/scripts/kallsyms.c
>> @@ -34,6 +34,7 @@ struct sym_entry {
>>         unsigned int len;
>>         unsigned int start_pos;
>>         unsigned char *sym;
>> +       int force_absolute;
>>  };
>>
>>  struct addr_range {
>> @@ -51,6 +52,14 @@ static struct addr_range text_ranges[] = {
>>  #define text_range_text     (&text_ranges[0])
>>  #define text_range_inittext (&text_ranges[1])
>>
>> +/*
>> + * Variables in these ranges, when the start is 0 based, will be forced to
>> + * be handled as absolute addresses.
>> + */
>> +static struct addr_range abs_ranges[] = {
>> +       { "__per_cpu_start",    "__per_cpu_end", -1ULL, 0 },
>> +};
>> +
>>  static struct sym_entry *table;
>>  static unsigned int table_size, table_cnt;
>>  static int all_symbols = 0;
>> @@ -165,6 +174,10 @@ static int read_symbol(FILE *in, struct sym_entry *s)
>>         }
>>         strcpy((char *)s->sym + 1, str);
>>         s->sym[0] = stype;
>> +       s->force_absolute = 0;
>> +
>> +       /* Check if we've found special absolute symbol range. */
>> +       check_symbol_range(sym, s->addr, abs_ranges, ARRAY_SIZE(abs_ranges));
>>
>>         return 0;
>>  }
>> @@ -211,6 +224,11 @@ static int symbol_valid(struct sym_entry *s)
>>         if (s->addr < kernel_start_addr)
>>                 return 0;
>>
>> +       /* Force zero-based range special symbols into being absolute. */
>> +       i = symbol_in_range(s, abs_ranges, ARRAY_SIZE(abs_ranges));
>> +       if (i >= 0 && abs_ranges[i].start = 0)
>> +               s->force_absolute = 1;
>
> Rusty, is this 0-detection workable for you? If so, should you or akpm
> carry this series for 3.15?

Damn, sorry, I wrote this patch and seems like I didn't actually send it
out.  No wonder you didn't respond :)

This applies on top of your first cleanup patch:

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

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 3c6224728960..21013e739773 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -51,9 +51,14 @@ static struct addr_range text_ranges[] = {
 #define text_range_text     (&text_ranges[0])
 #define text_range_inittext (&text_ranges[1])
 
+static struct addr_range percpu_range = {
+	"__per_cpu_start", "__per_cpu_end", -1ULL, 0
+};
+
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
 static int all_symbols = 0;
+static int absolute_percpu = 0;
 static char symbol_prefix_char = '\0';
 static unsigned long long kernel_start_addr = 0;
 
@@ -166,6 +171,9 @@ static int read_symbol(FILE *in, struct sym_entry *s)
 	strcpy((char *)s->sym + 1, str);
 	s->sym[0] = stype;
 
+	/* Record if we've found __per_cpu_start/end. */
+	check_symbol_range(sym, s->addr, &percpu_range, 1);
+
 	return 0;
 }
 
@@ -656,6 +664,15 @@ static void sort_symbols(void)
 	qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
 }
 
+static void make_percpus_absolute(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < table_cnt; i++)
+		if (symbol_in_range(&table[i], &percpu_range, 1))
+			table[i].sym[0] = 'A';
+}
+
 int main(int argc, char **argv)
 {
 	if (argc >= 2) {
@@ -663,6 +683,8 @@ int main(int argc, char **argv)
 		for (i = 1; i < argc; i++) {
 			if(strcmp(argv[i], "--all-symbols") = 0)
 				all_symbols = 1;
+			else if (strcmp(argv[i], "--absolute-percpu") = 0)
+				absolute_percpu = 1;
 			else if (strncmp(argv[i], "--symbol-prefix=", 16) = 0) {
 				char *p = &argv[i][16];
 				/* skip quote */
@@ -679,6 +701,8 @@ int main(int argc, char **argv)
 		usage();
 
 	read_map(stdin);
+	if (absolute_percpu)
+		make_percpus_absolute();
 	sort_symbols();
 	optimize_token_table();
 	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()
 		kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
 	fi
 
+	if [ -n "${CONFIG_X86_64}" ]; then
+		kallsymopt="${kallsymopt} --absolute-percpu"
+	fi
+
 	local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
 		      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
 


WARNING: multiple messages have this Message-ID (diff)
From: Rusty Russell <rusty@rustcorp.com.au>
To: Kees Cook <keescook@chromium.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Andrew Honig <ahonig@google.com>, Michal Marek <mmarek@suse.cz>,
	"x86\@kernel.org" <x86@kernel.org>, Tejun Heo <tj@kernel.org>,
	Tony Luck <tony.luck@intel.com>,
	Fenghua Yu <fenghua.yu@intel.com>,
	linux-ia64@vger.kernel.org, Kees Cook <keescook@chromium.org>,
	LKML <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH v2 2/2] kallsyms: handle special absolute symbols
Date: Thu, 13 Mar 2014 11:00:10 +1030	[thread overview]
Message-ID: <87y50fuei5.fsf@rustcorp.com.au> (raw)
In-Reply-To: <CAGXu5j+QoHH004usCiCfJU6DPQFnQ2gt3P4GDLS7Gx8Tz_gK+A@mail.gmail.com>

Kees Cook <keescook@chromium.org> writes:
> On Fri, Mar 7, 2014 at 5:00 PM, Kees Cook <keescook@chromium.org> wrote:
>> This forces the entire per_cpu range to be reported as absolute
>> without losing their linker symbol types, when the per_cpu area is
>> 0-based. Without this, the variables are incorrectly shown as relocated
>> under kASLR on x86_64.
>>
>> Several kallsyms output in different boot states for comparison of
>> various symbols:
>>
>> $ 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
>> $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.kaslr2
>> 000000000d400000 D __per_cpu_start
>> 000000000d404000 D gdt_page
>> 000000000d414280 D __per_cpu_end
>> ffffffff8e4001c8 T _stext
>> ffffffff8f2e53c0 D __per_cpu_offset
>> $ egrep ' (gdt_|_(stext|_per_cpu_))' /root/kallsyms.kaslr-fixed
>> 0000000000000000 D __per_cpu_start
>> 0000000000004000 D gdt_page
>> 0000000000014280 D __per_cpu_end
>> ffffffffadc001c8 T _stext
>> ffffffffaeae53c0 D __per_cpu_offset
>>
>> Signed-off-by: Kees Cook <keescook@chromium.org>
>> ---
>> v2:
>>  - only force absolute when per_cpu starts at 0.
>> ---
>>  scripts/kallsyms.c |   20 +++++++++++++++++++-
>>  1 file changed, 19 insertions(+), 1 deletion(-)
>>
>> diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
>> index 08f30ac5b07d..d3f93b8eb277 100644
>> --- a/scripts/kallsyms.c
>> +++ b/scripts/kallsyms.c
>> @@ -34,6 +34,7 @@ struct sym_entry {
>>         unsigned int len;
>>         unsigned int start_pos;
>>         unsigned char *sym;
>> +       int force_absolute;
>>  };
>>
>>  struct addr_range {
>> @@ -51,6 +52,14 @@ static struct addr_range text_ranges[] = {
>>  #define text_range_text     (&text_ranges[0])
>>  #define text_range_inittext (&text_ranges[1])
>>
>> +/*
>> + * Variables in these ranges, when the start is 0 based, will be forced to
>> + * be handled as absolute addresses.
>> + */
>> +static struct addr_range abs_ranges[] = {
>> +       { "__per_cpu_start",    "__per_cpu_end", -1ULL, 0 },
>> +};
>> +
>>  static struct sym_entry *table;
>>  static unsigned int table_size, table_cnt;
>>  static int all_symbols = 0;
>> @@ -165,6 +174,10 @@ static int read_symbol(FILE *in, struct sym_entry *s)
>>         }
>>         strcpy((char *)s->sym + 1, str);
>>         s->sym[0] = stype;
>> +       s->force_absolute = 0;
>> +
>> +       /* Check if we've found special absolute symbol range. */
>> +       check_symbol_range(sym, s->addr, abs_ranges, ARRAY_SIZE(abs_ranges));
>>
>>         return 0;
>>  }
>> @@ -211,6 +224,11 @@ static int symbol_valid(struct sym_entry *s)
>>         if (s->addr < kernel_start_addr)
>>                 return 0;
>>
>> +       /* Force zero-based range special symbols into being absolute. */
>> +       i = symbol_in_range(s, abs_ranges, ARRAY_SIZE(abs_ranges));
>> +       if (i >= 0 && abs_ranges[i].start == 0)
>> +               s->force_absolute = 1;
>
> Rusty, is this 0-detection workable for you? If so, should you or akpm
> carry this series for 3.15?

Damn, sorry, I wrote this patch and seems like I didn't actually send it
out.  No wonder you didn't respond :)

This applies on top of your first cleanup patch:

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

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 3c6224728960..21013e739773 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -51,9 +51,14 @@ static struct addr_range text_ranges[] = {
 #define text_range_text     (&text_ranges[0])
 #define text_range_inittext (&text_ranges[1])
 
+static struct addr_range percpu_range = {
+	"__per_cpu_start", "__per_cpu_end", -1ULL, 0
+};
+
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
 static int all_symbols = 0;
+static int absolute_percpu = 0;
 static char symbol_prefix_char = '\0';
 static unsigned long long kernel_start_addr = 0;
 
@@ -166,6 +171,9 @@ static int read_symbol(FILE *in, struct sym_entry *s)
 	strcpy((char *)s->sym + 1, str);
 	s->sym[0] = stype;
 
+	/* Record if we've found __per_cpu_start/end. */
+	check_symbol_range(sym, s->addr, &percpu_range, 1);
+
 	return 0;
 }
 
@@ -656,6 +664,15 @@ static void sort_symbols(void)
 	qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
 }
 
+static void make_percpus_absolute(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < table_cnt; i++)
+		if (symbol_in_range(&table[i], &percpu_range, 1))
+			table[i].sym[0] = 'A';
+}
+
 int main(int argc, char **argv)
 {
 	if (argc >= 2) {
@@ -663,6 +683,8 @@ int main(int argc, char **argv)
 		for (i = 1; i < argc; i++) {
 			if(strcmp(argv[i], "--all-symbols") == 0)
 				all_symbols = 1;
+			else if (strcmp(argv[i], "--absolute-percpu") == 0)
+				absolute_percpu = 1;
 			else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
 				char *p = &argv[i][16];
 				/* skip quote */
@@ -679,6 +701,8 @@ int main(int argc, char **argv)
 		usage();
 
 	read_map(stdin);
+	if (absolute_percpu)
+		make_percpus_absolute();
 	sort_symbols();
 	optimize_token_table();
 	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()
 		kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
 	fi
 
+	if [ -n "${CONFIG_X86_64}" ]; then
+		kallsymopt="${kallsymopt} --absolute-percpu"
+	fi
+
 	local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
 		      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
 


  reply	other threads:[~2014-03-13  0:42 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-08  1:00 [PATCH v2 0/2] kallsyms: handle special absolute symbols Kees Cook
2014-03-08  1:00 ` Kees Cook
2014-03-08  1:00 ` [PATCH v2 1/2] kallsyms: generalize address range checking Kees Cook
2014-03-08  1:00   ` Kees Cook
2014-03-08  1:00 ` [PATCH v2 2/2] kallsyms: handle special absolute symbols Kees Cook
2014-03-08  1:00   ` Kees Cook
2014-03-11 21:03   ` Kees Cook
2014-03-11 21:03     ` Kees Cook
2014-03-13  0:30     ` Rusty Russell [this message]
2014-03-13  0:42       ` Rusty Russell
2014-03-13  0:40       ` Kees Cook
2014-03-13  0:40         ` Kees Cook
2014-03-13  3:40         ` Rusty Russell
2014-03-13  3:52           ` Rusty Russell
2014-03-13  6:23           ` Kees Cook
2014-03-13  6:23             ` Kees Cook
2014-03-17  3:36             ` Rusty Russell
2014-03-17  3:48               ` Rusty Russell
2014-03-10 19:06 ` [PATCH v2 0/2] " Andrew Morton
2014-03-10 19:06   ` Andrew Morton
2014-03-10 19:58   ` Kees Cook
2014-03-10 19:58     ` Kees Cook
2014-03-10 20:02     ` Andrew Morton
2014-03-10 20:02       ` Andrew Morton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87y50fuei5.fsf@rustcorp.com.au \
    --to=rusty@rustcorp.com.au \
    --cc=ahonig@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=fenghua.yu@intel.com \
    --cc=keescook@chromium.org \
    --cc=linux-ia64@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mmarek@suse.cz \
    --cc=tj@kernel.org \
    --cc=tony.luck@intel.com \
    --cc=torvalds@linux-foundation.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.