Skip to content

Commit be58fd0

Browse files
committed
Revert: "cmd/link: add option to enable full RELRO for ELF"
This reverts https://go.dev/cl/c/go/+/473495. Reason for revert: breaks some Google-internal tests. This revert will be temporary until we can gather more info on the nature of the failures and hopefully develop an upstream test case, etc. Updates #45681. Change-Id: Ib628ddc53bc5489e4f76c0f4ad809b75e899102c Reviewed-on: https://go-review.googlesource.com/c/go/+/571415 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 1e20af0 commit be58fd0

File tree

8 files changed

+11
-198
lines changed

8 files changed

+11
-198
lines changed

src/cmd/go/internal/work/security.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ var validLinkerFlags = []*lazyregexp.Regexp{
210210
re(`-Wl,-?-unresolved-symbols=[^,]+`),
211211
re(`-Wl,--(no-)?warn-([^,]+)`),
212212
re(`-Wl,-?-wrap[=,][^,@\-][^,]*`),
213-
re(`-Wl(,-z,(relro|now|(no)?execstack))+`),
213+
re(`-Wl,-z,(no)?execstack`),
214+
re(`-Wl,-z,relro`),
214215

215216
re(`[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so|tbd)`), // direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
216217
re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),

src/cmd/go/internal/work/security_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,6 @@ var goodLinkerFlags = [][]string{
167167
{"-Wl,-framework", "-Wl,Chocolate"},
168168
{"-Wl,-framework,Chocolate"},
169169
{"-Wl,-unresolved-symbols=ignore-all"},
170-
{"-Wl,-z,relro"},
171-
{"-Wl,-z,relro,-z,now"},
172-
{"-Wl,-z,now"},
173-
{"-Wl,-z,noexecstack"},
174170
{"libcgotbdtest.tbd"},
175171
{"./libcgotbdtest.tbd"},
176172
}

src/cmd/link/doc.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ Flags:
4747
Link with C/C++ address sanitizer support.
4848
-aslr
4949
Enable ASLR for buildmode=c-shared on windows (default true).
50-
-bindnow
51-
Mark a dynamically linked ELF object for immediate function binding (default false).
5250
-buildid id
5351
Record id as Go toolchain build id.
5452
-buildmode mode

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

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,17 +1056,11 @@ func elfdynhash(ctxt *Link) {
10561056
}
10571057

10581058
s = ldr.CreateSymForUpdate(".dynamic", 0)
1059-
1060-
var dtFlags1 elf.DynFlag1
1061-
if *flagBindNow {
1062-
dtFlags1 |= elf.DF_1_NOW
1063-
Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS, uint64(elf.DF_BIND_NOW))
1064-
}
10651059
if ctxt.BuildMode == BuildModePIE {
1066-
dtFlags1 |= elf.DF_1_PIE
1060+
// https://github.com/bminor/glibc/blob/895ef79e04a953cac1493863bcae29ad85657ee1/elf/elf.h#L986
1061+
const DTFLAGS_1_PIE = 0x08000000
1062+
Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS_1, uint64(DTFLAGS_1_PIE))
10671063
}
1068-
Elfwritedynent(ctxt.Arch, s, elf.DT_FLAGS_1, uint64(dtFlags1))
1069-
10701064
elfverneed = nfile
10711065
if elfverneed != 0 {
10721066
elfWriteDynEntSym(ctxt, s, elf.DT_VERNEED, gnuVersionR.Sym())
@@ -1113,7 +1107,6 @@ func elfphload(seg *sym.Segment) *ElfPhdr {
11131107
func elfphrelro(seg *sym.Segment) {
11141108
ph := newElfPhdr()
11151109
ph.Type = elf.PT_GNU_RELRO
1116-
ph.Flags = elf.PF_R
11171110
ph.Vaddr = seg.Vaddr
11181111
ph.Paddr = seg.Vaddr
11191112
ph.Memsz = seg.Length
@@ -1563,11 +1556,7 @@ func (ctxt *Link) doelf() {
15631556

15641557
/* global offset table */
15651558
got := ldr.CreateSymForUpdate(".got", 0)
1566-
if ctxt.UseRelro() {
1567-
got.SetType(sym.SRODATARELRO)
1568-
} else {
1569-
got.SetType(sym.SELFGOT) // writable
1570-
}
1559+
got.SetType(sym.SELFGOT) // writable
15711560

15721561
/* ppc64 glink resolver */
15731562
if ctxt.IsPPC64() {
@@ -1580,11 +1569,7 @@ func (ctxt *Link) doelf() {
15801569
hash.SetType(sym.SELFROSECT)
15811570

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

15891574
plt := ldr.CreateSymForUpdate(".plt", 0)
15901575
if ctxt.IsPPC64() {
@@ -1606,12 +1591,9 @@ func (ctxt *Link) doelf() {
16061591

16071592
/* define dynamic elf table */
16081593
dynamic := ldr.CreateSymForUpdate(".dynamic", 0)
1609-
switch {
1610-
case thearch.ELF.DynamicReadOnly:
1594+
if thearch.ELF.DynamicReadOnly {
16111595
dynamic.SetType(sym.SELFROSECT)
1612-
case ctxt.UseRelro():
1613-
dynamic.SetType(sym.SRODATARELRO)
1614-
default:
1596+
} else {
16151597
dynamic.SetType(sym.SELFSECT)
16161598
}
16171599

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

Lines changed: 0 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package ld
88

99
import (
1010
"debug/elf"
11-
"fmt"
1211
"internal/testenv"
1312
"os"
1413
"path/filepath"
@@ -183,152 +182,3 @@ func main() {
183182
}
184183
}
185184
}
186-
187-
func TestElfBindNow(t *testing.T) {
188-
t.Parallel()
189-
testenv.MustHaveGoBuild(t)
190-
191-
const (
192-
prog = `package main; func main() {}`
193-
// with default buildmode code compiles in a statically linked binary, hence CGO
194-
progC = `package main; import "C"; func main() {}`
195-
)
196-
197-
tests := []struct {
198-
name string
199-
args []string
200-
prog string
201-
mustHaveBuildModePIE bool
202-
mustHaveCGO bool
203-
mustInternalLink bool
204-
wantDfBindNow bool
205-
wantDf1Now bool
206-
wantDf1Pie bool
207-
}{
208-
{name: "default", prog: prog},
209-
{
210-
name: "pie-linkmode-internal",
211-
args: []string{"-buildmode=pie", "-ldflags", "-linkmode=internal"},
212-
prog: prog,
213-
mustHaveBuildModePIE: true,
214-
mustInternalLink: true,
215-
wantDf1Pie: true,
216-
},
217-
{
218-
name: "bindnow-linkmode-internal",
219-
args: []string{"-ldflags", "-bindnow -linkmode=internal"},
220-
prog: progC,
221-
mustHaveCGO: true,
222-
mustInternalLink: true,
223-
wantDfBindNow: true,
224-
wantDf1Now: true,
225-
},
226-
{
227-
name: "bindnow-pie-linkmode-internal",
228-
args: []string{"-buildmode=pie", "-ldflags", "-bindnow -linkmode=internal"},
229-
prog: prog,
230-
mustHaveBuildModePIE: true,
231-
mustInternalLink: true,
232-
wantDfBindNow: true,
233-
wantDf1Now: true,
234-
wantDf1Pie: true,
235-
},
236-
{
237-
name: "bindnow-pie-linkmode-external",
238-
args: []string{"-buildmode=pie", "-ldflags", "-bindnow -linkmode=external"},
239-
prog: prog,
240-
mustHaveBuildModePIE: true,
241-
mustHaveCGO: true,
242-
wantDfBindNow: true,
243-
wantDf1Now: true,
244-
wantDf1Pie: true,
245-
},
246-
}
247-
248-
gotDynFlag := func(flags []uint64, dynFlag uint64) bool {
249-
for _, flag := range flags {
250-
if gotFlag := dynFlag&flag != 0; gotFlag {
251-
return true
252-
}
253-
}
254-
255-
return false
256-
}
257-
258-
for _, test := range tests {
259-
t.Run(test.name, func(t *testing.T) {
260-
if test.mustInternalLink {
261-
testenv.MustInternalLink(t, test.mustHaveCGO)
262-
}
263-
if test.mustHaveCGO {
264-
testenv.MustHaveCGO(t)
265-
}
266-
if test.mustHaveBuildModePIE {
267-
testenv.MustHaveBuildMode(t, "pie")
268-
}
269-
if test.mustHaveBuildModePIE && test.mustInternalLink {
270-
testenv.MustInternalLinkPIE(t)
271-
}
272-
273-
var (
274-
dir = t.TempDir()
275-
src = filepath.Join(dir, fmt.Sprintf("elf_%s.go", test.name))
276-
binFile = filepath.Join(dir, test.name)
277-
)
278-
279-
if err := os.WriteFile(src, []byte(test.prog), 0666); err != nil {
280-
t.Fatal(err)
281-
}
282-
283-
cmdArgs := append([]string{"build", "-o", binFile}, append(test.args, src)...)
284-
cmd := testenv.Command(t, testenv.GoToolPath(t), cmdArgs...)
285-
286-
if out, err := cmd.CombinedOutput(); err != nil {
287-
t.Fatalf("failed to build %v: %v:\n%s", cmd.Args, err, out)
288-
}
289-
290-
fi, err := os.Open(binFile)
291-
if err != nil {
292-
t.Fatalf("failed to open built file: %v", err)
293-
}
294-
defer fi.Close()
295-
296-
elfFile, err := elf.NewFile(fi)
297-
if err != nil {
298-
t.Skip("The system may not support ELF, skipped.")
299-
}
300-
defer elfFile.Close()
301-
302-
flags, err := elfFile.DynValue(elf.DT_FLAGS)
303-
if err != nil {
304-
t.Fatalf("failed to get DT_FLAGS: %v", err)
305-
}
306-
307-
flags1, err := elfFile.DynValue(elf.DT_FLAGS_1)
308-
if err != nil {
309-
t.Fatalf("failed to get DT_FLAGS_1: %v", err)
310-
}
311-
312-
gotDfBindNow := gotDynFlag(flags, uint64(elf.DF_BIND_NOW))
313-
gotDf1Now := gotDynFlag(flags1, uint64(elf.DF_1_NOW))
314-
315-
bindNowFlagsMatch := gotDfBindNow == test.wantDfBindNow && gotDf1Now == test.wantDf1Now
316-
317-
// some external linkers may set one of the two flags but not both.
318-
if !test.mustInternalLink {
319-
bindNowFlagsMatch = gotDfBindNow == test.wantDfBindNow || gotDf1Now == test.wantDf1Now
320-
}
321-
322-
if !bindNowFlagsMatch {
323-
t.Fatalf("Dynamic flags mismatch:\n"+
324-
"DT_FLAGS BIND_NOW got: %v, want: %v\n"+
325-
"DT_FLAGS_1 DF_1_NOW got: %v, want: %v",
326-
gotDfBindNow, test.wantDfBindNow, gotDf1Now, test.wantDf1Now)
327-
}
328-
329-
if gotDf1Pie := gotDynFlag(flags1, uint64(elf.DF_1_PIE)); gotDf1Pie != test.wantDf1Pie {
330-
t.Fatalf("DT_FLAGS_1 DF_1_PIE got: %v, want: %v", gotDf1Pie, test.wantDf1Pie)
331-
}
332-
})
333-
}
334-
}

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,16 +1604,12 @@ func (ctxt *Link) hostlink() {
16041604
}
16051605

16061606
var altLinker string
1607-
if ctxt.IsELF && (ctxt.DynlinkingGo() || *flagBindNow) {
1608-
// For ELF targets, when producing dynamically linked Go code
1609-
// or when immediate binding is explicitly requested,
1610-
// we force all symbol resolution to be done at program startup
1607+
if ctxt.IsELF && ctxt.DynlinkingGo() {
1608+
// We force all symbol resolution to be done at program startup
16111609
// because lazy PLT resolution can use large amounts of stack at
16121610
// times we cannot allow it to do so.
16131611
argv = append(argv, "-Wl,-z,now")
1614-
}
16151612

1616-
if ctxt.IsELF && ctxt.DynlinkingGo() {
16171613
// Do not let the host linker generate COPY relocations. These
16181614
// can move symbols out of sections that rely on stable offsets
16191615
// from the beginning of the section (like sym.STYPE).

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ func init() {
6363
// Flags used by the linker. The exported flags are used by the architecture-specific packages.
6464
var (
6565
flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id")
66-
flagBindNow = flag.Bool("bindnow", false, "mark a dynamically linked ELF object for immediate function binding")
6766

6867
flagOutfile = flag.String("o", "", "write output to `file`")
6968
flagPluginPath = flag.String("pluginpath", "", "full path name for plugin")

src/internal/testenv/testenv.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -369,15 +369,6 @@ func MustInternalLink(t testing.TB, withCgo bool) {
369369
}
370370
}
371371

372-
// MustInternalLinkPIE checks whether the current system can link PIE binary using
373-
// internal linking.
374-
// If not, MustInternalLinkPIE calls t.Skip with an explanation.
375-
func MustInternalLinkPIE(t testing.TB) {
376-
if !platform.InternalLinkPIESupported(runtime.GOOS, runtime.GOARCH) {
377-
t.Skipf("skipping test: internal linking for buildmode=pie on %s/%s is not supported", runtime.GOOS, runtime.GOARCH)
378-
}
379-
}
380-
381372
// MustHaveBuildMode reports whether the current system can build programs in
382373
// the given build mode.
383374
// If not, MustHaveBuildMode calls t.Skip with an explanation.

0 commit comments

Comments
 (0)