Skip to content

Commit 2dddc7e

Browse files
committed
cmd/link: move .dynamic and .got sections to relro if applicable
This is the second of two CLs to roll forward the changes in CL 473495, which was subsequently reverted. In this patch we move the .dynamic and .got sections from the writable data segment to the relro segment if the platform supports relro and we're producing a PIE binary, and also moves .got.plt into relro if eager binding is in effect (e.g. -bindnow or -Wl,-z,now). Updates #45681. Change-Id: I9f4fba6e825b96d1b5e27fb75844450dd0a650b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/571417 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 7f76c00 commit 2dddc7e

File tree

5 files changed

+121
-50
lines changed

5 files changed

+121
-50
lines changed

src/cmd/link/internal/ld/data.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1850,7 +1850,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
18501850
}
18511851
ldr := ctxt.loader
18521852

1853-
// .got
1853+
// writable .got (note that for PIE binaries .got goes in relro)
18541854
if len(state.data[sym.SELFGOT]) > 0 {
18551855
state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
18561856
}
@@ -2106,6 +2106,7 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
21062106
xcoffUpdateOuterSize(ctxt, state.datsize-symnStartValue, symn)
21072107
}
21082108
}
2109+
state.assignToSection(sect, sym.SELFRELROSECT, sym.SRODATA)
21092110

21102111
sect.Length = uint64(state.datsize) - sect.Vaddr
21112112
}

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

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,7 @@ func elfphload(seg *sym.Segment) *ElfPhdr {
11131113
func elfphrelro(seg *sym.Segment) {
11141114
ph := newElfPhdr()
11151115
ph.Type = elf.PT_GNU_RELRO
1116+
ph.Flags = elf.PF_R
11161117
ph.Vaddr = seg.Vaddr
11171118
ph.Paddr = seg.Vaddr
11181119
ph.Memsz = seg.Length
@@ -1562,7 +1563,11 @@ func (ctxt *Link) doelf() {
15621563

15631564
/* global offset table */
15641565
got := ldr.CreateSymForUpdate(".got", 0)
1565-
got.SetType(sym.SELFGOT) // writable
1566+
if ctxt.UseRelro() {
1567+
got.SetType(sym.SELFRELROSECT)
1568+
} else {
1569+
got.SetType(sym.SELFGOT) // writable
1570+
}
15661571

15671572
/* ppc64 glink resolver */
15681573
if ctxt.IsPPC64() {
@@ -1575,7 +1580,11 @@ func (ctxt *Link) doelf() {
15751580
hash.SetType(sym.SELFROSECT)
15761581

15771582
gotplt := ldr.CreateSymForUpdate(".got.plt", 0)
1578-
gotplt.SetType(sym.SELFSECT) // writable
1583+
if ctxt.UseRelro() && *flagBindNow {
1584+
gotplt.SetType(sym.SELFRELROSECT)
1585+
} else {
1586+
gotplt.SetType(sym.SELFSECT) // writable
1587+
}
15791588

15801589
plt := ldr.CreateSymForUpdate(".plt", 0)
15811590
if ctxt.IsPPC64() {
@@ -1597,9 +1606,12 @@ func (ctxt *Link) doelf() {
15971606

15981607
/* define dynamic elf table */
15991608
dynamic := ldr.CreateSymForUpdate(".dynamic", 0)
1600-
if thearch.ELF.DynamicReadOnly {
1609+
switch {
1610+
case thearch.ELF.DynamicReadOnly:
16011611
dynamic.SetType(sym.SELFROSECT)
1602-
} else {
1612+
case ctxt.UseRelro():
1613+
dynamic.SetType(sym.SELFRELROSECT)
1614+
default:
16031615
dynamic.SetType(sym.SELFSECT)
16041616
}
16051617

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

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ func TestElfBindNow(t *testing.T) {
198198
name string
199199
args []string
200200
prog string
201+
wantSecsRO []string
201202
mustHaveBuildModePIE bool
202203
mustHaveCGO bool
203204
mustInternalLink bool
@@ -213,6 +214,7 @@ func TestElfBindNow(t *testing.T) {
213214
mustHaveBuildModePIE: true,
214215
mustInternalLink: true,
215216
wantDf1Pie: true,
217+
wantSecsRO: []string{".dynamic", ".got"},
216218
},
217219
{
218220
name: "bindnow-linkmode-internal",
@@ -232,6 +234,7 @@ func TestElfBindNow(t *testing.T) {
232234
wantDfBindNow: true,
233235
wantDf1Now: true,
234236
wantDf1Pie: true,
237+
wantSecsRO: []string{".dynamic", ".got", ".got.plt"},
235238
},
236239
{
237240
name: "bindnow-pie-linkmode-external",
@@ -242,6 +245,8 @@ func TestElfBindNow(t *testing.T) {
242245
wantDfBindNow: true,
243246
wantDf1Now: true,
244247
wantDf1Pie: true,
248+
// NB: external linker produces .plt.got, not .got.plt
249+
wantSecsRO: []string{".dynamic", ".got"},
245250
},
246251
}
247252

@@ -251,10 +256,14 @@ func TestElfBindNow(t *testing.T) {
251256
return true
252257
}
253258
}
254-
255259
return false
256260
}
257261

262+
segContainsSec := func(p *elf.Prog, s *elf.Section) bool {
263+
return s.Addr >= p.Vaddr &&
264+
s.Addr+s.FileSize <= p.Vaddr+p.Filesz
265+
}
266+
258267
for _, test := range tests {
259268
t.Run(test.name, func(t *testing.T) {
260269
if test.mustInternalLink {
@@ -329,6 +338,53 @@ func TestElfBindNow(t *testing.T) {
329338
if gotDf1Pie := gotDynFlag(flags1, uint64(elf.DF_1_PIE)); gotDf1Pie != test.wantDf1Pie {
330339
t.Fatalf("DT_FLAGS_1 DF_1_PIE got: %v, want: %v", gotDf1Pie, test.wantDf1Pie)
331340
}
341+
342+
for _, wsroname := range test.wantSecsRO {
343+
// Locate section of interest.
344+
var wsro *elf.Section
345+
for _, s := range elfFile.Sections {
346+
if s.Name == wsroname {
347+
wsro = s
348+
break
349+
}
350+
}
351+
if wsro == nil {
352+
t.Fatalf("test %s: can't locate %q section",
353+
test.name, wsroname)
354+
}
355+
356+
// Now walk the program headers. Section should be part of
357+
// some segment that is readonly.
358+
foundRO := false
359+
foundSegs := []*elf.Prog{}
360+
for _, p := range elfFile.Progs {
361+
if segContainsSec(p, wsro) {
362+
foundSegs = append(foundSegs, p)
363+
if p.Flags == elf.PF_R {
364+
foundRO = true
365+
}
366+
}
367+
}
368+
if !foundRO {
369+
// Things went off the rails. Write out some
370+
// useful information for a human looking at the
371+
// test failure.
372+
t.Logf("test %s: %q section not in readonly segment",
373+
wsro.Name, test.name)
374+
t.Logf("section %s location: st=0x%x en=0x%x\n",
375+
wsro.Name, wsro.Addr, wsro.Addr+wsro.FileSize)
376+
t.Logf("sec %s found in these segments: ", wsro.Name)
377+
for _, p := range foundSegs {
378+
t.Logf(" %q", p.Type)
379+
}
380+
t.Logf("\nall segments: \n")
381+
for k, p := range elfFile.Progs {
382+
t.Logf("%d t=%s fl=%s st=0x%x en=0x%x\n",
383+
k, p.Type, p.Flags, p.Vaddr, p.Vaddr+p.Filesz)
384+
}
385+
t.Fatalf("test %s failed", test.name)
386+
}
387+
}
332388
})
333389
}
334390
}

src/cmd/link/internal/sym/symkind.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ const (
7676
SGCBITSRELRO
7777
SRODATARELRO
7878
SFUNCTABRELRO
79+
SELFRELROSECT
7980

8081
// Part of .data.rel.ro if it exists, otherwise part of .rodata.
8182
STYPELINK

src/cmd/link/internal/sym/symkind_string.go

Lines changed: 45 additions & 44 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)