Skip to content
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

initial commit for enhancing fuzz tests #2745

Merged
merged 8 commits into from
Nov 28, 2023
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ _test_plugins_fail/%.so: _test_plugins_fail/%.go

.PHONY: fuzz
fuzz: ## run all fuzz tests
for p in $(PACKAGES); do go test -run=NONE -fuzz=Fuzz -fuzztime 30s $$p; done
$(MAKE) -C fuzz $(MAKECMDGOALS)

.PHONY: lint
lint: build staticcheck ## run all linters
Expand Down
21 changes: 21 additions & 0 deletions fuzz/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM amazonlinux:2023

WORKDIR /workspace

ENV PATH="/root/go/bin:$PATH"

COPY . .

RUN dnf install -q -y make clang golang && \
update-alternatives --install /usr/bin/cc cc /usr/bin/clang 20 && \
go install github.com/mdempsky/go114-fuzz-build@latest && \
go mod init fuzz && \
go mod tidy && \
make -s -j $(nproc) && \
dnf autoremove -q -y && \
dnf clean all -q && \
go clean -cache -testcache -modcache -fuzzcache

ENTRYPOINT [ "/usr/bin/make", "fuzz" ]

CMD ["FUZZ_TARGETS=FuzzParseEskip"]
64 changes: 64 additions & 0 deletions fuzz/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
MKDIR = mkdir -p
GO_FUZZ_BUILD ?= go114-fuzz-build

PREFIX ?= $(CURDIR)
ARTIFACTS_PATH = $(PREFIX)/artifacts
DICTIONARY_PATH = $(PREFIX)/dictionaries
CORPUS_PATH = $(PREFIX)/corpus
FUZZ_TARGETS_PATH = $(PREFIX)/fuzz_targets

FUZZ_TARGETS ?= FuzzParseCIDRs FuzzParseEskip FuzzParseFilters \
FuzzParseIngressV1JSON FuzzParseIPCIDRs \
FuzzParseJwt FuzzParsePredicates \
FuzzParseRouteGroupsJSON FuzzServer

FUZZ_SANITIZER ?= address
FUZZ_FORKS ?= 2
FUZZ_MAX_TOTAL_TIME ?= 600
FUZZ_RUNS ?= -1
FUZZER_ARGS ?= -artifact_prefix=$(ARTIFACTS_PATH) \
-rss_limit_mb=2560 -timeout=25 \
-max_total_time=$(FUZZ_MAX_TOTAL_TIME) \
-len_control=0 -detect_leaks=0 -max_len=4096 \
-fork=$(FUZZ_FORKS) -runs=$(FUZZ_RUNS)

ifeq ($(FUZZ_SANITIZER), address)
FUZZ_BUILD_ARGS = -fsanitize=fuzzer -fsanitize=address -fsanitize-address-use-after-scope
else ifeq ($(FUZZ_SANITIZER), undefined)
FUZZ_BUILD_ARGS = -fsanitize=fuzzer -fsanitize=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unsigned-integer-overflow,unreachable,vla-bound,vptr -fno-sanitize-recover=array-bounds,bool,builtin,enum,float-divide-by-zero,function,integer-divide-by-zero,null,object-size,return,returns-nonnull-attribute,shift,signed-integer-overflow,unreachable,vla-bound,vptr
else ifeq ($(FUZZ_SANITIZER), none)
FUZZ_BUILD_ARGS = -fsanitize=fuzzer
else
$(error $(FUZZ_SANITIZER) is invalid sanitizer, available options are address, undefined, none)
endif

export ASAN_OPTIONS = alloc_dealloc_mismatch=0:allocator_may_return_null=1:allocator_release_to_os_interval_ms=500:check_malloc_usable_size=0:detect_container_overflow=1:detect_odr_violation=0:detect_leaks=1:detect_stack_use_after_return=1:fast_unwind_on_fatal=0:handle_abort=1:handle_segv=1:handle_sigill=1:max_uar_stack_size_log=16:print_scariness=1:quarantine_size_mb=10:strict_memcmp=1:symbolize=1:use_sigaltstack=1:dedup_token_length=3
export UBSAN_OPTIONS = print_stacktrace=1:print_summary=1:silence_unsigned_overflow=1:symbolize=1:dedup_token_length=3

.PHONY: help all fuzz clean
default: all

help: ## display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

all: $(FUZZ_TARGETS:=.out) ## build all fuzz binaries

%.a:
$(GO_FUZZ_BUILD) -func $(@:.a=) -o $@ $(FUZZ_TARGETS_PATH)

gosigfuzz/gosigfuzz.o:
$(CC) -c $(@:.o=.c) -o $@

%.out: %.a gosigfuzz/gosigfuzz.o
$(CC) $(FUZZ_BUILD_ARGS) -lresolv $^ -o $@

fuzz: $(FUZZ_TARGETS:=.out) ## run all fuzz tests
for TARGET in $(FUZZ_TARGETS); do \
$(MKDIR) $(CORPUS_PATH)/$$TARGET $(ARTIFACTS_PATH); \
ARGS="$(FUZZER_ARGS)"; \
[ -f "$(DICTIONARY_PATH)/$$TARGET.dict" ] && ARGS="$$ARGS -dict=$(DICTIONARY_PATH)/$$TARGET.dict"; \
$(PREFIX)/$$TARGET.out $$ARGS $(CORPUS_PATH)/$$TARGET; \
done

clean: ## clean temporary files and directories
$(RM) $(PREFIX)/*.out $(PREFIX)/*.a $(PREFIX)/*.h $(PREFIX)/main.*.go gosigfuzz/gosigfuzz.o
3 changes: 3 additions & 0 deletions fuzz/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Fuzzing

This directory contains a set of dictionaries and fuzz targets along with other tooling to fuzz skipper.
188 changes: 188 additions & 0 deletions fuzz/dictionaries/FuzzParseEskip.dict
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
"&&"
"*"
"->"
")"
":"
","
"("
";"
"<shunt>"
"<loopback>"
"<dynamic>"
"<"
">"
"backendIsProxy"
"modRequestHeader"
"setRequestHeader"
"appendRequestHeader"
"dropRequestHeader"
"modResponseHeader"
"setResponseHeader"
"appendResponseHeader"
"dropResponseHeader"
"setContextRequestHeader"
"appendContextRequestHeader"
"setContextResponseHeader"
"appendContextResponseHeader"
"copyRequestHeader"
"copyResponseHeader"
"modPath"
"setPath"
"redirectTo"
"redirectToLower"
"static"
"stripQuery"
"preserveHost"
"status"
"compress"
"decompress"
"setQuery"
"dropQuery"
"inlineContent"
"inlineContentIfStatus"
"flowId"
"xforward"
"xforwardFirst"
"randomContent"
"repeatContent"
"repeatContentHex"
"wrapContent"
"wrapContentHex"
"backendTimeout"
"readTimeout"
"writeTimeout"
"blockContent"
"blockContentHex"
"latency"
"bandwidth"
"chunks"
"backendLatency"
"backendBandwidth"
"backendChunks"
"absorb"
"absorbSilent"
"uniformRequestLatency"
"uniformResponseLatency"
"normalRequestLatency"
"normalResponseLatency"
"histogramRequestLatency"
"histogramResponseLatency"
"logHeader"
"tee"
"teenf"
"teeLoopback"
"sed"
"sedDelim"
"sedRequest"
"sedRequestDelim"
"basicAuth"
"webhook"
"oauthTokeninfoAnyScope"
"oauthTokeninfoAllScope"
"oauthTokeninfoAnyKV"
"oauthTokeninfoAllKV"
"oauthTokenintrospectionAnyClaims"
"oauthTokenintrospectionAllClaims"
"oauthTokenintrospectionAnyKV"
"oauthTokenintrospectionAllKV"
"secureOauthTokenintrospectionAnyClaims"
"secureOauthTokenintrospectionAllClaims"
"secureOauthTokenintrospectionAnyKV"
"secureOauthTokenintrospectionAllKV"
"forwardToken"
"forwardTokenField"
"oauthGrant"
"grantCallback"
"grantLogout"
"grantClaimsQuery"
"jwtValidation"
"oauthOidcUserInfo"
"oauthOidcAnyClaims"
"oauthOidcAllClaims"
"oidcClaimsQuery"
"dropRequestCookie"
"dropResponseCookie"
"requestCookie"
"responseCookie"
"jsCookie"
"consecutiveBreaker"
"rateBreaker"
"disableBreaker"
"admissionControl"
"clientRatelimit"
"ratelimit"
"clusterClientRatelimit"
"clusterRatelimit"
"clusterLeakyBucketRatelimit"
"backendRatelimit"
"ratelimitFailClosed"
"lua"
"corsOrigin"
"headerToQuery"
"queryToHeader"
"disableAccessLog"
"enableAccessLog"
"auditLog"
"unverifiedAuditLog"
"setDynamicBackendHostFromHeader"
"setDynamicBackendSchemeFromHeader"
"setDynamicBackendUrlFromHeader"
"setDynamicBackendHost"
"setDynamicBackendScheme"
"setDynamicBackendUrl"
"apiUsageMonitoring"
"fifo"
"lifo"
"lifoGroup"
"rfcPath"
"rfcHost"
"bearerinjector"
"tracingBaggageToTag"
"stateBagToTag"
"tracingTag"
"tracingTagFromResponse"
"tracingSpanName"
"originMarker"
"fadeIn"
"endpointCreated"
"consistentHashKey"
"consistentHashBalanceFactor"
"opaAuthorizeRequest"
"opaServeResponse"
"healthcheck"
"setFastCgiFilename"
"disableRatelimit"
"unknownRatelimit"
"Path"
"PathSubtree"
"PathRegexp"
"Host"
"HostAny"
"ForwardedHost"
"ForwardedProtocol"
"Weight"
"True"
"False"
"Shutdown"
"Method"
"Methods"
"Header"
"HeaderRegexp"
"Cookie"
"JWTPayloadAnyKV"
"JWTPayloadAllKV"
"JWTPayloadAnyKVRegexp"
"JWTPayloadAllKVRegexp"
"HeaderSHA256"
"After"
"Before"
"Between"
"Cron"
"QueryParam"
"Source"
"SourceFromLast"
"ClientIP"
"Tee"
"Traffic"
"TrafficSegment"
"ContentLengthBetween"
Loading