diff --git a/ChangeLog.md b/ChangeLog.md index 524ba78..41465ec 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,62 @@ +# wolfSentry Release 1.2.2 (May 4, 2023) + +Release 1.2.2 of the wolfSentry embedded firewall/IDPS has bug fixes and improvements including: + +## Noteworthy Changes and Additions + +Added C89 pedantic compatibility in core codebase, including unit tests, via `-DWOLFSENTRY_C89`. + +Added error code `IO_FAILED`, returned for various stdio failures that previously returned `SYS_OP_FAILED` or went undetected. + +Refined `wolfsentry_lock_unlock()` so that final unlock while holding a promotion reservation is not an error and implicitly drops the reservation. + +## Bug Fixes and Cleanups + +Cleanups guided by `clang-tidy` and `cppcheck`: fixed a misused retval from `posix_memalign()`, fixed overwritten retvals in `wolfsentry_lock_unlock()`, and effected myriad cleanups to improve clarity and portability. + +Fixed missing assignment of `new->prev` in `wolfsentry_table_clone()`. + +Fixed route metadata coherency in transactional configuration updates: add `wolfsentry_route_copy_metadata()`, and call it from `wolfsentry_context_exchange()`. + +When `wolfsentry_route_event_dispatch*()` results in a default policy fallback, return `USED_FALLBACK` success code. + +Properly release lock promotion reservation in `wolfsentry_config_json_init_ex()` if obtained. + +Fixed several accounting bugs in the lock kernel related to promotion reservations. + +Copy `fallthrough_route` pointer in `wolfsentry_route_table_clone_header()`, rather than improperly trying to clone the fallthrough route. + +## Self-Test Enhancements + +Added new global compiler warnings to `Makefile`: + + * `-Wmissing-prototypes` + * `-Wdeclaration-after-statement` + * `-Wnested-externs` + * `-Wlogical-not-parentheses` + * `-Wpacked-not-aligned` + +Added new targets to `Makefile.analyzers`: + + * `clang-tidy-build-test` + * `cppcheck-analyze` + * `c89-test` + * `m32-c89-test` + * `freertos-arm32-c89-build-test` + * `freertos-arm32-singlethreaded-build-test` + * `sanitize-aarch64-be-test` + * `sanitize-all-no-inline-gcc` + * `no-inline-test` + * `no-alloca-test` + * `release-check` + +Added `WOLFSENTRY_CONFIG_LOAD_FLAG_NO_FLUSH` coverage and an array of should-fail JSON objects to `unittests.c`:`test_json()`. + +Added more arg-not-null and thread-inited checks to thread/lock routines in `src/wolfsentry_util.c`, and corresponding unit test coverage for all null/uninited arg permutations. + +Added assert in release recipe to assure that wolfsentry.h has a version that matches the tagged version. + + # wolfSentry Release 1.2.1 (Apr 5, 2023) Release 1.2.1 of the wolfSentry embedded firewall/IDPS has bug fixes and improvements including: diff --git a/Makefile b/Makefile index 0606b38..8f1a262 100644 --- a/Makefile +++ b/Makefile @@ -315,16 +315,16 @@ test: $(BUILD_TOP)/.tested $(BUILD_TOP)/.tested: $(addprefix $(BUILD_TOP)/tests/,$(UNITTEST_LIST)) ifdef VERY_QUIET - @for test in $(basename $(UNITTEST_LIST)); do $(TEST_ENV) $(VALGRIND) "$(BUILD_TOP)/tests/$$test" >/dev/null; exitcode=$$?; if [ $$exitcode != 0 ]; then echo "$${test} failed" 1>&2; break; fi; done; exit $$exitcode + @for test in $(basename $(UNITTEST_LIST)); do $(TEST_ENV) $(EXE_LAUNCHER) "$(BUILD_TOP)/tests/$$test" >/dev/null; exitcode=$$?; if [ $$exitcode != 0 ]; then echo "$${test} failed" 1>&2; break; fi; done; exit $$exitcode else ifeq "$(V)" "1" - @for test in $(basename $(UNITTEST_LIST)); do echo "$${test}:"; $(TEST_ENV) $(VALGRIND) "$(BUILD_TOP)/tests/$$test"; exitcode=$$?; if [ $$exitcode != 0 ]; then break; fi; echo "$${test} succeeded"; echo; done; if [ "$$exitcode" = 0 ]; then echo 'all subtests succeeded.'; else exit $$exitcode; fi + @for test in $(basename $(UNITTEST_LIST)); do echo "$${test}:"; echo $(TEST_ENV) $(EXE_LAUNCHER) "$(BUILD_TOP)/tests/$$test"; $(TEST_ENV) $(EXE_LAUNCHER) "$(BUILD_TOP)/tests/$$test"; exitcode=$$?; if [ $$exitcode != 0 ]; then break; fi; echo "$${test} succeeded"; echo; done; if [ "$$exitcode" = 0 ]; then echo 'all subtests succeeded.'; else exit $$exitcode; fi else - @for test in $(basename $(UNITTEST_LIST)); do echo -n "$${test}..."; $(TEST_ENV) $(VALGRIND) "$(BUILD_TOP)/tests/$$test" >/dev/null; exitcode=$$?; if [ $$exitcode != 0 ]; then break; fi; echo ' succeeded'; done; if [ "$$exitcode" = 0 ]; then echo 'all subtests succeeded.'; else exit $$exitcode; fi + @for test in $(basename $(UNITTEST_LIST)); do echo -n "$${test}..."; $(TEST_ENV) $(EXE_LAUNCHER) "$(BUILD_TOP)/tests/$$test" >/dev/null; exitcode=$$?; if [ $$exitcode != 0 ]; then break; fi; echo ' succeeded'; done; if [ "$$exitcode" = 0 ]; then echo 'all subtests succeeded.'; else exit $$exitcode; fi endif endif ifdef BUILD_DYNAMIC - @for test in $(UNITTEST_LIST_SHARED); do LD_LIBRARY_PATH=$(BUILD_TOP) $(TEST_ENV) $(VALGRIND) "$(BUILD_TOP)/tests/$$test" >/dev/null || exit $?; done + @for test in $(UNITTEST_LIST_SHARED); do LD_LIBRARY_PATH=$(BUILD_TOP) $(TEST_ENV) $(EXE_LAUNCHER) "$(BUILD_TOP)/tests/$$test" >/dev/null || exit $?; done ifndef VERY_QUIET @echo '$(UNITTEST_LIST_SHARED) succeeded.' endif @@ -414,6 +414,7 @@ CLEAN_RM_ARGS = -f $(BUILD_TOP)/.build_params $(BUILD_TOP)/wolfsentry/wolfsentry .PHONY: release release: @if [[ -z "$(RELEASE)" ]]; then echo "Can't make release -- version isn't known."; exit 1; fi + @cd "$(SRC_TOP)" && git show "$(RELEASE):wolfsentry/wolfsentry.h" | awk '/^#define WOLFSENTRY_VERSION_MAJOR /{major=$$3; next;}/^#define WOLFSENTRY_VERSION_MINOR /{minor=$$3; next;}/^#define WOLFSENTRY_VERSION_TINY /{tiny=$$3; next;} {if ((major != "") && (minor != "") && (tiny != "")) {exit(0);}} END { if ("v" major "." minor "." tiny == "$(RELEASE)") {exit(0);} else {printf("make release: tagged version \"%s\" doesn'\''t match version in header \"v%s.%s.%s\".\n", "$(RELEASE)", major, minor, tiny) > "/dev/stderr"; exit(1);}; }' ifndef VERY_QUIET @echo "generating release archive $${PWD}/wolfsentry-$(RELEASE).zip" endif diff --git a/Makefile.analyzers b/Makefile.analyzers index 5c59a89..d4259f8 100644 --- a/Makefile.analyzers +++ b/Makefile.analyzers @@ -48,19 +48,19 @@ clang-version-test: .PHONY: valgrind valgrind: CFLAGS+=-fno-omit-frame-pointer valgrind: LDFLAGS+=-fno-omit-frame-pointer -valgrind: VALGRIND=valgrind --tool=memcheck --leak-check=full --error-exitcode=10 $(VALGRIND_ARGS) +valgrind: EXE_LAUNCHER=valgrind --tool=memcheck --leak-check=full --error-exitcode=10 $(VALGRIND_ARGS) valgrind: test .PHONY: valgrind-drd valgrind-drd: CFLAGS+=-fno-omit-frame-pointer valgrind-drd: LDFLAGS+=-fno-omit-frame-pointer -valgrind-drd: VALGRIND=valgrind --tool=drd --error-exitcode=10 $(VALGRIND_ARGS) +valgrind-drd: EXE_LAUNCHER=valgrind --tool=drd --error-exitcode=10 $(VALGRIND_ARGS) valgrind-drd: test .PHONY: valgrind-helgrind valgrind-helgrind: CFLAGS+=-fno-omit-frame-pointer valgrind-helgrind: LDFLAGS+=-fno-omit-frame-pointer -valgrind-helgrind: VALGRIND=valgrind --tool=helgrind --error-exitcode=10 $(VALGRIND_ARGS) +valgrind-helgrind: EXE_LAUNCHER=valgrind --tool=helgrind --error-exitcode=10 $(VALGRIND_ARGS) valgrind-helgrind: test .PHONY: valgrind-all @@ -102,7 +102,7 @@ sanitize-no-leak: CFLAGS+=-fsanitize=bounds-strict sanitize-no-leak: LDFLAGS+=-fsanitize=bounds-strict endif -sanitize-no-leak: TEST_ENV+=ASAN_OPTIONS='detect_invalid_pointer_pairs=2:halt_on_error=1:detect_stack_use_after_return=1' UBSAN_OPTIONS='halt_on_error=1' +sanitize-no-leak: TEST_ENV+=ASAN_OPTIONS='detect_leaks=0:detect_invalid_pointer_pairs=2:halt_on_error=1:detect_stack_use_after_return=1' UBSAN_OPTIONS='halt_on_error=1' sanitize-no-leak: test .PHONY: sanitize-thread @@ -177,6 +177,15 @@ sanitize-all-no-inline-gcc: @echo "passed: no defects from any gcc no-online sanitizers." @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-sanitizer-no-inline-builds-gcc" clean +.PHONY: sanitize-aarch64-be-test +sanitize-aarch64-be-test: + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-sanitize-aarch64-be-builds" clean + @HOST=aarch64_be-unknown-linux-gnu; \ + HOST_RPATH=$$(dirname $$($${HOST}-gcc -print-libgcc-file-name)) && \ + $(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-sanitize-aarch64-be-builds" HOST=$$HOST EXE_LAUNCHER="qemu-aarch64_be -E LD_LIBRARY_PATH=$${HOST_RPATH} -L /usr/aarch64_be-unknown-linux-gnu" EXTRA_CFLAGS+='-fno-sanitize-recover=all' EXTRA_LDFLAGS="-Wl,-rpath-link=$$HOST_RPATH -Wl,-rpath=$$HOST_RPATH" sanitize-no-leak + @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-sanitize-aarch64-be-builds" clean + @echo "passed: sanitize-aarch64-be test." + .PHONY: sanitize-all-clang sanitize-all-clang: clang-version-test @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-sanitizer-builds-clang" clean @@ -228,7 +237,7 @@ cppcheck-analyze: .PHONY: analyze-all # valgrind-all-clang disabled until the valgrind team fixes https://bugs.kde.org/show_bug.cgi?id=452758 # "Valgrind does not read properly DWARF5 as generated by Clang14" -analyze-all: valgrind-all-gcc sanitize-all-gcc sanitize-all-clang sanitize-all-no-inline-gcc clang-tidy-build-test cppcheck-analyze +analyze-all: valgrind-all-gcc sanitize-all-gcc sanitize-aarch64-be-test sanitize-all-clang sanitize-all-no-inline-gcc clang-tidy-build-test cppcheck-analyze @echo 'passed: analyzers found no defects.' .PHONY: analyze-macosx @@ -339,7 +348,7 @@ minimal-build-test: dynamic-build-test: @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-dynamic-build-test" clean @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-dynamic-build-test" "$(addprefix $(BUILD_PARENT)/wolfsentry-dynamic-build-test/tests/,$(UNITTEST_LIST_SHARED))" - @for test in $(UNITTEST_LIST_SHARED); do LD_LIBRARY_PATH="$(BUILD_PARENT)/wolfsentry-dynamic-build-test" $(TEST_ENV) $(VALGRIND) "$(BUILD_PARENT)/wolfsentry-dynamic-build-test/tests/$$test" >/dev/null || exit $?; done + @for test in $(UNITTEST_LIST_SHARED); do LD_LIBRARY_PATH="$(BUILD_PARENT)/wolfsentry-dynamic-build-test" $(TEST_ENV) $(EXE_LAUNCHER) "$(BUILD_PARENT)/wolfsentry-dynamic-build-test/tests/$$test" >/dev/null || exit $?; done @echo 'passed: $(UNITTEST_LIST_SHARED).' @$(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 BUILD_TOP="$(BUILD_PARENT)/wolfsentry-dynamic-build-test" clean @@ -400,16 +409,26 @@ linux-lwip-test: .PHONY: dist-check dist-check: - @if [[ ! -d $(SRC_TOP)/.git ]]; then echo 'skipping dist-check in non-git source tree.'; exit 0; fi; \ + @if [[ ! -d $(SRC_TOP)/.git ]]; then echo 'skipping $@ in non-git source tree.'; exit 0; fi; \ $(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 dist-test && \ $(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f $(THIS_MAKEFILE) VERY_QUIET=1 dist-test-clean && \ echo 'passed: $@.' +release-check: + @if [[ ! -d $(SRC_TOP)/.git ]]; then echo 'skipping $@ in non-git source tree.'; exit 0; fi; \ + mkdir release-test-$$$$ && \ + cd release-test-$$$$ && \ + $(MAKE) $(EXTRA_MAKE_FLAGS) $(QUIET_FLAG) -f ../$(THIS_MAKEFILE) VERY_QUIET=1 SRC_TOP="$(SRC_TOP)" release && \ + cd .. && \ + rm release-test-$$$$/*.zip && \ + rmdir release-test-$$$$ && \ + echo 'passed: $@.' + .PHONY: check check: dynamic-build-test c99-test no-alloca-test singlethreaded-test no-json-test no-json-dom-test no-error-strings-test no-protocol-names-test no-getprotoby-test no-stdio-build-test minimal-build-test .PHONY: check-extra -check-extra: static-build-test c89-test no-inline-test m32-test m32-c89-test freertos-arm32-build-test freertos-arm32-singlethreaded-build-test freertos-arm32-c89-build-test linux-lwip-test dist-check +check-extra: static-build-test c89-test no-inline-test m32-test m32-c89-test freertos-arm32-build-test freertos-arm32-singlethreaded-build-test freertos-arm32-c89-build-test linux-lwip-test dist-check release-check ifdef JSON_TEST_CORPUS_DIR export JSON_TEST_CORPUS_DIR diff --git a/wolfsentry/wolfsentry.h b/wolfsentry/wolfsentry.h index a40a4e1..1a5246b 100644 --- a/wolfsentry/wolfsentry.h +++ b/wolfsentry/wolfsentry.h @@ -25,7 +25,7 @@ #define WOLFSENTRY_VERSION_MAJOR 1 #define WOLFSENTRY_VERSION_MINOR 2 -#define WOLFSENTRY_VERSION_TINY 1 +#define WOLFSENTRY_VERSION_TINY 2 #define WOLFSENTRY_VERSION_ENCODE(major, minor, tiny) (((major) << 16U) | ((minor) << 8U) | (tiny)) #define WOLFSENTRY_VERSION WOLFSENTRY_VERSION_ENCODE(WOLFSENTRY_VERSION_MAJOR, WOLFSENTRY_VERSION_MINOR, WOLFSENTRY_VERSION_TINY) #define WOLFSENTRY_VERSION_GT(major, minor, tiny) (WOLFSENTRY_VERSION > WOLFSENTRY_VERSION_ENCODE(major, minor, tiny))