]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Jun 2022 11:39:36 +0000 (13:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 6 Jun 2022 11:39:36 +0000 (13:39 +0200)
added patches:
objtool-fix-objtool-regression-on-x32-systems.patch
objtool-fix-symbol-creation.patch

queue-5.18/objtool-fix-objtool-regression-on-x32-systems.patch [new file with mode: 0644]
queue-5.18/objtool-fix-symbol-creation.patch [new file with mode: 0644]
queue-5.18/series

diff --git a/queue-5.18/objtool-fix-objtool-regression-on-x32-systems.patch b/queue-5.18/objtool-fix-objtool-regression-on-x32-systems.patch
new file mode 100644 (file)
index 0000000..fb90317
--- /dev/null
@@ -0,0 +1,101 @@
+From 22682a07acc308ef78681572e19502ce8893c4d4 Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Mon, 16 May 2022 11:06:36 -0400
+Subject: objtool: Fix objtool regression on x32 systems
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 22682a07acc308ef78681572e19502ce8893c4d4 upstream.
+
+Commit c087c6e7b551 ("objtool: Fix type of reloc::addend") failed to
+appreciate cross building from ILP32 hosts, where 'int' == 'long' and
+the issue persists.
+
+As such, use s64/int64_t/Elf64_Sxword for this field and suffer the
+pain that is ISO C99 printf formats for it.
+
+Fixes: c087c6e7b551 ("objtool: Fix type of reloc::addend")
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+[peterz: reword changelog, s/long long/s64/]
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Cc: <stable@vger.kernel.org>
+Link: https://lkml.kernel.org/r/alpine.LRH.2.02.2205161041260.11556@file01.intranet.prod.int.rdu2.redhat.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/objtool/check.c               |    9 +++++----
+ tools/objtool/elf.c                 |    2 +-
+ tools/objtool/include/objtool/elf.h |    4 ++--
+ 3 files changed, 8 insertions(+), 7 deletions(-)
+
+--- a/tools/objtool/check.c
++++ b/tools/objtool/check.c
+@@ -5,6 +5,7 @@
+ #include <string.h>
+ #include <stdlib.h>
++#include <inttypes.h>
+ #include <sys/mman.h>
+ #include <arch/elf.h>
+@@ -560,12 +561,12 @@ static int add_dead_ends(struct objtool_
+               else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
+                       insn = find_last_insn(file, reloc->sym->sec);
+                       if (!insn) {
+-                              WARN("can't find unreachable insn at %s+0x%lx",
++                              WARN("can't find unreachable insn at %s+0x%" PRIx64,
+                                    reloc->sym->sec->name, reloc->addend);
+                               return -1;
+                       }
+               } else {
+-                      WARN("can't find unreachable insn at %s+0x%lx",
++                      WARN("can't find unreachable insn at %s+0x%" PRIx64,
+                            reloc->sym->sec->name, reloc->addend);
+                       return -1;
+               }
+@@ -595,12 +596,12 @@ reachable:
+               else if (reloc->addend == reloc->sym->sec->sh.sh_size) {
+                       insn = find_last_insn(file, reloc->sym->sec);
+                       if (!insn) {
+-                              WARN("can't find reachable insn at %s+0x%lx",
++                              WARN("can't find reachable insn at %s+0x%" PRIx64,
+                                    reloc->sym->sec->name, reloc->addend);
+                               return -1;
+                       }
+               } else {
+-                      WARN("can't find reachable insn at %s+0x%lx",
++                      WARN("can't find reachable insn at %s+0x%" PRIx64,
+                            reloc->sym->sec->name, reloc->addend);
+                       return -1;
+               }
+--- a/tools/objtool/elf.c
++++ b/tools/objtool/elf.c
+@@ -546,7 +546,7 @@ static struct section *elf_create_reloc_
+                                               int reltype);
+ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
+-                unsigned int type, struct symbol *sym, long addend)
++                unsigned int type, struct symbol *sym, s64 addend)
+ {
+       struct reloc *reloc;
+--- a/tools/objtool/include/objtool/elf.h
++++ b/tools/objtool/include/objtool/elf.h
+@@ -73,7 +73,7 @@ struct reloc {
+       struct symbol *sym;
+       unsigned long offset;
+       unsigned int type;
+-      long addend;
++      s64 addend;
+       int idx;
+       bool jump_table_start;
+ };
+@@ -135,7 +135,7 @@ struct elf *elf_open_read(const char *na
+ struct section *elf_create_section(struct elf *elf, const char *name, unsigned int sh_flags, size_t entsize, int nr);
+ int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
+-                unsigned int type, struct symbol *sym, long addend);
++                unsigned int type, struct symbol *sym, s64 addend);
+ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
+                         unsigned long offset, unsigned int type,
+                         struct section *insn_sec, unsigned long insn_off);
diff --git a/queue-5.18/objtool-fix-symbol-creation.patch b/queue-5.18/objtool-fix-symbol-creation.patch
new file mode 100644 (file)
index 0000000..011f784
--- /dev/null
@@ -0,0 +1,348 @@
+From ead165fa1042247b033afad7be4be9b815d04ade Mon Sep 17 00:00:00 2001
+From: Peter Zijlstra <peterz@infradead.org>
+Date: Tue, 17 May 2022 17:42:04 +0200
+Subject: objtool: Fix symbol creation
+
+From: Peter Zijlstra <peterz@infradead.org>
+
+commit ead165fa1042247b033afad7be4be9b815d04ade upstream.
+
+Nathan reported objtool failing with the following messages:
+
+  warning: objtool: no non-local symbols !?
+  warning: objtool: gelf_update_symshndx: invalid section index
+
+The problem is due to commit 4abff6d48dbc ("objtool: Fix code relocs
+vs weak symbols") failing to consider the case where an object would
+have no non-local symbols.
+
+The problem that commit tries to address is adding a STB_LOCAL symbol
+to the symbol table in light of the ELF spec's requirement that:
+
+  In each symbol table, all symbols with STB_LOCAL binding preced the
+  weak and global symbols.  As ``Sections'' above describes, a symbol
+  table section's sh_info section header member holds the symbol table
+  index for the first non-local symbol.
+
+The approach taken is to find this first non-local symbol, move that
+to the end and then re-use the freed spot to insert a new local symbol
+and increment sh_info.
+
+Except it never considered the case of object files without global
+symbols and got a whole bunch of details wrong -- so many in fact that
+it is a wonder it ever worked :/
+
+Specifically:
+
+ - It failed to re-hash the symbol on the new index, so a subsequent
+   find_symbol_by_index() would not find it at the new location and a
+   query for the old location would now return a non-deterministic
+   choice between the old and new symbol.
+
+ - It failed to appreciate that the GElf wrappers are not a valid disk
+   format (it works because GElf is basically Elf64 and we only
+   support x86_64 atm.)
+
+ - It failed to fully appreciate how horrible the libelf API really is
+   and got the gelf_update_symshndx() call pretty much completely
+   wrong; with the direct consequence that if inserting a second
+   STB_LOCAL symbol would require moving the same STB_GLOBAL symbol
+   again it would completely come unstuck.
+
+Write a new elf_update_symbol() function that wraps all the magic
+required to update or create a new symbol at a given index.
+
+Specifically, gelf_update_sym*() require an @ndx argument that is
+relative to the @data argument; this means you have to manually
+iterate the section data descriptor list and update @ndx.
+
+Fixes: 4abff6d48dbc ("objtool: Fix code relocs vs weak symbols")
+Reported-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Signed-off-by: Borislav Petkov <bp@suse.de>
+Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
+Tested-by: Nathan Chancellor <nathan@kernel.org>
+Cc: <stable@vger.kernel.org>
+Link: https://lkml.kernel.org/r/YoPCTEYjoPqE4ZxB@hirez.programming.kicks-ass.net
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/objtool/elf.c |  198 +++++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 129 insertions(+), 69 deletions(-)
+
+--- a/tools/objtool/elf.c
++++ b/tools/objtool/elf.c
+@@ -374,6 +374,9 @@ static void elf_add_symbol(struct elf *e
+       struct list_head *entry;
+       struct rb_node *pnode;
++      INIT_LIST_HEAD(&sym->pv_target);
++      sym->alias = sym;
++
+       sym->type = GELF_ST_TYPE(sym->sym.st_info);
+       sym->bind = GELF_ST_BIND(sym->sym.st_info);
+@@ -435,8 +438,6 @@ static int read_symbols(struct elf *elf)
+                       return -1;
+               }
+               memset(sym, 0, sizeof(*sym));
+-              INIT_LIST_HEAD(&sym->pv_target);
+-              sym->alias = sym;
+               sym->idx = i;
+@@ -600,24 +601,21 @@ static void elf_dirty_reloc_sym(struct e
+ }
+ /*
+- * Move the first global symbol, as per sh_info, into a new, higher symbol
+- * index. This fees up the shndx for a new local symbol.
++ * The libelf API is terrible; gelf_update_sym*() takes a data block relative
++ * index value, *NOT* the symbol index. As such, iterate the data blocks and
++ * adjust index until it fits.
++ *
++ * If no data block is found, allow adding a new data block provided the index
++ * is only one past the end.
+  */
+-static int elf_move_global_symbol(struct elf *elf, struct section *symtab,
+-                                struct section *symtab_shndx)
++static int elf_update_symbol(struct elf *elf, struct section *symtab,
++                           struct section *symtab_shndx, struct symbol *sym)
+ {
+-      Elf_Data *data, *shndx_data = NULL;
+-      Elf32_Word first_non_local;
+-      struct symbol *sym;
+-      Elf_Scn *s;
+-
+-      first_non_local = symtab->sh.sh_info;
+-
+-      sym = find_symbol_by_index(elf, first_non_local);
+-      if (!sym) {
+-              WARN("no non-local symbols !?");
+-              return first_non_local;
+-      }
++      Elf32_Word shndx = sym->sec ? sym->sec->idx : SHN_UNDEF;
++      Elf_Data *symtab_data = NULL, *shndx_data = NULL;
++      Elf64_Xword entsize = symtab->sh.sh_entsize;
++      int max_idx, idx = sym->idx;
++      Elf_Scn *s, *t = NULL;
+       s = elf_getscn(elf->elf, symtab->idx);
+       if (!s) {
+@@ -625,79 +623,124 @@ static int elf_move_global_symbol(struct
+               return -1;
+       }
+-      data = elf_newdata(s);
+-      if (!data) {
+-              WARN_ELF("elf_newdata");
+-              return -1;
++      if (symtab_shndx) {
++              t = elf_getscn(elf->elf, symtab_shndx->idx);
++              if (!t) {
++                      WARN_ELF("elf_getscn");
++                      return -1;
++              }
+       }
+-      data->d_buf = &sym->sym;
+-      data->d_size = sizeof(sym->sym);
+-      data->d_align = 1;
+-      data->d_type = ELF_T_SYM;
++      for (;;) {
++              /* get next data descriptor for the relevant sections */
++              symtab_data = elf_getdata(s, symtab_data);
++              if (t)
++                      shndx_data = elf_getdata(t, shndx_data);
++
++              /* end-of-list */
++              if (!symtab_data) {
++                      void *buf;
++
++                      if (idx) {
++                              /* we don't do holes in symbol tables */
++                              WARN("index out of range");
++                              return -1;
++                      }
+-      sym->idx = symtab->sh.sh_size / sizeof(sym->sym);
+-      elf_dirty_reloc_sym(elf, sym);
++                      /* if @idx == 0, it's the next contiguous entry, create it */
++                      symtab_data = elf_newdata(s);
++                      if (t)
++                              shndx_data = elf_newdata(t);
++
++                      buf = calloc(1, entsize);
++                      if (!buf) {
++                              WARN("malloc");
++                              return -1;
++                      }
+-      symtab->sh.sh_info += 1;
+-      symtab->sh.sh_size += data->d_size;
+-      symtab->changed = true;
++                      symtab_data->d_buf = buf;
++                      symtab_data->d_size = entsize;
++                      symtab_data->d_align = 1;
++                      symtab_data->d_type = ELF_T_SYM;
++
++                      symtab->sh.sh_size += entsize;
++                      symtab->changed = true;
++
++                      if (t) {
++                              shndx_data->d_buf = &sym->sec->idx;
++                              shndx_data->d_size = sizeof(Elf32_Word);
++                              shndx_data->d_align = sizeof(Elf32_Word);
++                              shndx_data->d_type = ELF_T_WORD;
+-      if (symtab_shndx) {
+-              s = elf_getscn(elf->elf, symtab_shndx->idx);
+-              if (!s) {
+-                      WARN_ELF("elf_getscn");
++                              symtab_shndx->sh.sh_size += sizeof(Elf32_Word);
++                              symtab_shndx->changed = true;
++                      }
++
++                      break;
++              }
++
++              /* empty blocks should not happen */
++              if (!symtab_data->d_size) {
++                      WARN("zero size data");
+                       return -1;
+               }
+-              shndx_data = elf_newdata(s);
++              /* is this the right block? */
++              max_idx = symtab_data->d_size / entsize;
++              if (idx < max_idx)
++                      break;
++
++              /* adjust index and try again */
++              idx -= max_idx;
++      }
++
++      /* something went side-ways */
++      if (idx < 0) {
++              WARN("negative index");
++              return -1;
++      }
++
++      /* setup extended section index magic and write the symbol */
++      if (shndx >= SHN_UNDEF && shndx < SHN_LORESERVE) {
++              sym->sym.st_shndx = shndx;
++              if (!shndx_data)
++                      shndx = 0;
++      } else {
++              sym->sym.st_shndx = SHN_XINDEX;
+               if (!shndx_data) {
+-                      WARN_ELF("elf_newshndx_data");
++                      WARN("no .symtab_shndx");
+                       return -1;
+               }
++      }
+-              shndx_data->d_buf = &sym->sec->idx;
+-              shndx_data->d_size = sizeof(Elf32_Word);
+-              shndx_data->d_align = 4;
+-              shndx_data->d_type = ELF_T_WORD;
+-
+-              symtab_shndx->sh.sh_size += 4;
+-              symtab_shndx->changed = true;
++      if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)) {
++              WARN_ELF("gelf_update_symshndx");
++              return -1;
+       }
+-      return first_non_local;
++      return 0;
+ }
+ static struct symbol *
+ elf_create_section_symbol(struct elf *elf, struct section *sec)
+ {
+       struct section *symtab, *symtab_shndx;
+-      Elf_Data *shndx_data = NULL;
+-      struct symbol *sym;
+-      Elf32_Word shndx;
++      Elf32_Word first_non_local, new_idx;
++      struct symbol *sym, *old;
+       symtab = find_section_by_name(elf, ".symtab");
+       if (symtab) {
+               symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
+-              if (symtab_shndx)
+-                      shndx_data = symtab_shndx->data;
+       } else {
+               WARN("no .symtab");
+               return NULL;
+       }
+-      sym = malloc(sizeof(*sym));
++      sym = calloc(1, sizeof(*sym));
+       if (!sym) {
+               perror("malloc");
+               return NULL;
+       }
+-      memset(sym, 0, sizeof(*sym));
+-
+-      sym->idx = elf_move_global_symbol(elf, symtab, symtab_shndx);
+-      if (sym->idx < 0) {
+-              WARN("elf_move_global_symbol");
+-              return NULL;
+-      }
+       sym->name = sec->name;
+       sym->sec = sec;
+@@ -707,24 +750,41 @@ elf_create_section_symbol(struct elf *el
+       // st_other 0
+       // st_value 0
+       // st_size 0
+-      shndx = sec->idx;
+-      if (shndx >= SHN_UNDEF && shndx < SHN_LORESERVE) {
+-              sym->sym.st_shndx = shndx;
+-              if (!shndx_data)
+-                      shndx = 0;
+-      } else {
+-              sym->sym.st_shndx = SHN_XINDEX;
+-              if (!shndx_data) {
+-                      WARN("no .symtab_shndx");
++
++      /*
++       * Move the first global symbol, as per sh_info, into a new, higher
++       * symbol index. This fees up a spot for a new local symbol.
++       */
++      first_non_local = symtab->sh.sh_info;
++      new_idx = symtab->sh.sh_size / symtab->sh.sh_entsize;
++      old = find_symbol_by_index(elf, first_non_local);
++      if (old) {
++              old->idx = new_idx;
++
++              hlist_del(&old->hash);
++              elf_hash_add(symbol, &old->hash, old->idx);
++
++              elf_dirty_reloc_sym(elf, old);
++
++              if (elf_update_symbol(elf, symtab, symtab_shndx, old)) {
++                      WARN("elf_update_symbol move");
+                       return NULL;
+               }
++
++              new_idx = first_non_local;
+       }
+-      if (!gelf_update_symshndx(symtab->data, shndx_data, sym->idx, &sym->sym, shndx)) {
+-              WARN_ELF("gelf_update_symshndx");
++      sym->idx = new_idx;
++      if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) {
++              WARN("elf_update_symbol");
+               return NULL;
+       }
++      /*
++       * Either way, we added a LOCAL symbol.
++       */
++      symtab->sh.sh_info += 1;
++
+       elf_add_symbol(elf, sym);
+       return sym;
index 531c1c752f241c8e08e7c7c0bce8712e8bbae272..30b4e4727cec719b10f4731e8cb66538ef97e632 100644 (file)
@@ -715,3 +715,5 @@ f2fs-fix-to-do-sanity-check-on-total_data_blocks.patch
 f2fs-don-t-use-casefolded-comparison-for-.-and.patch
 f2fs-fix-fallocate-to-use-file_modified-to-update-permissions-consistently.patch
 f2fs-fix-to-do-sanity-check-for-inline-inode.patch
+objtool-fix-objtool-regression-on-x32-systems.patch
+objtool-fix-symbol-creation.patch