अपडेट पर वापस जाएँ
New releaseAug 26, 2026

gosentry v0.4.1

सुरक्षा-केंद्रित Go टूलचेन, अत्याधुनिक फ़ज़िंग क्षमताओं पर केंद्रित।

साझा करें

gosentry

integration tests

gosentry Go टूलचेन का एक सुरक्षा-केंद्रित फोर्क है, जो Go कोडबेस पर अत्याधुनिक फज़िंग अभियानों के लिए कई सुविधाओं को एकीकृत करता है। यदि आप पहले go test -fuzz का उपयोग कर रहे थे, तो आपको इसके विकल्प के रूप में gosentry का उपयोग करना चाहिए। इसमें कई फज़िंग सुधार और बग डिटेक्टर शामिल हैं जो Go टूलचेन में मूल रूप से मौजूद नहीं हैं। नीचे TLDR; देखें। आप संबंधित ब्लॉग लेख यहाँ भी पढ़ सकते हैं।

TLDR (विशेषताएं और विकल्प):

  • struct इनपुट को सीधे फज़ करें (कोई कस्टम पार्सर आवश्यक नहीं)। f.Add(Input{N: 7, S: "hi"}) के साथ सीड जोड़ें, फिर f.Fuzz(func(t *testing.T, in Input) { ... })
  • पूर्णांक ओवरफ्लो पर पैनिक करें और अंकगणितीय समस्याओं का पता लगाएं
  • पथ बाधाओं को हल करने जैसी अत्याधुनिक फज़िंग तकनीकों के लिए LibAFL के साथ फज़ करें
  • बेकार म्यूटेशन से बचने के लिए ग्रामर से इनपुट उत्पन्न/म्यूटेट करें। म्यूटेशन वैध गणितीय संक्रियाएँ उत्पन्न करता है, जैसे X + Y - Z X / U + Z - 14 बन सकता है, X + Yè - Z के बजाय
  • चयनित फ़ंक्शनों पर पैनिक करें (जैसे क्रिटिकल एरर लॉगर) और कॉल होने पर क्रैश करें
  • फज़र को हाल ही में बदली गई पंक्तियों और नए कवरेज पर केंद्रित करें, मुख्य रूप से नए कमिट्स को लक्षित करने के लिए
  • फज़-टाइम पर डेटा रेस पकड़ें
  • फज़-टाइम पर Go लीक पकड़ें
  • फज़-टाइम पर टाइमआउट के साथ अटकी हुई एक्ज़ीक्यूशन पकड़ें
  • एक CLI से फज़ कैंपेन कॉर्पस से HTML कवरेज रिपोर्ट उत्पन्न करें

विषय-सूची

बिल्ड```bash

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

> [!TIP]
> योगदानकर्ता दस्तावेज़:  कोड मैप, अनुशंसित डेव लूप, CI एंट्रीपॉइंट और बेंचमार्क स्क्रिप्ट के लिए `docs/gosentry/index.md` पढ़ें।
> यह फोर्क `golang/go:master` से `master` में PRs खोलने और ऑटो-मर्ज करने के लिए Pull GitHub App का उपयोग करता है, जिससे हम Go टूलचेन के नवीनतम अपडेट से कभी पीछे नहीं रहते हैं।

## फ़ीचर 1: स्ट्रक्चर-जागरूक फ़ज़िंग (स्ट्रक्चर को इनपुट के रूप में फ़ज़ करें)

#### अवलोकन

Go का नेटिव फ़ज़िंग (`go test -fuzz=...`) फ़ज़ पैरामीटर के रूप में केवल स्केलर प्रकारों के एक छोटे समूह का समर्थन करता है (`[]byte`, `string`, संख्याएँ, ...)। gosentry में, आप उन स्केलरों से निर्मित **कंपोज़िट प्रकारों** को भी फ़ज़ कर सकते हैं: स्ट्रक्चर, ऐरे, स्लाइस और पॉइंटर्स।
यह तब उपयोगी है जब आपका कोड स्वाभाविक रूप से संरचित इनपुट लेता है और आप कॉर्पस को सीड और म्यूटेट करने के लिए कस्टम एन्कोडर/डिकोडर नहीं बनाना चाहते हैं।
उदाहरणों के लिए `test/gosentry/examples/multiargs` और `test/gosentry/examples/composite` देखें।

#### सरल उदाहरण```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")
		}
	})
}
struct seeds (f.Add) और struct फज़िंग कैसे काम करते हैं (गोंद की परत)

Go का native fuzzer किसी struct मान को सीधे फज़ नहीं कर सकता (यह केवल scalar प्रकारों की छोटी सूची को mutate करना जानता है)। gosentry एक छोटी गोंद-परत जोड़ता है: जब आपका fuzz target composite प्रकारों (जैसे Input) का उपयोग करता है, gosentry पर्दे के पीछे एक ही []byte फज़ करता है। हर निष्पादन पर, यह उन बाइट्स को आपके struct में डीकोड करता है (फ़ील्ड-दर-फ़ील्ड, slices/arrays/pointers के लिए पुनरावर्ती रूप से) और फिर डीकोड किए गए मान के साथ आपके f.Fuzz कॉलबैक को कॉल करता है। वही एन्कोडिंग seeds के लिए उपयोग होती है, इसलिए f.Add(Input{...}) एक एन्कोडेड []byte corpus entry बन जाता है जिसे fuzzer किसी भी अन्य seed की तरह पुनः उपयोग और mutate कर सकता है।

Fuzzers (LibAFL सहित) raw bytes mutate करते हैं, इसलिए हमें एक ऐसा decoder चाहिए जो किसी भी byte slice को "कुछ" struct मान में बदल सके और आगे बढ़ता रहे। JSON/gob अधिकांश रैंडम इनपुट अस्वीकार कर देंगे (कवरेज के लिए बुरा), और वे unexported फ़ील्ड्स को भी नहीं भरते, जबकि fuzzing अक्सर invariants को तोड़ने से लाभ उठाता है। यह custom format छोटा, तेज़, deterministic और malformed डेटा के प्रति सहिष्णु है।

अंदर से, यह gosentry का अपना simple binary format उपयोग करता है (gob नहीं, JSON नहीं)। कोड src/testing/libafl.go में स्थित है:

  • एन्कोड: libaflMarshalInputs / libaflAppendValue
  • डीकोड: libaflUnmarshalArgs / libaflDecodeValue

एन्कोडिंग नियम (high level):

  • bool: 1 बाइट (0 या 1)
  • Integers: little-endian बाइट्स (int/uint 8 बाइट्स होते हैं)
  • Floats: little-endian में IEEE-754 बिट्स (float32 = 4 बाइट्स, float64 = 8 बाइट्स)
  • string: uvarint(len) फिर raw string बाइट्स
  • []byte: uvarint(len) फिर raw बाइट्स
  • अन्य slices: uvarint(len) फिर प्रत्येक एलिमेंट एन्कोड होता है
  • Structs: फ़ील्ड्स घोषणा क्रम में एन्कोड होते हैं
  • Pointers: 1 बाइट (0 = nil, 1 = मौजूद) फिर pointed value

फ़ीचर 2: पूर्णांक overflow और truncation समस्याओं का पता लगाना

अवलोकन

यह कार्य पहले विकसित go-panikint से प्रेरित है। यह पूर्णांक अंकगणितीय संक्रियाओं के लिए overflow/underflow का पता लगाना और (वैकल्पिक रूप से) पूर्णांक रूपांतरणों के लिए type truncation का पता लगाना जोड़ता है। जब overflow या truncation का पता चलता है, तो विस्तृत त्रुटि संदेश के साथ एक panic ट्रिगर होता है, जिसमें शामिल विशिष्ट संक्रिया प्रकार और पूर्णांक प्रकार शामिल होते हैं।

अंकगणितीय संक्रियाएँ: यह signed और unsigned दोनों प्रकार के पूर्णांकों के लिए जोड़ +, घटाव -, गुणा *, और भाग / को संभालती है। Signed पूर्णांकों के लिए, int8, int16, int32 शामिल हैं। Unsigned पूर्णांकों के लिए, uint8, uint16, uint32, uint64 शामिल हैं। भाग का मामला विशेष रूप से signed पूर्णांकों के लिए MIN_INT / -1 overflow स्थिति का पता लगाता है। int64 और uintptr की अंकगणितीय संक्रियाओं के लिए जाँच नहीं की जाती।

प्रकार truncation का पता लगाना: यह संभावित रूप से हानिपूर्ण (lossy) पूर्णांक प्रकार रूपांतरणों का पता लगाता है। सभी पूर्णांक प्रकारों को कवर करता है: int8, int16, int32, int64, uint8, uint16, uint32, uint64uintptr को प्लेटफ़ॉर्म-निर्भर उपयोग के कारण बाहर रखा गया है। यह डिफ़ॉल्ट रूप से अक्षम है।

Overflow का पता लगाना डिफ़ॉल्ट रूप से सक्षम है। इसे अक्षम करने के लिए, अपने ./make.bash से पहले GOFLAGS='-gcflags=-overflowdetect=false' जोड़ें। आप truncation issues checker को भी इसके साथ सक्षम कर सकते हैं: -gcflags=-truncationdetect=true

यह कैसे काम करता है

यह फ़ीचर कंपाइलर की SSA जनरेशन को पैच करता है ताकि पूर्णांक अंकगणितीय संक्रियाओं और पूर्णांक रूपांतरणों को अतिरिक्त runtime जाँचें मिलें, जो किसी bug का पता चलने पर विस्तृत त्रुटि संदेश के साथ panic करने के लिए runtime में कॉल करती हैं। जाँचें source-location-आधारित फ़िल्टरिंग का उपयोग करके लागू की जाती हैं, ताकि उपयोगकर्ता कोड इंस्ट्रूमेंट किया जाए, जबकि मानक पुस्तकालय फ़ाइलें और निर्भरताएँ (module cache और vendor/) छोड़ दी जाती हैं।

आप इससे संबंधित ब्लॉग पोस्ट यहाँ पढ़ सकते हैं।

गलत सकारात्मक (false positives) को दबाना

किसी विशेष रिपोर्ट को दबाने के लिए संक्रिया वाली ही पंक्ति में या ठीक उसके ऊपर वाली पंक्ति में एक मार्कर जोड़ें:

  • Overflow/underflow: overflow_false_positive
  • Truncation: truncation_false_positive

उदाहरण:```go // overflow_false_positive intentionalOverflow := a + b // truncation_false_positive x := uint8(big) sum2 := a + b // overflow_false_positive x2 := uint8(big) // truncation_false_positive

Sometimes this might not work, that's because Go is in-lining the function. If `// overflow_false_positive` isn't enough, add `//go:noinline` before the signature of your function.

## Feature 3: Panic on selected functions

When fuzzing targets, we may be interested in triggering a panic when certain functions are called. For example, some software may emit `log.error` messages instead of panicking, even though such conditions often indicate states that security researchers would want to detect during fuzzing.
However, these errors are usually handled internally (e.g., through retry or pause mechanisms, or by printing messages to logs), which makes them largely invisible to fuzzers. The objective of this feature is to address this issue.

#### How to use

Compile gosentry, then use the `--panic-on` flag.```bash
./bin/go test -fuzz=FuzzHarness --use-libafl --focus-on-new-code=false --catch-races=false --catch-leaks=false --panic-on="test_go_panicon.(*Logger).Warning,test_go_panicon.(*Logger).Error"

ऊपर दिया गया उदाहरण panic करेगा जब (*Logger).Warning या (*Logger).Error में से किसी को भी कॉल किया जाए (कॉमा-सेपरेटेड सूची)।

चयनित फ़ंक्शंस पर panic सुविधा कैसे काम करती है```text ┌───────────────────────────────────────────────────────────────────────────┐ │ 1) gosentry `go test` │ │ - parses + validates `-panic-on=...` against packages being built │ │ - forwards patterns to the compiler via `-panic-on-call=...` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) `cmd/compile` │ │ - prevents inlining of matching calls so the call stays visible │ │ - SSA pass inserts a call to `runtime.panicOnCall(...)` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) `runtime.panicOnCall` │ │ - panics with: "panic-on-call: func-name" │ └───────────────────────────────────────────────────────────────────────────┘ ``` व्यवहार में, यह किसी भी मेल खाते कॉल साइट को फ़ज़र्स के लिए क्रैश/पैनिक जैसा व्यवहार कराता है (ध्यान दें: केवल स्टैटिक कॉल साइट्स को ही फँसाया जा सकता है)।

फ़ीचर 4: LibAFL अत्याधुनिक फ़ज़िंग

LibAFL पारंपरिक Go फ़ज़र की तुलना में कहीं बेहतर प्रदर्शन करता है। फ़ज़िंग करते समय (go test -fuzz=...), gosentry डिफ़ॉल्ट रूप से LibAFL का उपयोग करता है (runner golibafl/ में)।

स्थिरता नोट: LibAFL मोड में, gosentry GODEBUG=updatemaxprocs=0 को बाध्य करता है (रनटाइम ऑटो GOMAXPROCS अपडेट को अक्षम करता है) ताकि एक आंतरायिक Linux CI क्रैश ("sync: inconsistent mutex state") से बचा जा सके। विवरण misc/gosentry/USE_LIBAFL.md में हैं।

LibAFL (डिफ़ॉल्ट) का उपयोग करते समय, आपको स्पष्ट रूप से चुनना होगा कि git-जागरूक शेड्यूलिंग सक्षम करनी है या नहीं: --focus-on-new-code=true|false। अधिक दस्तावेज़ीकरण इस Markdown फ़ाइल में। आप LibAFL के लिए एक वैकल्पिक JSONC कॉन्फ़िग फ़ाइल भी पास कर सकते हैं (ग्रामर फ़ज़िंग विकल्पों सहित), देखें यहाँ। "stop_all_fuzzers_on_panic": false के साथ, LibAFL प्रत्येक क्रैश को सहेजता है और फ़ज़िंग जारी रखने के लिए अपने क्लाइंट को पुनः आरंभ करता है।```bash ./bin/go test -fuzz=FuzzHarness --focus-on-new-code=false --catch-races=false --catch-leaks=false --libafl-config=path/to/libafl.jsonc # optional --libafl-config

Use `-fuzztime=1m` का उपयोग करके LibAFL अभियान को एक मिनट के बाद रोकें।

LibAFL अभियान कॉर्पस से कवरेज रिपोर्ट निर्माण [Feature 8](#feature-8-generate-go-coverage-reports-from-fuzzing-campaign) में प्रलेखित है।

व्याकरण-आधारित फ़ज़िंग (Nautilus) [Feature 7](#feature-7-grammar-based-fuzzing-nautilus) में प्रलेखित है।

<details>
<summary><strong>Go + LibAFL कैसे आपस में जुड़े हैं</strong></summary>```text
┌───────────────────────────────────────────────────────────────────────────┐
│ 1) gosentry `go test`                                                      │
│    - captures  `testing.F.Fuzz(...)` callback                             │
│    - generates  extra source file: `_libaflmain.go`                       │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 2) Generated bridge: `_libaflmain.go`                                     │
│    - provides libFuzzer-style C ABI entrypoints:                          │
│        LLVMFuzzerInitialize                                               │
│        LLVMFuzzerTestOneInput                                             │
│    - adapts bytes -> Go types -> calls the captured fuzz callback         │
└───────────────┬───────────────────────────────────────────────────────────┘ 
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 3) `libharness.a` (static archive on disk) contains:                      │
│      - compiled objects for all test package (+ dependencies)             │
│      - generated `_testmain.go` + `_libaflmain.go`                        │
│      - LLVMFuzzerInitialize                                               │
│      - LLVMFuzzerTestOneInput                                             │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 4) `golibafl/` (Rust + LibAFL)                                            │
│    env: HARNESS_LIB=/path/to/libharness.a                                 │
│    fuzz loop: mutate input -> LLVMFuzzerTestOneInput(data) -> observe     │
└───────────────────────────────────────────────────────────────────────────┘

--use-libafl मोड में, gosentry libharness.a बनाता है और Rust golibafl रनर libFuzzer एंट्रीपॉइंट्स के माध्यम से इसे इन-प्रोसेस चलाता है। ध्यान दें: HARNESS_LIB किसी भी हार्नेस आर्काइव नाम की ओर संकेत कर सकता है (उदाहरण के लिए --catch-races द्वारा उपयोग किया गया libharness_race.a).

कवरेज इंस्ट्रूमेंटेशन कैसे काम करता है (LibAFL + Go टार्गेट)

--use-libafl मोड में, gosentry कवरेज इंस्ट्रूमेंटेशन सक्षम के साथ Go हार्नेस को कंपाइल करता है। यह कोड में छोटे काउंटर जोड़ता है जो आपके प्रोग्राम के विभिन्न हिस्सों के चलने पर बदलते हैं। जब हार्नेस golibafl के अंदर शुरू होता है, Go रनटाइम इन काउंटरों को LibAFL को उजागर करता है। LibAFL प्रत्येक इनपुट के बाद उन्हें पढ़ता है ताकि देख सके कि कौन सा कोड चला, और अगले म्यूटेशनों को निर्देशित करने के लिए उस कवरेज का उपयोग करता है।

सीमाएँ

चलिए LibAFL उपयोग करने के पीछे की प्रेरणा के बारे में बात करते हैं। go test -fuzz के साथ फ़ज़िंग अत्याधुनिक फ़ज़िंग तकनीकों से बहुत पीछे है। इसका एक अच्छा उदाहरण AFL++ का CMPLOG/Redqueen है। ये सुविधाएँ फ़ज़र्स को कुछ कंस्ट्रेंट्स को हल करने की अनुमति देती हैं। मान लीजिए निम्नलिखित स्निपेट```go if input == "IMARANDOMSTRINGJUSTCMPLOGMEMAN" { panic("this string is illegal") }

SOTA fuzzers जैसे AFL++ या LibAFL उस स्थिति में panic को तुरंत ढूंढ लेंगे। हालाँकि, Go native fuzzer ऐसा नहीं करेगा। यह एक बड़ा अंतर है जो coverage exploration को **बहुत अधिक** सीमित करता है।

नीचे दिया गया बेंचमार्क उन सीमाओं को दर्शाता है। ध्यान दें कि उन बेंचमार्कों को [gosentry-bench-libafl रिपॉज़िटरी](https://github.com/kevin-valerio/gosentry-bench-libafl/tree/main) के माध्यम से **पुनरुत्पादित** और बेहतर किया जा सकता है।

##### बेंचमार्क 1:

नीचे दिया गया चार्ट LibAFL बनाम Go native fuzzer का उपयोग करके Google के [UUID](https://github.com/google/uuid) को फ़ज़िंग करते समय कवर की गई लाइनों की संख्या के विकास को दर्शाता है।
![BENCH1](https://assets.kitploit.com/production/public/readmes/41918/7b1ea005996846c9ee4d7c0d42fee26731050d10b6b21d59c551e4b1b956923e.png "BENCH1")

##### बेंचमार्क 2:

नीचे दिया गया चार्ट LibAFL बनाम Go native fuzzer का उपयोग करके [go-ethereum](https://github.com/ethereum/go-ethereum) को फ़ज़िंग करते समय कवर की गई लाइनों की संख्या के विकास को दर्शाता है।
![BENCH2](https://assets.kitploit.com/production/public/readmes/41918/61aab8540ab8d339307854de6737a405056c3c8ad83a822df40f74e362b93021.png "BENCH2")



#### उदाहरण
आप इसे `test/gosentry/examples/` में कुछ fuzzing harnesses पर आज़मा सकते हैं।```bash
cd test/gosentry/examples/reverse
../../../../bin/go test -fuzz=FuzzReverse --focus-on-new-code=false --catch-races=false --catch-leaks=false

Stop the fuzz campaign with Ctrl+C.

LibAFL आउटपुट निर्देशिका (अभियान पहचान / कॉर्पस पुन: उपयोग)

gosentry LibAFL के अभियान की स्थिति (कॉर्पस, क्रैश, आदि) को Go की फ़ज़ कैश रूट (मोटे तौर पर $(go env GOCACHE)/fuzz) के अंतर्गत संग्रहीत करता है, एक नियतात्मक निर्देशिका में जो समान पैकेज + समान फ़ज़ टारगेट (और समान प्रोजेक्ट रूट) से व्युत्पन्न होती है।

इसका अर्थ है कि समान फ़ज़ अभियान को रोकने (Ctrl+C) और पुनः प्रारंभ करने पर, डिफ़ॉल्ट रूप से पिछले LibAFL queue/ कॉर्पस से जारी रहेगा।

पथ रन के अंत में मुद्रित होता है:```text libafl output dir: /full/path/to/.../fuzz//libafl//

नोट्स:
- `<harness>` फ़ज़ टारगेट का नाम है जब `-fuzz` एक साधारण पहचानकर्ता हो जैसे `FuzzXxx` (या `^FuzzXxx$`), अन्यथा यह `pattern-<hash>` होता है।
- कवरेज जनरेशन (`--generate-coverage`) सही `queue/` कॉर्पस खोजने के लिए उसी नियम का उपयोग करता है, इसलिए इसे उसी पैकेज से उसी `-fuzz=...` के साथ चलाया जाना चाहिए।

## सुविधा 5: Git-blame-उन्मुख फ़ज़िंग (प्रयोगात्मक)

#### अवलोकन

कवरेज-निर्देशित फ़ज़िंग नए पथों की खोज में बहुत अच्छी है, लेकिन यह सभी कवर किए गए कोड को समान रूप से दिलचस्प मानती है। बड़े कोडबेस का फ़ज़िंग करते समय, आप फ़ज़र को हाल ही में संशोधित कोड की ओर झुकाना चाह सकते हैं, जहां रिग्रेशन और बग्स उत्पन्न होने की अधिक संभावना होती है। LibAFL मोड में, gosentry `git blame` का उपयोग करके उन इनपुटों को प्राथमिकता दे सकता है जो हाल ही में बदली गई पंक्तियों को निष्पादित करते हैं (जबकि कवरेज मार्गदर्शन को प्राथमिक संकेत के रूप में बनाए रखता है)।

यह कार्य [LibAFL-git-aware](https://github.com/kevin-valerio/LibAFL-git-aware) से पिछले कार्य पर आधारित है। सभी तकनीकी गहराई से जुड़े विवरण वहाँ प्रलेखित हैं।

#### उपयोग कैसे करें

`--focus-on-new-code=true` के साथ git-aware शेड्यूलिंग सक्षम करें:```bash
./bin/go test -fuzz=FuzzHarness --use-libafl --focus-on-new-code=true --catch-races=false --catch-leaks=false

इस मोड को कवरेज काउंटरों को स्रोत file:line पर वापस मैप करने के लिए git (git blame चलाने के लिए) और go tool addr2line की आवश्यकता होती है।

git-blame-उन्मुख फ़ज़िंग कैसे काम करता है```text ┌───────────────────────────────────────────────────────────────────────────┐ │ 1) gosentry `go test -fuzz` │ │ - builds `libharness.a` (contains `go.o` + `.go.fuzzcntrs`) │ │ - runs `golibafl` with `GOLIBAFL_FOCUS_ON_NEW_CODE=1` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) `golibafl` generates a cached "git recency map" │ │ - maps coverage counters -> (file:line) via `go tool addr2line` │ │ - runs `git blame` to get a timestamp per line │ │ - stores timestamps in `git_recency_map.bin` │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) LibAFL scheduler uses the recency map │ │ - coverage decides what enters the corpus │ │ - among the corpus, prioritize inputs that hit newer lines │ └───────────────────────────────────────────────────────────────────────────┘ ```
gosentry git_recency_map.bin कैसे बनाता है

.go.fuzzcntrs वह लिंकर सेक्शन है जिसमें Go के libFuzzer-शैली 8-बिट कवरेज काउंटर रहते हैं (-gcflags=all=-d=libfuzzer द्वारा सक्षम); प्रत्येक बाइट दर्शाता है कि "यह इंस्ट्रूमेंटेड स्थान कितनी बार हिट हुआ"। जब --focus-on-new-code=true होता है, तो golibafl निम्न प्रकार से git_recency_map.bin उत्पन्न करता है:

  1. libharness.a से go.o निकालना।
  2. काउंटर संख्या N प्राप्त करने के लिए .go.fuzzcntrs सेक्शन का आकार पढ़ना।
  3. प्रत्येक काउंटर इंडेक्स का पता पुनर्प्राप्त करने के लिए .go.fuzzcntrs प्रतीकों को संदर्भित करने वाले .text रिलोकेशन को स्कैन करना।
  4. go tool addr2line का उपयोग करके प्रत्येक पते को file:line में हल करना।
  5. प्रति पंक्ति committer-time प्राप्त करने के लिए git blame --line-porcelain चलाना।
  6. git_recency_map.bin को u64 head_time + u64 N + N * u64 timestamps (लिटिल-एंडियन) के रूप में लिखना। अनमैप की गई प्रविष्टियाँ टाइमस्टैम्प 0 उपयोग करती हैं।
बेंचमार्क 1 (go-ethereum / geth): बेसलाइन बनाम git-जागरूक

misc/gosentry/bench_focus_on_new_code_geth.sh --trials 5 --warmup 600 --timeout 200 के साथ निष्पादित किया गया।```text gitaware_5: crash (7122ms) baseline results: trial 1: crash (107747ms) trial 2: crash (146415ms) trial 3: crash (37902ms) trial 4: crash (154034ms) trial 5: timeout (200000ms) baseline crashes: 4/5 (timeouts=1, errors=0) baseline median (capped to timeout): 146.415s

git-aware results: trial 1: timeout (200000ms) trial 2: crash (87432ms) trial 3: crash (61733ms) trial 4: crash (157540ms) trial 5: crash (7122ms) git-aware crashes: 4/5 (timeouts=1, errors=0) git-aware median (capped to timeout): 87.432s

</details>

## फीचर 6: फ़ज़-टाइम पर रेस कंडीशन, goroutine लीक और हैंग (टाइमआउट) का पता लगाना

##### पुष्टि किए गए हैंग पकड़ना (LibAFL टाइमआउट)

LibAFL के साथ फ़ज़िंग करते समय, एक हार्नेस निष्पादन **टाइमआउट** हो सकता है (उदाहरण के लिए डेडलॉक / goroutines के अटके रहने, या अत्यंत धीमे पथ के कारण)।

गलत सकारात्मक परिणाम कम करने के लिए, gosentry टाइमआउट को हैंग उम्मीदवार मानता है और टाइमआउट किए गए इनपुट को बड़े टाइमआउट के साथ कुछ बार रीप्ले करके इसकी पुष्टि करता है। पुष्टि किए गए हैंग पर, gosentry इनपुट को `<libafl output dir>/hangs/` में लिखता है और फ़ज़ अभियान रोक देता है (इसे बग/क्रैश की तरह मानता है)।

बाहर निकलने से पहले, `golibafl` क्रैश/हैंग करने वाले इनपुट को कम करने का प्रयास करता है (best-effort; हैंग कुल ~60s तक सीमित हैं)।

नोट: हैंग पुष्टि प्रारंभिक कॉर्पस आयात/निर्माण के दौरान भी चलती है, इसलिए जो टार्गेट हर इनपुट पर टाइमआउट करते हैं उन्हें नियतात्मक रूप से भी पहचाना जा सकता है।

यह `--libafl-config` के माध्यम से कॉन्फ़िगर किया जाता है:
- `catch_hangs` (डिफ़ॉल्ट: `true`)
- `hang_timeout_ms` (डिफ़ॉल्ट: `10000`)
- `hang_confirm_runs` (डिफ़ॉल्ट: `3`)

##### डेटा रेस पकड़ना (`--catch-races`)

gosentry एक अलग `-race` रीप्ले लूप चला सकता है जो LibAFL `queue/` निर्देशिका को देखता है और नए खोजे गए सीड्स को `GORACE=halt_on_error=1` के साथ रीप्ले करता है।

रीप्ले लूप केवल-रीप्ले के लिए एक अलग `-race` हार्नेस आर्काइव बनाता है (बिना फ़ज़ कवरेज इंस्ट्रुमेंटेशन के)।

जब रीप्ले के दौरान डेटा रेस का पता चलता है, gosentry `catch-races:` सारांश और रीप्रो कमांड से पहले पूरी रेस डिटेक्टर रिपोर्ट प्रिंट करता है।

नोट: Go का रेस डिटेक्टर केवल **एकल हार्नेस निष्पादन के अंदर** डेटा रेस का पता लगाता है (एक ही प्रक्रिया में goroutines के बीच बिना उचित सिंक्रोनाइज़ेशन के एक ही मेमोरी तक पहुँचने वाली रेस)। `--catch-races` उन रेसों को चूक जाएगा यदि सीड रेसी कंकररेंसी को ट्रिगर नहीं करता है, और यह क्रॉस-प्रोसेस रेसों का पता नहीं लगाता है।

<details>
<summary><strong>डेटा रेस मोड कैसे काम करता है</strong></summary>

यह मोड `go test` (समान पैरेंट प्रक्रिया) के अंदर एक छोटा मॉनिटर शुरू करता है, और यह पूरे फ़ज़ अभियान के दौरान चलता है।

- कब: मुख्य LibAFL फ़ज़िंग प्रक्रिया शुरू होने से पहले, gosentry रीप्ले हार्नेस + रनर बनाता है।
- निगरानी: फ़ज़िंग शुरू होने से पहले, gosentry `<libafl output dir>/queue/` की प्रारंभिक सामग्री का स्नैपशॉट एक `seen` सेट में लेता है। फिर एक goroutine हर ~1s में `<libafl output dir>/queue/` को पोल करता है और केवल नए निर्मित सीड्स रीप्ले करता है (डॉटफ़ाइल्स और `*.metadata` को छोड़ देता है)।```text
Legend: output/... = <libafl output dir>/...

┌───────────────────────────────────────────────────────────────────────────┐
│ 1) Main LibAFL fuzzing run                                                 │
│    - `golibafl` writes new seeds to `output/queue/`                        │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 2) `--catch-races` sidecar setup                                           │
│    - builds replay harness: `libharness_race.a` (`go test -race ...`)      │
│    - builds replay runner: `golibafl-race` (linked against race harness)   │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 3) Replay loop                                                             │
│    - polls `output/queue/` for new seeds                                   │
│    - runs: `GORACE=halt_on_error=1 golibafl-race run --input <seed>`       │
│      (2 workers × 3 repeats per seed)                                      │
└───────────────┬───────────────────────────────────────────────────────────┘
                v
┌───────────────────────────────────────────────────────────────────────────┐
│ 4) On "DATA RACE"                                                          │
│    - prints the race detector report                                       │
│    - copies seed to `output/races/`                                        │
│    - stops the fuzz campaign (treat as bug/crash)                          │
└───────────────────────────────────────────────────────────────────────────┘
गोरूटीन लीक पकड़ना (--catch-leaks)

gosentry goleak रीप्ले लूप भी चला सकता है जो LibAFL queue/ डायरेक्टरी पर नज़र रखता है और go.uber.org/goleak सक्षम रहते हुए नई खोजी गई सीड्स को रीप्ले करता है।

गोरूटीन लीक का पता चलने पर, gosentry सटीक सीड पथ प्रिंट करता है और उसे <libafl output dir>/leaks/ में कॉपी करता है।

नोट: goleak गोरूटीन लीक के लिए है, मेमोरी लीक के लिए नहीं।

गोरूटीन लीक मोड कैसे काम करता है

यह मोड go test के अंदर एक छोटा मॉनिटर भी शुरू करता है (उसी पैरेंट प्रोसेस में), और यह पूरे फ़ज़ अभियान के दौरान चलता है।

  • निगरानी: एक गोरूटीन हर ~1 सेकंड में <libafl output dir>/queue/ को पोल करता है और प्रत्येक नई सीड को GOSENTRY_LIBAFL_CATCH_LEAKS=1 के साथ रीप्ले करता है (प्रत्येक निष्पादन के बाद go.uber.org/goleak सक्षम करता है)।```text Legend: output/... = /...

┌───────────────────────────────────────────────────────────────────────────┐ │ 1) Main LibAFL fuzzing run │ │ - golibafl writes new seeds to output/queue/ │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) --catch-leaks sidecar setup │ │ - builds replay runner: golibafl-leak (linked against the harness) │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) Replay loop │ │ - polls output/queue/ for new seeds │ │ - runs: GOSENTRY_LIBAFL_CATCH_LEAKS=1 golibafl-leak run --input <seed>│ │ (enables go.uber.org/goleak checks after each execution) │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 4) On "catch-leaks: detected goroutine leak" │ │ - copies seed to output/leaks/ │ │ - stops the fuzz campaign (treat as bug/crash) │ └───────────────────────────────────────────────────────────────────────────┘

</details>


#### उपयोग कैसे करें

`--catch-leaks=true` के साथ goroutine leak कैचिंग या `--catch-races=true` के साथ race कैचिंग सक्षम करें```bash
./bin/go test -fuzz=FuzzHarness --use-libafl --focus-on-new-code=false --catch-races=true --catch-leaks=true

Feature 7: व्याकरण-आधारित फ़ज़िंग (Nautilus)

अवलोकन

बाइट-स्तरीय फ़ज़िंग बढ़िया है, लेकिन पार्सर और फ़ाइल प्रारूपों को अक्सर संरचित इनपुट की आवश्यकता होती है। --use-grammar के साथ, gosentry LibAFL के Nautilus व्याकरण म्यूटेटर का उपयोग करके उन इनपुटों को उत्पन्न और म्यूटेट करता है जो उपयोगकर्ता-प्रदत्त व्याकरण (JSON प्रारूप) के अनुरूप होते हैं, और उन्हें आपके नियमित Go फ़ज़ हार्नेस (testing.F.Fuzz) में फ़ीड करता है।

व्याकरण मोड में, LibAFL फिर भी सामान्य कवरेज-निर्देशित लूप चलाता है (कॉर्पस सीड चुनें → म्यूटेट करें → निष्पादित करें → कवरेज बढ़ाने वाले इनपुट रखें)। रनर Nautilus म्यूटेशन (सीड → व्याकरण ट्री → म्यूटेट → अनपार्स) के साथ-साथ (डिफ़ॉल्ट रूप से) एक CMPLOG-निर्देशित, I2S-जैसा चरण जोड़ता है जो रनटाइम तुलनाओं के आधार पर Nautilus लीफ टर्मिनल को फिर से लिखता है। यह इनपुट्स को व्याकरण-मान्य रखता है (यह व्याकरण मोड में कच्चे बाइट-स्तरीय हावक/टोकन चरण नहीं चलाता)। आप --libafl-config में nautilus_cmplog_i2s=false के माध्यम से CMPLOG/I2S चरण को अक्षम कर सकते हैं (बाइट-स्तरीय फ़ज़िंग अभी भी CMPLOG/I2S को हमेशा चालू रखती है)।

[!NOTE] व्याकरण मोड आमतौर पर बाइट-स्तरीय फ़ज़िंग की तुलना में धीमा होता है। यह एक ट्रेड-ऑफ है: अधिक संरचना बनाम प्रति सेकंड कम निष्पादन।

सर्वोत्तम परिणामों के लिए, एक-तर्क फ़ज़ कॉलबैक का उपयोग करें जो या तो बाइट स्लाइस ([]byte) या string लेता है:```go f.Fuzz(func(t testing.T, data []byte) { / parse data */ }) // or: f.Fuzz(func(t testing.T, s string) { / parse s */ })

ग्रामर मोड एकल इनपुट आर्गुमेंट (`[]byte` या `string`) के साथ सबसे अच्छा काम करता है। मल्टी-आर्ग फ़ज़ कॉलबैक के कारण gosentry अंतर्निहित बाइट बफ़र को अलग-अलग मानों में डिकोड कर देता है, इसलिए मूल ग्रामर-जनरेटेड टेक्स्ट बरकरार नहीं रहता।

> [!NOTE]
> ग्रामर मोड फिर भी **बाइट्स/स्ट्रिंग्स** उत्पन्न करता है। यदि आपको संरचित इनपुट चाहिए (या आप डिफरेंशियल फ़ज़िंग कर रहे हैं), तो आपका हार्नेस वह जगह है जहाँ आप `data` को डोमेन मानों में बदलते हैं (parse/unmarshal)। (ग्रामर मोड के बाहर, gosentry बाइट्स से डिकोड करके composite Go > types को भी फ़ज़ कर सकता है; देखें [सुविधा 1](#feature-1-struct-aware-fuzzing-fuzz-structs-as-inputs)।)

आप Nautilus को `--libafl-config` के माध्यम से ट्यून कर सकते हैं (केवल `--use-grammar` के साथ उपयोग होता है): `nautilus_max_len` और `nautilus_cmplog_i2s` (`misc/gosentry/libafl.config.jsonc` देखें)।

<details>
<summary><strong>बेंचमार्क: Nautilus ग्रामर CMPLOG/I2S चरण (चालू बनाम बंद)</strong></summary>

Feb 17, 2026 को रिपॉज़िटरी के JSON ग्रामर उदाहरण का उपयोग करके निष्पादित किया गया (`test/gosentry/examples/grammar_json`, `FuzzGrammarJSON`, ग्रामर `testdata/JSON.json`)।

परिणाम (LibAFL `UserStats`):

| मोड | `nautilus_cmplog_i2s` | रन टाइम | निष्पादन | निष्पादन/सेकंड | एजेस |
|---|---:|---:|---:|---:|---:|
| चालू | `true` | 1m-5s | 103818 | 1.586k | 388/8008 (4%) |
| बंद | `false` | 1m-0s | 256659 | 4.251k | 388/8008 (4%) |

नोट: `edges` LibAFL का कवरेज मैप एजेस है, Go सोर्स लाइनें नहीं।

</details>

कुछ जनरेटेड इनपुट प्रिंट करने के लिए `GOSENTRY_VERBOSE_AFL=1` सेट करें। **हर** ग्रामर-मोड निष्पादन को `GOLIBAFL_MUTATED_INPUT "..."` के रूप में प्रिंट करने के लिए `GOSENTRY_VERBOSE_AFL_ALL_INPUTS=1` सेट करें (बहुत शोरगुल भरा)।

#### ग्रामर लेखन सहायक उपकरण

यदि आपको अपने स्वयं के टार्गेट फॉर्मेट/प्रोटोकॉल के लिए एक नया Nautilus JSON ग्रामर बनाने की आवश्यकता है, तो gosentry निम्नलिखित प्रदान करता है:

- एक LLM-तैयार प्रॉम्प्ट: [misc/gosentry/nautilus/prompt.md](https://github.com/trailofbits/gosentry/blob/HEAD/misc/gosentry/nautilus/prompt.md)
- उदाहरण ग्रामरों का एक छोटा सेट: [misc/gosentry/nautilus/examples/](https://github.com/trailofbits/gosentry/blob/HEAD/misc/gosentry/nautilus/examples/)

<details>
<summary><strong>Go फ़ज़ हार्नेस उदाहरण (JSON)</strong></summary>```go
func FuzzGrammarJSON(f *testing.F) {
	f.Fuzz(func(t *testing.T, data []byte) {
		dec := json.NewDecoder(bytes.NewReader(data))
		dec.UseNumber()

		var v any
		if err := dec.Decode(&v); err != nil {
			t.Fatalf("invalid JSON: %v", err)
		}
		if err := dec.Decode(&struct{}{}); err != io.EOF {
			t.Fatalf("invalid JSON: trailing data")
		}
	})
}

डिफरेंशियल फ़ज़िंग हार्नेस की रूपरेखा (दो पार्सर):```go f.Fuzz(func(t *testing.T, data []byte) { gotA, errA := ParseA(data) gotB, errB := ParseB(data) if (errA == nil) != (errB == nil) { t.Fatalf("parser disagreement: A=%v B=%v", errA, errB) } _ = gotA _ = gotB })

</details>

<details>
<summary><strong>उदाहरण: एक "वास्तविक इनपुट भाषा" की ग्रामर फज़िंग (कोई कस्टम एनकोडर नहीं)</strong></summary>

यह उदाहरण एक छोटे अंकगणितीय एक्सप्रेशन इवैल्यूएटर को ग्रामर से **मान्य एक्सप्रेशन** उत्पन्न करके फज़ करता है। यहाँ कोई तदर्थ "struct to bytes" एन्कोडिंग नहीं है: फज़र उसी प्रकार का इनपुट उत्पन्न करता है जिसे आपका कोड सामान्यतः पार्स करता है।

हार्नेस (ग्रामर मोड में 1-arg `string` इनपुट सबसे अच्छा काम करता है):```go
func FuzzExprEval(f *testing.F) {
	f.Add("1+2")
	f.Add("(3*4)-5")

	f.Fuzz(func(t *testing.T, expr string) {
		// Parse+eval your language/protocol.
    // You can be **sure** that `expr` will always be a valid math operation. Just decode/parse/unmarshall it afterwards. 
		_, _ = Eval(expr)
	})
}

व्याकरण रूपरेखा (Nautilus JSON प्रारूप):```json [ ["Expr", "{Term}"], ["Expr", "{Term}+{Expr}"], ["Expr", "{Term}-{Expr}"], ["Term", "{Factor}"], ["Term", "{Factor}*{Term}"], ["Factor", "{Num}"], ["Factor", "({Expr})"], ["Num", "0"], ["Num", "1"], ["Num", "2"], ["Num", "3"] ]

</details>

<details>
<summary><strong>Nautilus JSON ग्रामर उदाहरण (छोटा JSON सबसेट)</strong></summary>

यह `--grammar=...` द्वारा अपेक्षित फ़ाइल प्रारूप है:
- ग्रामर नियमों की एक JSON सरणी है: `["NonTerm", "RHS"]`.
- गैर-टर्मिनल नाम बड़े अक्षर से शुरू होने चाहिए (`Value`, `Object`, ...).
- RHS में किसी अन्य नियम को संदर्भित करने के लिए `{NonTerm}` का उपयोग करें.
- `{` और `}` गैर-टर्मिनल संदर्भों के लिए आरक्षित हैं; लिटरल ब्रेसेज़ को आउटपुट करने के लिए, RHS स्ट्रिंग में `\\{` और `\\}` का उपयोग करें.```json
[
  ["Json", "{Value}"],
  ["Value", "null"],
  ["Value", "{String}"],
  ["String", "\"{Chars}\""],
  ["Chars", ""],
  ["Chars", "{Char}{Chars}"],
  ["Char", "a"],
  ["Char", "b"]
]
gosentry में grammar fuzzing कैसे काम करता है```text Legend: output/... = /...

┌───────────────────────────────────────────────────────────────────────────┐ │ 0) gosentry go test -fuzz=FuzzXxx (LibAFL + --use-grammar) │ │ - captures your testing.F.Fuzz callback + its parameter types │ │ - builds libharness.a (libFuzzer-style entrypoints for LibAFL) │ │ - runs golibafl fuzz ... --use-grammar --grammar ... │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 1) golibafl (Rust + LibAFL) fuzzes the Go harness in-process │ │ - loads libharness.a via HARNESS_LIB=... │ │ - observers: edges + time (+ cmplog for comparisons) │ │ - feedback/objective: coverage/time/crash (and optional hang handling) │ │ - scheduler selects a corpus seed (coverage-guided) │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 2) Nautilus (in-process, per client) │ │ - loads the JSON grammar into a Nautilus context │ │ - fuzz loop stage: parse seed -> mutate tree -> unparse to bytes │ │ - if the seed is not parseable: fall back to generation-from-scratch │ └───────────────┬───────────────────────────────────────────────────────────┘ v ┌───────────────────────────────────────────────────────────────────────────┐ │ 3) Grammar mode stages │ │ - initial corpus: if input dir empty, call generate N times │ │ - fuzz loop: corpus seed -> grammar mutate -> exec harness │ │ - new coverage inputs are added to the on-disk corpus (output/queue/) │ └───────────────────────────────────────────────────────────────────────────┘

</details>

सीमाएँ (वर्तमान ग्लू):
- ग्रामर मोड एकल इनपुट आर्ग्युमेंट के साथ सबसे अच्छा काम करता है; मल्टी-आर्ग फ़ज़ टारगेट अंतर्निहित बाइट बफ़र को अलग-अलग मानों में डिकोड करेंगे।
- अभी तक दो कॉर्पस सीड्स के बीच कोई ग्रामर पुनर्संयोजन/क्रॉसओवर नहीं है (म्यूटेशन सिंगल-सीड है)।

## फीचर 8: फ़ज़िंग अभियान से Go कवरेज रिपोर्ट जनरेट करें

LibAFL फ़ज़ अभियान चलाने के बाद (या उसके दौरान), gosentry वर्तमान LibAFL **क्यू कॉर्पस** को रीप्ले करके Go कवरेज रिपोर्ट जनरेट कर सकता है (बिना फ़ज़िंग के)।```bash
# Same package + same fuzz target as your fuzz campaign:
./bin/go test -fuzz=FuzzHarness --generate-coverage .

यह <libafl output dir>/queue/ से इनपुट्स को रीप्ले करता है और cover.out और cover.html लिखता है।

ट्रॉफियाँ

ये बग्स gosentry की grammar fuzzing सुविधा का उपयोग करके differential-fuzzing अभियान चलाकर पाए गए थे।

Optimism

REVM

श्रेय

श्रेणियाँ