]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 22 Jun 2019 15:32:11 +0000 (17:32 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 22 Jun 2019 15:32:11 +0000 (17:32 +0200)
added patches:
objtool-support-per-function-rodata-sections.patch
tracing-silence-gcc-9-array-bounds-warning.patch

queue-4.19/objtool-support-per-function-rodata-sections.patch [new file with mode: 0644]
queue-4.19/series [new file with mode: 0644]
queue-4.19/tracing-silence-gcc-9-array-bounds-warning.patch [new file with mode: 0644]

diff --git a/queue-4.19/objtool-support-per-function-rodata-sections.patch b/queue-4.19/objtool-support-per-function-rodata-sections.patch
new file mode 100644 (file)
index 0000000..13a56ff
--- /dev/null
@@ -0,0 +1,189 @@
+From 4a60aa05a0634241ce17f957bf9fb5ac1eed6576 Mon Sep 17 00:00:00 2001
+From: Allan Xavier <allan.x.xavier@oracle.com>
+Date: Fri, 7 Sep 2018 08:12:01 -0500
+Subject: objtool: Support per-function rodata sections
+
+From: Allan Xavier <allan.x.xavier@oracle.com>
+
+commit 4a60aa05a0634241ce17f957bf9fb5ac1eed6576 upstream.
+
+Add support for processing switch jump tables in objects with multiple
+.rodata sections, such as those created by '-ffunction-sections' and
+'-fdata-sections'.  Currently, objtool always looks in .rodata for jump
+table information, which results in many "sibling call from callable
+instruction with modified stack frame" warnings with objects compiled
+using those flags.
+
+The fix is comprised of three parts:
+
+1. Flagging all .rodata sections when importing ELF information for
+   easier checking later.
+
+2. Keeping a reference to the section each relocation is from in order
+   to get the list_head for the other relocations in that section.
+
+3. Finding jump tables by following relocations to .rodata sections,
+   rather than always referencing a single global .rodata section.
+
+The patch has been tested without data sections enabled and no
+differences in the resulting orc unwind information were seen.
+
+Note that as objtool adds terminators to end of each .text section the
+unwind information generated between a function+data sections build and
+a normal build aren't directly comparable. Manual inspection suggests
+that objtool is now generating the correct information, or at least
+making more of an effort to do so than it did previously.
+
+Signed-off-by: Allan Xavier <allan.x.xavier@oracle.com>
+Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+Link: https://lkml.kernel.org/r/099bdc375195c490dda04db777ee0b95d566ded1.1536325914.git.jpoimboe@redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ tools/objtool/check.c |   38 ++++++++++++++++++++++++++++++++------
+ tools/objtool/check.h |    4 ++--
+ tools/objtool/elf.c   |    1 +
+ tools/objtool/elf.h   |    3 ++-
+ 4 files changed, 37 insertions(+), 9 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -839,7 +839,7 @@ static int add_switch_table(struct objto
+       struct symbol *pfunc = insn->func->pfunc;
+       unsigned int prev_offset = 0;
+-      list_for_each_entry_from(rela, &file->rodata->rela->rela_list, list) {
++      list_for_each_entry_from(rela, &table->rela_sec->rela_list, list) {
+               if (rela == next_table)
+                       break;
+@@ -929,6 +929,7 @@ static struct rela *find_switch_table(st
+ {
+       struct rela *text_rela, *rodata_rela;
+       struct instruction *orig_insn = insn;
++      struct section *rodata_sec;
+       unsigned long table_offset;
+       /*
+@@ -956,10 +957,13 @@ static struct rela *find_switch_table(st
+               /* look for a relocation which references .rodata */
+               text_rela = find_rela_by_dest_range(insn->sec, insn->offset,
+                                                   insn->len);
+-              if (!text_rela || text_rela->sym != file->rodata->sym)
++              if (!text_rela || text_rela->sym->type != STT_SECTION ||
++                  !text_rela->sym->sec->rodata)
+                       continue;
+               table_offset = text_rela->addend;
++              rodata_sec = text_rela->sym->sec;
++
+               if (text_rela->type == R_X86_64_PC32)
+                       table_offset += 4;
+@@ -967,10 +971,10 @@ static struct rela *find_switch_table(st
+                * Make sure the .rodata address isn't associated with a
+                * symbol.  gcc jump tables are anonymous data.
+                */
+-              if (find_symbol_containing(file->rodata, table_offset))
++              if (find_symbol_containing(rodata_sec, table_offset))
+                       continue;
+-              rodata_rela = find_rela_by_dest(file->rodata, table_offset);
++              rodata_rela = find_rela_by_dest(rodata_sec, table_offset);
+               if (rodata_rela) {
+                       /*
+                        * Use of RIP-relative switch jumps is quite rare, and
+@@ -1055,7 +1059,7 @@ static int add_switch_table_alts(struct
+       struct symbol *func;
+       int ret;
+-      if (!file->rodata || !file->rodata->rela)
++      if (!file->rodata)
+               return 0;
+       for_each_sec(file, sec) {
+@@ -1201,10 +1205,33 @@ static int read_retpoline_hints(struct o
+       return 0;
+ }
++static void mark_rodata(struct objtool_file *file)
++{
++      struct section *sec;
++      bool found = false;
++
++      /*
++       * This searches for the .rodata section or multiple .rodata.func_name
++       * sections if -fdata-sections is being used. The .str.1.1 and .str.1.8
++       * rodata sections are ignored as they don't contain jump tables.
++       */
++      for_each_sec(file, sec) {
++              if (!strncmp(sec->name, ".rodata", 7) &&
++                  !strstr(sec->name, ".str1.")) {
++                      sec->rodata = true;
++                      found = true;
++              }
++      }
++
++      file->rodata = found;
++}
++
+ static int decode_sections(struct objtool_file *file)
+ {
+       int ret;
++      mark_rodata(file);
++
+       ret = decode_instructions(file);
+       if (ret)
+               return ret;
+@@ -2176,7 +2203,6 @@ int check(const char *_objname, bool orc
+       INIT_LIST_HEAD(&file.insn_list);
+       hash_init(file.insn_hash);
+       file.whitelist = find_section_by_name(file.elf, ".discard.func_stack_frame_non_standard");
+-      file.rodata = find_section_by_name(file.elf, ".rodata");
+       file.c_file = find_section_by_name(file.elf, ".comment");
+       file.ignore_unreachables = no_unreachable;
+       file.hints = false;
+--- a/tools/objtool/check.h
++++ b/tools/objtool/check.h
+@@ -60,8 +60,8 @@ struct objtool_file {
+       struct elf *elf;
+       struct list_head insn_list;
+       DECLARE_HASHTABLE(insn_hash, 16);
+-      struct section *rodata, *whitelist;
+-      bool ignore_unreachables, c_file, hints;
++      struct section *whitelist;
++      bool ignore_unreachables, c_file, hints, rodata;
+ };
+ int check(const char *objname, bool orc);
+--- a/tools/objtool/elf.c
++++ b/tools/objtool/elf.c
+@@ -390,6 +390,7 @@ static int read_relas(struct elf *elf)
+                       rela->offset = rela->rela.r_offset;
+                       symndx = GELF_R_SYM(rela->rela.r_info);
+                       rela->sym = find_symbol_by_index(elf, symndx);
++                      rela->rela_sec = sec;
+                       if (!rela->sym) {
+                               WARN("can't find rela entry symbol %d for %s",
+                                    symndx, sec->name);
+--- a/tools/objtool/elf.h
++++ b/tools/objtool/elf.h
+@@ -48,7 +48,7 @@ struct section {
+       char *name;
+       int idx;
+       unsigned int len;
+-      bool changed, text;
++      bool changed, text, rodata;
+ };
+ struct symbol {
+@@ -68,6 +68,7 @@ struct rela {
+       struct list_head list;
+       struct hlist_node hash;
+       GElf_Rela rela;
++      struct section *rela_sec;
+       struct symbol *sym;
+       unsigned int type;
+       unsigned long offset;
diff --git a/queue-4.19/series b/queue-4.19/series
new file mode 100644 (file)
index 0000000..b39ee0d
--- /dev/null
@@ -0,0 +1,2 @@
+tracing-silence-gcc-9-array-bounds-warning.patch
+objtool-support-per-function-rodata-sections.patch
diff --git a/queue-4.19/tracing-silence-gcc-9-array-bounds-warning.patch b/queue-4.19/tracing-silence-gcc-9-array-bounds-warning.patch
new file mode 100644 (file)
index 0000000..626a5f5
--- /dev/null
@@ -0,0 +1,103 @@
+From 0c97bf863efce63d6ab7971dad811601e6171d2f Mon Sep 17 00:00:00 2001
+From: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
+Date: Thu, 23 May 2019 14:45:35 +0200
+Subject: tracing: Silence GCC 9 array bounds warning
+
+From: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
+
+commit 0c97bf863efce63d6ab7971dad811601e6171d2f upstream.
+
+Starting with GCC 9, -Warray-bounds detects cases when memset is called
+starting on a member of a struct but the size to be cleared ends up
+writing over further members.
+
+Such a call happens in the trace code to clear, at once, all members
+after and including `seq` on struct trace_iterator:
+
+    In function 'memset',
+        inlined from 'ftrace_dump' at kernel/trace/trace.c:8914:3:
+    ./include/linux/string.h:344:9: warning: '__builtin_memset' offset
+    [8505, 8560] from the object at 'iter' is out of the bounds of
+    referenced subobject 'seq' with type 'struct trace_seq' at offset
+    4368 [-Warray-bounds]
+      344 |  return __builtin_memset(p, c, size);
+          |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In order to avoid GCC complaining about it, we compute the address
+ourselves by adding the offsetof distance instead of referring
+directly to the member.
+
+Since there are two places doing this clear (trace.c and trace_kdb.c),
+take the chance to move the workaround into a single place in
+the internal header.
+
+Link: http://lkml.kernel.org/r/20190523124535.GA12931@gmail.com
+
+Signed-off-by: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com>
+[ Removed unnecessary parenthesis around "iter" ]
+Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ kernel/trace/trace.c     |    6 +-----
+ kernel/trace/trace.h     |   18 ++++++++++++++++++
+ kernel/trace/trace_kdb.c |    6 +-----
+ 3 files changed, 20 insertions(+), 10 deletions(-)
+
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -8351,12 +8351,8 @@ void ftrace_dump(enum ftrace_dump_mode o
+               cnt++;
+-              /* reset all but tr, trace, and overruns */
+-              memset(&iter.seq, 0,
+-                     sizeof(struct trace_iterator) -
+-                     offsetof(struct trace_iterator, seq));
++              trace_iterator_reset(&iter);
+               iter.iter_flags |= TRACE_FILE_LAT_FMT;
+-              iter.pos = -1;
+               if (trace_find_next_entry_inc(&iter) != NULL) {
+                       int ret;
+--- a/kernel/trace/trace.h
++++ b/kernel/trace/trace.h
+@@ -1895,4 +1895,22 @@ static inline void tracer_hardirqs_off(u
+ extern struct trace_iterator *tracepoint_print_iter;
++/*
++ * Reset the state of the trace_iterator so that it can read consumed data.
++ * Normally, the trace_iterator is used for reading the data when it is not
++ * consumed, and must retain state.
++ */
++static __always_inline void trace_iterator_reset(struct trace_iterator *iter)
++{
++      const size_t offset = offsetof(struct trace_iterator, seq);
++
++      /*
++       * Keep gcc from complaining about overwriting more than just one
++       * member in the structure.
++       */
++      memset((char *)iter + offset, 0, sizeof(struct trace_iterator) - offset);
++
++      iter->pos = -1;
++}
++
+ #endif /* _LINUX_KERNEL_TRACE_H */
+--- a/kernel/trace/trace_kdb.c
++++ b/kernel/trace/trace_kdb.c
+@@ -41,12 +41,8 @@ static void ftrace_dump_buf(int skip_lin
+       kdb_printf("Dumping ftrace buffer:\n");
+-      /* reset all but tr, trace, and overruns */
+-      memset(&iter.seq, 0,
+-                 sizeof(struct trace_iterator) -
+-                 offsetof(struct trace_iterator, seq));
++      trace_iterator_reset(&iter);
+       iter.iter_flags |= TRACE_FILE_LAT_FMT;
+-      iter.pos = -1;
+       if (cpu_file == RING_BUFFER_ALL_CPUS) {
+               for_each_tracing_cpu(cpu) {