]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: define ELF .note section on FreeBSD
authorDmitri Goutnik <dgoutnik@gmail.com>
Wed, 15 Jun 2022 19:50:19 +0000 (14:50 -0500)
committerDmitri Goutnik <dgoutnik@gmail.com>
Thu, 13 Oct 2022 21:14:48 +0000 (21:14 +0000)
Write .note signature section when targeting FreeBSD, similar to NetBSD
and OpenBSD. This allows binaries to declare the ABI version they were
compiled for and opt out of ASLR when compiled with -race.

Fixes #48164

Change-Id: Ie54dd5c70697a3f42a75fd640540350fd8a4dc71
Reviewed-on: https://go-review.googlesource.com/c/go/+/412494
Reviewed-by: Meng Zhuo <mzh@golangcn.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Yuval Pavel Zholkover <paulzhol@gmail.com>
src/cmd/link/elf_test.go
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/target.go

index dd202a32dc11a3fabe5c27f3d84dbc22c17aead1..8f7af2598c9b092236fffcefccdb89dd7e34172f 100644 (file)
@@ -204,8 +204,8 @@ func TestMergeNoteSections(t *testing.T) {
        expected := 1
 
        switch runtime.GOOS {
-       case "linux", "freebsd", "dragonfly":
-       case "openbsd", "netbsd":
+       case "linux", "dragonfly":
+       case "openbsd", "netbsd", "freebsd":
                // These OSes require independent segment
                expected = 2
        default:
index dd5844bd10ee0aa133ea70a4611bf185f8973264..41fc9ab76fd59f9e08be88e93228a22dd4162b3e 100644 (file)
@@ -607,8 +607,13 @@ func elfWriteMipsAbiFlags(ctxt *Link) int {
        return int(sh.Size)
 }
 
-func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
-       n := 3*4 + uint64(sz) + resoff%4
+func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sizes ...int) int {
+       n := resoff % 4
+       // if section contains multiple notes (as is the case with FreeBSD signature),
+       // multiple note sizes can be specified
+       for _, sz := range sizes {
+               n += 3*4 + uint64(sz)
+       }
 
        sh.Type = uint32(elf.SHT_NOTE)
        sh.Flags = uint64(elf.SHF_ALLOC)
@@ -714,6 +719,67 @@ func elfwriteopenbsdsig(out *OutBuf) int {
        return int(sh.Size)
 }
 
+// FreeBSD Signature (as per sys/elf_common.h)
+const (
+       ELF_NOTE_FREEBSD_NAMESZ            = 8
+       ELF_NOTE_FREEBSD_DESCSZ            = 4
+       ELF_NOTE_FREEBSD_ABI_TAG           = 1
+       ELF_NOTE_FREEBSD_NOINIT_TAG        = 2
+       ELF_NOTE_FREEBSD_FEATURE_CTL_TAG   = 4
+       ELF_NOTE_FREEBSD_VERSION           = 1203000 // 12.3-RELEASE
+       ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE = 0x1
+)
+
+const ELF_NOTE_FREEBSD_NAME = "FreeBSD\x00"
+
+func elffreebsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
+       n := ELF_NOTE_FREEBSD_NAMESZ + ELF_NOTE_FREEBSD_DESCSZ
+       // FreeBSD signature section contains 3 equally sized notes
+       return elfnote(sh, startva, resoff, n, n, n)
+}
+
+// elfwritefreebsdsig writes FreeBSD .note section.
+//
+// See https://www.netbsd.org/docs/kernel/elf-notes.html for the description of
+// a Note element format and
+// https://github.com/freebsd/freebsd-src/blob/main/sys/sys/elf_common.h#L790
+// for the FreeBSD-specific values.
+func elfwritefreebsdsig(out *OutBuf) int {
+       sh := elfshname(".note.tag")
+       if sh == nil {
+               return 0
+       }
+       out.SeekSet(int64(sh.Off))
+
+       // NT_FREEBSD_ABI_TAG
+       out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
+       out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
+       out.Write32(ELF_NOTE_FREEBSD_ABI_TAG)
+       out.WriteString(ELF_NOTE_FREEBSD_NAME)
+       out.Write32(ELF_NOTE_FREEBSD_VERSION)
+
+       // NT_FREEBSD_NOINIT_TAG
+       out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
+       out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
+       out.Write32(ELF_NOTE_FREEBSD_NOINIT_TAG)
+       out.WriteString(ELF_NOTE_FREEBSD_NAME)
+       out.Write32(0)
+
+       // NT_FREEBSD_FEATURE_CTL
+       out.Write32(ELF_NOTE_FREEBSD_NAMESZ)
+       out.Write32(ELF_NOTE_FREEBSD_DESCSZ)
+       out.Write32(ELF_NOTE_FREEBSD_FEATURE_CTL_TAG)
+       out.WriteString(ELF_NOTE_FREEBSD_NAME)
+       if *flagRace {
+               // The race detector can't handle ASLR, turn the ASLR off when compiling with -race.
+               out.Write32(ELF_NOTE_FREEBSD_FCTL_ASLR_DISABLE)
+       } else {
+               out.Write32(0)
+       }
+
+       return int(sh.Size)
+}
+
 func addbuildinfo(val string) {
        if !strings.HasPrefix(val, "0x") {
                Exitf("-B argument must start with 0x: %s", val)
@@ -1327,6 +1393,9 @@ func (ctxt *Link) doelf() {
        if ctxt.IsOpenbsd() {
                shstrtab.Addstring(".note.openbsd.ident")
        }
+       if ctxt.IsFreebsd() {
+               shstrtab.Addstring(".note.tag")
+       }
        if len(buildinfo) > 0 {
                shstrtab.Addstring(".note.gnu.build-id")
        }
@@ -1820,7 +1889,7 @@ func asmbElf(ctxt *Link) {
                phsh(ph, sh)
        }
 
-       if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd {
+       if ctxt.HeadType == objabi.Hnetbsd || ctxt.HeadType == objabi.Hopenbsd || ctxt.HeadType == objabi.Hfreebsd {
                var sh *ElfShdr
                switch ctxt.HeadType {
                case objabi.Hnetbsd:
@@ -1830,8 +1899,12 @@ func asmbElf(ctxt *Link) {
                case objabi.Hopenbsd:
                        sh = elfshname(".note.openbsd.ident")
                        resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
+
+               case objabi.Hfreebsd:
+                       sh = elfshname(".note.tag")
+                       resoff -= int64(elffreebsdsig(sh, uint64(startva), uint64(resoff)))
                }
-               // netbsd and openbsd require ident in an independent segment.
+               // NetBSD, OpenBSD and FreeBSD require ident in an independent segment.
                pnotei := newElfPhdr()
                pnotei.Type = elf.PT_NOTE
                pnotei.Flags = elf.PF_R
@@ -2209,6 +2282,9 @@ elfobj:
                if ctxt.HeadType == objabi.Hopenbsd {
                        a += int64(elfwriteopenbsdsig(ctxt.Out))
                }
+               if ctxt.HeadType == objabi.Hfreebsd {
+                       a += int64(elfwritefreebsdsig(ctxt.Out))
+               }
                if len(buildinfo) > 0 {
                        a += int64(elfwritebuildinfo(ctxt.Out))
                }
index cc8e4181b6a763b737724a63bf7872e211870901..d0ce99f3e9f9efcde873b19ed6810adb1a37a2e0 100644 (file)
@@ -176,6 +176,11 @@ func (t *Target) IsOpenbsd() bool {
        return t.HeadType == objabi.Hopenbsd
 }
 
+func (t *Target) IsFreebsd() bool {
+       t.mustSetHeadType()
+       return t.HeadType == objabi.Hfreebsd
+}
+
 func (t *Target) mustSetHeadType() {
        if t.HeadType == objabi.Hunknown {
                panic("HeadType is not set")