Torna agli aggiornamenti
New releaseAug 26, 2026

gosentry v0.4.1

Toolchain Go orientata alla sicurezza, focalizzata su capacità di fuzzing all'avanguardia.

Condividi

gosentry

integration tests

gosentry è un fork della toolchain Go incentrato sulla sicurezza, che integra numerose funzionalità per campagne di fuzzing all'avanguardia su codebase Go. Se prima usavi go test -fuzz, dovresti usare gosentry come sostituto. Include vari miglioramenti per il fuzzing e rilevatori di bug che non sono presenti nativamente nella toolchain Go. Vedi TLDR; qui sotto. Puoi anche leggere l'articolo del blog associato qui.

TLDR (funzionalità e opzioni):

  • Esegui il fuzzing direttamente su input di tipo struct (nessun parser personalizzato necessario). Aggiungi seed con f.Add(Input{N: 7, S: "hi"}) e poi f.Fuzz(func(t *testing.T, in Input) { ... }).
  • Va in panic in caso di overflow di interi e rileva problemi aritmetici
  • Fuzza con LibAFL per tecniche di fuzzing all'avanguardia come la risoluzione dei vincoli di percorso
  • Genera/muta input a partire da una grammatica per evitare mutazioni inutili. La mutazione genera un'operazione matematica valida, ad esempio X + Y - Z può diventare X / U + Z - 14 invece di X + Yè - Z
  • Panic su funzioni selezionate (come i logger di errori critici) e crash quando viene chiamata
  • Concentra il fuzzer sulle righe modificate di recente E sulla nuova copertura, per mirare principalmente ai nuovi commit
  • Rileva le data race in fase di fuzzing
  • Rileva i leak di goroutine in fase di fuzzing
  • Rileva esecuzioni bloccate con timeout in fase di fuzzing
  • Genera un report di copertura HTML dal corpus di una campagna di fuzzing con un'unica CLI

Sommario

Compilazione```bash

cd src && ./make.bash # Produces ../bin/go. See GOFLAGS below.

> [!TIP]
> Documentazione per contributori:  leggi `docs/gosentry/index.md` per una mappa del codice, il ciclo di sviluppo consigliato, i punti di ingresso della CI e gli script di benchmark.
> Questo fork utilizza la Pull GitHub App per aprire e unire automaticamente le PR da `golang/go:master` in `master`, assicurandoci di non rimanere mai indietro rispetto agli ultimi aggiornamenti della toolchain Go.

## Funzionalità 1: Fuzzing consapevole delle struct (fuzz di struct come input)

#### Panoramica

Il fuzzing nativo di Go (`go test -fuzz=...`) supporta solo un piccolo insieme di tipi scalari come parametri di fuzz (`[]byte`, `string`, numeri, ...). In gosentry, puoi anche fare fuzz di **tipi compositi** costruiti da quegli scalari: struct, array, slice e puntatori.
Questo è utile quando il tuo codice accetta naturalmente input strutturati e non vuoi costruire un encoder/decoder personalizzato solo per inizializzare e mutare il corpus.
Vedi `test/gosentry/examples/multiargs` e `test/gosentry/examples/composite` per esempi.

#### Esempio semplice```go
type Input struct {
	Data []byte
	S    string
	N    int
	OK   bool
}

func FuzzStructInput(f *testing.F) {
	// Seed the initial corpus with a Go struct (gosentry feature).
	f.Add(Input{Data: []byte("A"), S: "B", N: 7, OK: true})

	f.Fuzz(func(t *testing.T, in Input) {
		if in.OK && in.N == 1337 && in.S == "BOOMMOOB" && bytes.Equal(in.Data, []byte("A")) {
			t.Fatalf("boom")
		}
	})
}
Come funzionano i seed delle struct (f.Add) e il fuzzing delle struct (la colla creata)

Il fuzzer nativo di Go non può fare fuzzing direttamente su un valore struct (sa solo mutare una piccola lista di tipi scalari). gosentry aggiunge un piccolo strato di colla: quando il tuo fuzz target usa tipi compositi (come Input), gosentry esegue il fuzzing su un singolo []byte dietro le quinte. A ogni esecuzione, decodifica quei byte nella tua struct (campo per campo, ricorsivamente per slice/array/puntatori) e poi chiama la callback f.Fuzz con il valore decodificato. La stessa codifica viene usata per i seed, quindi f.Add(Input{...}) diventa una voce di corpus []byte codificata che il fuzzer può riutilizzare e mutare come qualsiasi altro seed.

I fuzzer (incluso LibAFL) mutano byte grezzi, quindi vogliamo un decoder che possa trasformare qualsiasi slice di byte in un valore di struct "qualsiasi" e continuare. JSON/gob rifiuterebbero la maggior parte degli input casuali (male per la copertura), e inoltre non popolano i campi non esportati, mentre il fuzzing trae spesso beneficio dalla rottura degli invarianti. Questo formato personalizzato è piccolo, veloce, deterministico e tollerante ai dati malformati.

Dietro le quinte, usa il semplice formato binario di gosentry (non gob, non JSON). Il codice si trova in src/testing/libafl.go:

  • Encode: libaflMarshalInputs / libaflAppendValue
  • Decode: libaflUnmarshalArgs / libaflDecodeValue

Regole di codifica (a livello generale):

  • bool: 1 byte (0 o 1)
  • Interi: byte little-endian (int/uint sono 8 byte)
  • Float: bit IEEE-754 in little-endian (float32 = 4 byte, float64 = 8 byte)
  • string: uvarint(len) poi byte grezzi della stringa
  • []byte: uvarint(len) poi byte grezzi
  • Altre slice: uvarint(len) poi ogni elemento codificato
  • Struct: campi codificati nell'ordine di dichiarazione
  • Puntatori: 1 byte (0 = nil, 1 = presente) poi il valore puntato

Funzionalità 2: Rilevamento di problemi di overflow e troncamento degli interi

Panoramica

Questo lavoro trae ispirazione dal go-panikint sviluppato in precedenza. Aggiunge il rilevamento di overflow/underflow per le operazioni aritmetiche sugli interi e (opzionalmente) il rilevamento del troncamento di tipo per le conversioni tra interi. Quando viene rilevato overflow o troncamento, viene generato un panic con un messaggio di errore dettagliato, che include il tipo di operazione specifico e i tipi di interi coinvolti.

Operazioni aritmetiche: Gestisce addizione +, sottrazione -, moltiplicazione * e divisione / sia per i tipi interi con segno che senza segno. Per gli interi con segno, copre int8, int16, int32. Per gli interi senza segno, copre uint8, uint16, uint32, uint64. Il caso della divisione rileva specificamente la condizione di overflow MIN_INT / -1 per gli interi con segno. int64 e uintptr non sono controllati per le operazioni aritmetiche.

Rilevamento del troncamento di tipo: Rileva conversioni tra tipi interi potenzialmente con perdita di dati. Copre tutti i tipi interi: int8, int16, int32, int64, uint8, uint16, uint32, uint64. Esclude uintptr a causa dell'uso dipendente dalla piattaforma. Questa funzione è disabilitata per impostazione predefinita.

Categorie