diff options
Diffstat (limited to 'src/cmd/link/internal/ld')
-rw-r--r-- | src/cmd/link/internal/ld/data.go | 3 | ||||
-rw-r--r-- | src/cmd/link/internal/ld/elf.go | 20 | ||||
-rw-r--r-- | src/cmd/link/internal/ld/elf_test.go | 58 |
3 files changed, 75 insertions, 6 deletions
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 11dc48b18b..feaa3c34d8 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -1850,7 +1850,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) { } ldr := ctxt.loader - // .got + // writable .got (note that for PIE binaries .got goes in relro) if len(state.data[sym.SELFGOT]) > 0 { state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06) } @@ -2106,6 +2106,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) { xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn) } } + state.assignToSection(sect, sym.SELFRELROSECT, sym.SRODATA) sect.Length = uint64(state.datsize) - sect.Vaddr } diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 97b24b0cae..0d8455d92e 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1113,6 +1113,7 @@ func elfphload(seg *sym.Segment) *ElfPhdr { func elfphrelro(seg *sym.Segment) { ph := newElfPhdr() ph.Type = elf.PT_GNU_RELRO + ph.Flags = elf.PF_R ph.Vaddr = seg.Vaddr ph.Paddr = seg.Vaddr ph.Memsz = seg.Length @@ -1562,7 +1563,11 @@ func (ctxt *Link) doelf() { /* global offset table */ got := ldr.CreateSymForUpdate(".got", 0) - got.SetType(sym.SELFGOT) // writable + if ctxt.UseRelro() { + got.SetType(sym.SELFRELROSECT) + } else { + got.SetType(sym.SELFGOT) // writable + } /* ppc64 glink resolver */ if ctxt.IsPPC64() { @@ -1575,7 +1580,11 @@ func (ctxt *Link) doelf() { hash.SetType(sym.SELFROSECT) gotplt := ldr.CreateSymForUpdate(".got.plt", 0) - gotplt.SetType(sym.SELFSECT) // writable + if ctxt.UseRelro() && *flagBindNow { + gotplt.SetType(sym.SELFRELROSECT) + } else { + gotplt.SetType(sym.SELFSECT) // writable + } plt := ldr.CreateSymForUpdate(".plt", 0) if ctxt.IsPPC64() { @@ -1597,9 +1606,12 @@ func (ctxt *Link) doelf() { /* define dynamic elf table */ dynamic := ldr.CreateSymForUpdate(".dynamic", 0) - if thearch.ELF.DynamicReadOnly { + switch { + case thearch.ELF.DynamicReadOnly: dynamic.SetType(sym.SELFROSECT) - } else { + case ctxt.UseRelro(): + dynamic.SetType(sym.SELFRELROSECT) + default: dynamic.SetType(sym.SELFSECT) } diff --git a/src/cmd/link/internal/ld/elf_test.go b/src/cmd/link/internal/ld/elf_test.go index 16bf4039b1..b48cf66038 100644 --- a/src/cmd/link/internal/ld/elf_test.go +++ b/src/cmd/link/internal/ld/elf_test.go @@ -198,6 +198,7 @@ func TestElfBindNow(t *testing.T) { name string args []string prog string + wantSecsRO []string mustHaveBuildModePIE bool mustHaveCGO bool mustInternalLink bool @@ -213,6 +214,7 @@ func TestElfBindNow(t *testing.T) { mustHaveBuildModePIE: true, mustInternalLink: true, wantDf1Pie: true, + wantSecsRO: []string{".dynamic", ".got"}, }, { name: "bindnow-linkmode-internal", @@ -232,6 +234,7 @@ func TestElfBindNow(t *testing.T) { wantDfBindNow: true, wantDf1Now: true, wantDf1Pie: true, + wantSecsRO: []string{".dynamic", ".got", ".got.plt"}, }, { name: "bindnow-pie-linkmode-external", @@ -242,6 +245,8 @@ func TestElfBindNow(t *testing.T) { wantDfBindNow: true, wantDf1Now: true, wantDf1Pie: true, + // NB: external linker produces .plt.got, not .got.plt + wantSecsRO: []string{".dynamic", ".got"}, }, } @@ -251,10 +256,14 @@ func TestElfBindNow(t *testing.T) { return true } } - return false } + segContainsSec := func(p *elf.Prog, s *elf.Section) bool { + return s.Addr >= p.Vaddr && + s.Addr+s.FileSize <= p.Vaddr+p.Filesz + } + for _, test := range tests { t.Run(test.name, func(t *testing.T) { if test.mustInternalLink { @@ -329,6 +338,53 @@ func TestElfBindNow(t *testing.T) { if gotDf1Pie := gotDynFlag(flags1, uint64(elf.DF_1_PIE)); gotDf1Pie != test.wantDf1Pie { t.Fatalf("DT_FLAGS_1 DF_1_PIE got: %v, want: %v", gotDf1Pie, test.wantDf1Pie) } + + for _, wsroname := range test.wantSecsRO { + // Locate section of interest. + var wsro *elf.Section + for _, s := range elfFile.Sections { + if s.Name == wsroname { + wsro = s + break + } + } + if wsro == nil { + t.Fatalf("test %s: can't locate %q section", + test.name, wsroname) + } + + // Now walk the program headers. Section should be part of + // some segment that is readonly. + foundRO := false + foundSegs := []*elf.Prog{} + for _, p := range elfFile.Progs { + if segContainsSec(p, wsro) { + foundSegs = append(foundSegs, p) + if p.Flags == elf.PF_R { + foundRO = true + } + } + } + if !foundRO { + // Things went off the rails. Write out some + // useful information for a human looking at the + // test failure. + t.Logf("test %s: %q section not in readonly segment", + wsro.Name, test.name) + t.Logf("section %s location: st=0x%x en=0x%x\n", + wsro.Name, wsro.Addr, wsro.Addr+wsro.FileSize) + t.Logf("sec %s found in these segments: ", wsro.Name) + for _, p := range foundSegs { + t.Logf(" %q", p.Type) + } + t.Logf("\nall segments: \n") + for k, p := range elfFile.Progs { + t.Logf("%d t=%s fl=%s st=0x%x en=0x%x\n", + k, p.Type, p.Flags, p.Vaddr, p.Vaddr+p.Filesz) + } + t.Fatalf("test %s failed", test.name) + } + } }) } } |