]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: fix malformed .shstrtab section
authorThan McIntosh <thanm@google.com>
Wed, 13 Sep 2023 13:26:41 +0000 (09:26 -0400)
committerThan McIntosh <thanm@google.com>
Wed, 13 Sep 2023 16:29:40 +0000 (16:29 +0000)
For ELF targets, the code in the go linker that generates the
".shstrtab" section was using a loader symbol to accumulate the
contents of the section, then setting the section type to
sym.SELFROSECT. This resulted in a section whose offset indicated that
it fell into a loadable ELF segment, which is not how the .shstrtab is
supposed to work (it should be outside of all loadable segments,
similar to .strtab and .symtab). The peculiar .shstrtab caused
confusion in third party tools that operate on ELF files, notably
llvm-strip.

This patch rewrites the .shstrtab generation code to avoid using a
loader.Symbol and instead accumulate the contents of the section into
a regular byte slice, then emit the section's data in the same way
that .strtab is handled.

Fixes #62600.

Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-windows-amd64-longtest
Change-Id: Ie54020d7b2d779d3ac9f5465fd505217d0681f79
Reviewed-on: https://go-review.googlesource.com/c/go/+/528036
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/elf_test.go
src/cmd/link/internal/ld/symtab.go

index 0bc78b4f1e045523bf32b3746078fdb26612cf21..a3f99b19608a1118f3ecfe585bcfc9af8f11bc20 100644 (file)
@@ -155,7 +155,7 @@ const (
  * marshal a 32-bit representation from the 64-bit structure.
  */
 
-var Elfstrdat []byte
+var elfstrdat, elfshstrdat []byte
 
 /*
  * Total amount of space to reserve at the start of the file
@@ -1386,12 +1386,16 @@ func (ctxt *Link) doelf() {
        ldr := ctxt.loader
 
        /* predefine strings we need for section headers */
-       shstrtab := ldr.CreateSymForUpdate(".shstrtab", 0)
 
-       shstrtab.SetType(sym.SELFROSECT)
+       addshstr := func(s string) int {
+               off := len(elfshstrdat)
+               elfshstrdat = append(elfshstrdat, s...)
+               elfshstrdat = append(elfshstrdat, 0)
+               return off
+       }
 
        shstrtabAddstring := func(s string) {
-               off := shstrtab.Addstring(s)
+               off := addshstr(s)
                elfsetstring(ctxt, 0, s, int(off))
        }
 
@@ -1746,12 +1750,16 @@ func Asmbelfsetup() {
 
 func asmbElf(ctxt *Link) {
        var symo int64
-       if !*FlagS {
-               symo = int64(Segdwarf.Fileoff + Segdwarf.Filelen)
-               symo = Rnd(symo, int64(ctxt.Arch.PtrSize))
+       symo = int64(Segdwarf.Fileoff + Segdwarf.Filelen)
+       symo = Rnd(symo, int64(ctxt.Arch.PtrSize))
+       ctxt.Out.SeekSet(symo)
+       if *FlagS {
+               ctxt.Out.Write(elfshstrdat)
+       } else {
                ctxt.Out.SeekSet(symo)
                asmElfSym(ctxt)
-               ctxt.Out.Write(Elfstrdat)
+               ctxt.Out.Write(elfstrdat)
+               ctxt.Out.Write(elfshstrdat)
                if ctxt.IsExternal() {
                        elfEmitReloc(ctxt)
                }
@@ -2155,9 +2163,6 @@ func asmbElf(ctxt *Link) {
 
 elfobj:
        sh := elfshname(".shstrtab")
-       sh.Type = uint32(elf.SHT_STRTAB)
-       sh.Addralign = 1
-       shsym(sh, ldr, ldr.Lookup(".shstrtab", 0))
        eh.Shstrndx = uint16(sh.shnum)
 
        if ctxt.IsMIPS() {
@@ -2184,6 +2189,7 @@ elfobj:
                elfshname(".symtab")
                elfshname(".strtab")
        }
+       elfshname(".shstrtab")
 
        for _, sect := range Segtext.Sections {
                elfshbits(ctxt.LinkMode, sect)
@@ -2226,6 +2232,7 @@ elfobj:
                sh.Flags = 0
        }
 
+       var shstroff uint64
        if !*FlagS {
                sh := elfshname(".symtab")
                sh.Type = uint32(elf.SHT_SYMTAB)
@@ -2239,10 +2246,19 @@ elfobj:
                sh = elfshname(".strtab")
                sh.Type = uint32(elf.SHT_STRTAB)
                sh.Off = uint64(symo) + uint64(symSize)
-               sh.Size = uint64(len(Elfstrdat))
+               sh.Size = uint64(len(elfstrdat))
                sh.Addralign = 1
+               shstroff = sh.Off + sh.Size
+       } else {
+               shstroff = uint64(symo)
        }
 
+       sh = elfshname(".shstrtab")
+       sh.Type = uint32(elf.SHT_STRTAB)
+       sh.Off = shstroff
+       sh.Size = uint64(len(elfshstrdat))
+       sh.Addralign = 1
+
        /* Main header */
        copy(eh.Ident[:], elf.ELFMAG)
 
index 8af0ca144eb1b32132cf891ce53bc33a89658243..f5f5e8ef4ebfa02292d89f142a2fd5dcefa38423 100644 (file)
@@ -125,3 +125,61 @@ func TestNoDuplicateNeededEntries(t *testing.T) {
                t.Errorf("Got %d entries for `libc.so`, want %d", got, want)
        }
 }
+
+func TestShStrTabAttributesIssue62600(t *testing.T) {
+       t.Parallel()
+       testenv.MustHaveGoBuild(t)
+       dir := t.TempDir()
+
+       const prog = `
+package main
+
+func main() {
+       println("whee")
+}
+`
+       src := filepath.Join(dir, "issue62600.go")
+       if err := os.WriteFile(src, []byte(prog), 0666); err != nil {
+               t.Fatal(err)
+       }
+
+       binFile := filepath.Join(dir, "issue62600")
+       cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", binFile, src)
+       if out, err := cmd.CombinedOutput(); err != nil {
+               t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
+       }
+
+       fi, err := os.Open(binFile)
+       if err != nil {
+               t.Fatalf("failed to open built file: %v", err)
+       }
+       defer fi.Close()
+
+       elfFile, err := elf.NewFile(fi)
+       if err != nil {
+               t.Skip("The system may not support ELF, skipped.")
+       }
+
+       section := elfFile.Section(".shstrtab")
+       if section == nil {
+               t.Fatal("no .shstrtab")
+       }
+
+       // The .shstrtab section should have a zero address, non-zero
+       // size, no ALLOC flag, and the offset should not fall into any of
+       // the segments defined by the program headers.
+       if section.Addr != 0 {
+               t.Fatalf("expected Addr == 0 for .shstrtab got %x", section.Addr)
+       }
+       if section.Size == 0 {
+               t.Fatal("expected nonzero Size for .shstrtab got 0")
+       }
+       if section.Flags&elf.SHF_ALLOC != 0 {
+               t.Fatal("expected zero alloc flag got nonzero for .shstrtab")
+       }
+       for idx, p := range elfFile.Progs {
+               if section.Offset >= p.Off && section.Offset < p.Off+p.Filesz {
+                       t.Fatalf("badly formed .shstrtab, is contained in segment %d", idx)
+               }
+       }
+}
index b039e7d8749c268950b0e71b30eef921d431c8d3..01f9780d8b44805e89f741a96f553a91f5dc934a 100644 (file)
@@ -45,14 +45,14 @@ import (
 // Symbol table.
 
 func putelfstr(s string) int {
-       if len(Elfstrdat) == 0 && s != "" {
+       if len(elfstrdat) == 0 && s != "" {
                // first entry must be empty string
                putelfstr("")
        }
 
-       off := len(Elfstrdat)
-       Elfstrdat = append(Elfstrdat, s...)
-       Elfstrdat = append(Elfstrdat, 0)
+       off := len(elfstrdat)
+       elfstrdat = append(elfstrdat, s...)
+       elfstrdat = append(elfstrdat, 0)
        return off
 }