From: Than McIntosh Date: Wed, 13 Sep 2023 13:26:41 +0000 (-0400) Subject: cmd/link: fix malformed .shstrtab section X-Git-Tag: go1.22rc1~867 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=3251006291c3e09c6ea40b6a65e5f05d9b9de573;p=gostls13.git cmd/link: fix malformed .shstrtab section 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 LUCI-TryBot-Result: Go LUCI --- diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 0bc78b4f1e..a3f99b1960 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -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) diff --git a/src/cmd/link/internal/ld/elf_test.go b/src/cmd/link/internal/ld/elf_test.go index 8af0ca144e..f5f5e8ef4e 100644 --- a/src/cmd/link/internal/ld/elf_test.go +++ b/src/cmd/link/internal/ld/elf_test.go @@ -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) + } + } +} diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index b039e7d874..01f9780d8b 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -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 }