Skip to content

cmd/compile, cmd/link: use libFuzzer 8-bit instead of extra counters #51318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/cmd/compile/internal/gc/obj.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ func ggloblnod(nam *ir.Name) {
} else {
base.Ctxt.Globl(s, size, flags)
}
if nam.LibfuzzerExtraCounter() {
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
if nam.Libfuzzer8BitCounter() {
s.Type = objabi.SLIBFUZZER_8BIT_COUNTER
}
if nam.Sym().Linkname != "" {
// Make sure linkname'd symbol is non-package. When a symbol is
Expand Down
6 changes: 3 additions & 3 deletions src/cmd/compile/internal/ir/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ const (
nameInlFormal // PAUTO created by inliner, derived from callee formal
nameInlLocal // PAUTO created by inliner, derived from callee local
nameOpenDeferSlot // if temporary var storing info for open-coded defers
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
nameLibfuzzer8BitCounter // if PEXTERN should be assigned to __sancov_cntrs section
nameAlias // is type name an alias
)

Expand All @@ -250,7 +250,7 @@ func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken !=
func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 }
func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
func (n *Name) Libfuzzer8BitCounter() bool { return n.flags&nameLibfuzzer8BitCounter != 0 }

func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) }
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
Expand All @@ -263,7 +263,7 @@ func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken,
func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) }
func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
func (n *Name) SetLibfuzzer8BitCounter(b bool) { n.flags.set(nameLibfuzzer8BitCounter, b) }

// OnStack reports whether variable n may reside on the stack.
func (n *Name) OnStack() bool {
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/compile/internal/ssa/writebarrier.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ func IsSanitizerSafeAddr(v *Value) bool {
// read-only once initialized.
return true
case OpAddr:
return v.Aux.(*obj.LSym).Type == objabi.SRODATA || v.Aux.(*obj.LSym).Type == objabi.SLIBFUZZER_EXTRA_COUNTER
return v.Aux.(*obj.LSym).Type == objabi.SRODATA || v.Aux.(*obj.LSym).Type == objabi.SLIBFUZZER_8BIT_COUNTER
}
return false
}
Expand Down
34 changes: 22 additions & 12 deletions src/cmd/compile/internal/walk/order.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,21 +446,31 @@ func (o *orderState) edge() {
return
}

// Create a new uint8 counter to be allocated in section
// __libfuzzer_extra_counters.
// Create a new uint8 counter to be allocated in section __sancov_cntrs
counter := staticinit.StaticName(types.Types[types.TUINT8])
counter.SetLibfuzzerExtraCounter(true)
// As well as setting SetLibfuzzerExtraCounter, we preemptively set the
// symbol type to SLIBFUZZER_EXTRA_COUNTER so that the race detector
counter.SetLibfuzzer8BitCounter(true)
// As well as setting SetLibfuzzer8BitCounter, we preemptively set the
// symbol type to SLIBFUZZER_8BIT_COUNTER so that the race detector
// instrumentation pass (which does not have access to the flags set by
// SetLibfuzzerExtraCounter) knows to ignore them. This information is
// lost by the time it reaches the compile step, so SetLibfuzzerExtraCounter
// SetLibfuzzer8BitCounter) knows to ignore them. This information is
// lost by the time it reaches the compile step, so SetLibfuzzer8BitCounter
// is still necessary.
counter.Linksym().Type = objabi.SLIBFUZZER_EXTRA_COUNTER

// counter += 1
incr := ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, ir.NewInt(1))
o.append(incr)
counter.Linksym().Type = objabi.SLIBFUZZER_8BIT_COUNTER

// We guarantee that the counter never becomes zero again once it has been
// incremented once. This implementation follows the NeverZero optimization
// presented by the paper:
// "AFL++: Combining Incremental Steps of Fuzzing Research"
// The NeverZero policy avoids the overflow to 0 by setting the counter to one
// after it reaches 255 and so, if an edge is executed at least one time, the entry is
// never 0.
// Another policy presented in the paper is the Saturated Counters policy which
// freezes the counter when it reaches the value of 255. However, a range
// of experiments showed that that decreases overall performance.
o.append(ir.NewIfStmt(base.Pos,
ir.NewBinaryExpr(base.Pos, ir.OEQ, counter, ir.NewInt(0xff)),
[]ir.Node{ir.NewAssignStmt(base.Pos, counter, ir.NewInt(1))},
[]ir.Node{ir.NewAssignOpStmt(base.Pos, ir.OADD, counter, ir.NewInt(1))}))
}

// orderBlock orders the block of statements in n into a new slice,
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/internal/objabi/symkind.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const (
SDWARFLOC
SDWARFLINES
// Coverage instrumentation counter for libfuzzer.
SLIBFUZZER_EXTRA_COUNTER
SLIBFUZZER_8BIT_COUNTER
// Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values.

)
8 changes: 4 additions & 4 deletions src/cmd/internal/objabi/symkind_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions src/cmd/link/internal/ld/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -1782,10 +1782,10 @@ func (state *dodataState) allocateDataSections(ctxt *Link) {
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.end", 0), sect)

// Coverage instrumentation counters for libfuzzer.
if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
sect := state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._counters", 0), sect)
ldr.SetSymSect(ldr.LookupOrCreateSym("internal/fuzz._ecounters", 0), sect)
if len(state.data[sym.SLIBFUZZER_8BIT_COUNTER]) > 0 {
sect := state.allocateNamedSectionAndAssignSyms(&Segdata, "__sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, sym.Sxxx, 06)
ldr.SetSymSect(ldr.LookupOrCreateSym("__start___sancov_cntrs", 0), sect)
ldr.SetSymSect(ldr.LookupOrCreateSym("__stop___sancov_cntrs", 0), sect)
}

if len(state.data[sym.STLSBSS]) > 0 {
Expand Down Expand Up @@ -2558,7 +2558,7 @@ func (ctxt *Link) address() []*sym.Segment {
bss = s
case ".noptrbss":
noptrbss = s
case "__libfuzzer_extra_counters":
case "__sancov_cntrs":
fuzzCounters = s
}
}
Expand Down Expand Up @@ -2677,8 +2677,8 @@ func (ctxt *Link) address() []*sym.Segment {
ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))

if fuzzCounters != nil {
ctxt.xdefine("internal/fuzz._counters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr))
ctxt.xdefine("internal/fuzz._ecounters", sym.SLIBFUZZER_EXTRA_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
ctxt.xdefine("__start___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr))
ctxt.xdefine("__stop___sancov_cntrs", sym.SLIBFUZZER_8BIT_COUNTER, int64(fuzzCounters.Vaddr+fuzzCounters.Length))
}

if ctxt.IsSolaris() {
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/link/internal/ld/elf.go
Original file line number Diff line number Diff line change
Expand Up @@ -1304,7 +1304,7 @@ func (ctxt *Link) doelf() {
shstrtab.Addstring(".data")
shstrtab.Addstring(".bss")
shstrtab.Addstring(".noptrbss")
shstrtab.Addstring("__libfuzzer_extra_counters")
shstrtab.Addstring("__sancov_cntrs")
shstrtab.Addstring(".go.buildinfo")
if ctxt.IsMIPS() {
shstrtab.Addstring(".MIPS.abiflags")
Expand Down
2 changes: 1 addition & 1 deletion src/cmd/link/internal/ld/xcoff.go
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,7 @@ func (f *xcoffFile) asmaixsym(ctxt *Link) {
putaixsym(ctxt, s, TLSSym)
}

case st == sym.SBSS, st == sym.SNOPTRBSS, st == sym.SLIBFUZZER_EXTRA_COUNTER:
case st == sym.SBSS, st == sym.SNOPTRBSS, st == sym.SLIBFUZZER_8BIT_COUNTER:
if ldr.AttrReachable(s) {
data := ldr.Data(s)
if len(data) > 0 {
Expand Down
38 changes: 19 additions & 19 deletions src/cmd/link/internal/sym/symkind.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const (
SXCOFFTOC
SBSS
SNOPTRBSS
SLIBFUZZER_EXTRA_COUNTER
SLIBFUZZER_8BIT_COUNTER
STLSBSS
SXREF
SMACHOSYMSTR
Expand Down Expand Up @@ -126,24 +126,24 @@ const (
// AbiSymKindToSymKind maps values read from object files (which are
// of type cmd/internal/objabi.SymKind) to values of type SymKind.
var AbiSymKindToSymKind = [...]SymKind{
objabi.Sxxx: Sxxx,
objabi.STEXT: STEXT,
objabi.SRODATA: SRODATA,
objabi.SNOPTRDATA: SNOPTRDATA,
objabi.SDATA: SDATA,
objabi.SBSS: SBSS,
objabi.SNOPTRBSS: SNOPTRBSS,
objabi.STLSBSS: STLSBSS,
objabi.SDWARFCUINFO: SDWARFCUINFO,
objabi.SDWARFCONST: SDWARFCONST,
objabi.SDWARFFCN: SDWARFFCN,
objabi.SDWARFABSFCN: SDWARFABSFCN,
objabi.SDWARFTYPE: SDWARFTYPE,
objabi.SDWARFVAR: SDWARFVAR,
objabi.SDWARFRANGE: SDWARFRANGE,
objabi.SDWARFLOC: SDWARFLOC,
objabi.SDWARFLINES: SDWARFLINES,
objabi.SLIBFUZZER_EXTRA_COUNTER: SLIBFUZZER_EXTRA_COUNTER,
objabi.Sxxx: Sxxx,
objabi.STEXT: STEXT,
objabi.SRODATA: SRODATA,
objabi.SNOPTRDATA: SNOPTRDATA,
objabi.SDATA: SDATA,
objabi.SBSS: SBSS,
objabi.SNOPTRBSS: SNOPTRBSS,
objabi.STLSBSS: STLSBSS,
objabi.SDWARFCUINFO: SDWARFCUINFO,
objabi.SDWARFCONST: SDWARFCONST,
objabi.SDWARFFCN: SDWARFFCN,
objabi.SDWARFABSFCN: SDWARFABSFCN,
objabi.SDWARFTYPE: SDWARFTYPE,
objabi.SDWARFVAR: SDWARFVAR,
objabi.SDWARFRANGE: SDWARFRANGE,
objabi.SDWARFLOC: SDWARFLOC,
objabi.SDWARFLINES: SDWARFLINES,
objabi.SLIBFUZZER_8BIT_COUNTER: SLIBFUZZER_8BIT_COUNTER,
}

// ReadOnly are the symbol kinds that form read-only sections. In some
Expand Down
8 changes: 4 additions & 4 deletions src/cmd/link/internal/sym/symkind_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 34 additions & 1 deletion src/runtime/libfuzzer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

package runtime

import _ "unsafe" // for go:linkname
import "unsafe"

func libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
func libfuzzerCall(fn *byte, arg0, arg1 uintptr)

func libfuzzerTraceCmp1(arg0, arg1 uint8) {
Expand Down Expand Up @@ -42,6 +43,22 @@ func libfuzzerTraceConstCmp8(arg0, arg1 uint64) {
libfuzzerCall(&__sanitizer_cov_trace_const_cmp8, uintptr(arg0), uintptr(arg1))
}

var pcTables []byte

func init() {
libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_8bit_counters_init, &__start___sancov_cntrs, &__stop___sancov_cntrs)
start := unsafe.Pointer(&__start___sancov_cntrs)
end := unsafe.Pointer(&__stop___sancov_cntrs)

// PC tables are arrays of ptr-sized integers representing pairs [PC,PCFlags] for every instrumented block.
// The number of PCs and PCFlags is the same as the number of 8-bit counters. Each PC table entry has
// the size of two ptr-sized integers. We allocate one more byte than what we actually need so that we can
// get a pointer representing the end of the PC table array.
size := (uintptr(end)-uintptr(start))*unsafe.Sizeof(uintptr(0))*2 + 1
pcTables = make([]byte, size)
libfuzzerCallWithTwoByteBuffers(&__sanitizer_cov_pcs_init, &pcTables[0], &pcTables[size-1])
}

//go:linkname __sanitizer_cov_trace_cmp1 __sanitizer_cov_trace_cmp1
//go:cgo_import_static __sanitizer_cov_trace_cmp1
var __sanitizer_cov_trace_cmp1 byte
Expand Down Expand Up @@ -73,3 +90,19 @@ var __sanitizer_cov_trace_const_cmp4 byte
//go:linkname __sanitizer_cov_trace_const_cmp8 __sanitizer_cov_trace_const_cmp8
//go:cgo_import_static __sanitizer_cov_trace_const_cmp8
var __sanitizer_cov_trace_const_cmp8 byte

//go:linkname __sanitizer_cov_8bit_counters_init __sanitizer_cov_8bit_counters_init
//go:cgo_import_static __sanitizer_cov_8bit_counters_init
var __sanitizer_cov_8bit_counters_init byte

//go:linkname __start___sancov_cntrs __start___sancov_cntrs
//go:cgo_import_static __start___sancov_cntrs
var __start___sancov_cntrs byte

//go:linkname __stop___sancov_cntrs __stop___sancov_cntrs
//go:cgo_import_static __stop___sancov_cntrs
var __stop___sancov_cntrs byte

//go:linkname __sanitizer_cov_pcs_init __sanitizer_cov_pcs_init
//go:cgo_import_static __sanitizer_cov_pcs_init
var __sanitizer_cov_pcs_init byte
23 changes: 23 additions & 0 deletions src/runtime/libfuzzer_amd64.s
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,26 @@ call:
CALL AX
MOVQ R12, SP
RET

// void runtime·libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
// Calls C function fn from libFuzzer and passes 2 arguments of type *byte to it.
TEXT runtime·libfuzzerCallWithTwoByteBuffers(SB), NOSPLIT, $0-24
MOVQ fn+0(FP), AX
MOVQ start+8(FP), RARG0
MOVQ end+16(FP), RARG1

get_tls(R12)
MOVQ g(R12), R14
MOVQ g_m(R14), R13

// Switch to g0 stack.
MOVQ SP, R12 // callee-saved, preserved across the CALL
MOVQ m_g0(R13), R10
CMPQ R10, R14
JE call // already on g0
MOVQ (g_sched+gobuf_sp)(R10), SP
call:
ANDQ $~15, SP // alignment for gcc ABI
CALL AX
MOVQ R12, SP
RET
21 changes: 21 additions & 0 deletions src/runtime/libfuzzer_arm64.s
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,24 @@ call:
BL R9
MOVD R19, RSP
RET

// void runtime·libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
// Calls C function fn from libFuzzer and passes 2 arguments of type *byte to it.
TEXT runtime·libfuzzerCallWithTwoByteBuffers(SB), NOSPLIT, $0-24
MOVD fn+0(FP), R9
MOVD start+8(FP), R0
MOVD end+16(FP), R1

MOVD g_m(g), R10

// Switch to g0 stack.
MOVD RSP, R19 // callee-saved, preserved across the CALL
MOVD m_g0(R10), R11
CMP R11, g
BEQ call // already on g0
MOVD (g_sched+gobuf_sp)(R11), R12
MOVD R12, RSP
call:
BL R9
MOVD R19, RSP
RET