diff --git a/nixos/tests/hardened.nix b/nixos/tests/hardened.nix index 485efc0fb78c..a0b629086b5a 100644 --- a/nixos/tests/hardened.nix +++ b/nixos/tests/hardened.nix @@ -33,18 +33,7 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... } : { testScript = let - hardened-malloc-tests = pkgs.stdenv.mkDerivation { - name = "hardened-malloc-tests-${pkgs.graphene-hardened-malloc.version}"; - src = pkgs.graphene-hardened-malloc.src; - buildPhase = '' - cd test/simple-memory-corruption - make -j4 - ''; - - installPhase = '' - find . -type f -executable -exec install -Dt $out/bin '{}' + - ''; - }; + hardened-malloc-tests = pkgs.graphene-hardened-malloc.ld-preload-tests; in '' machine.wait_for_unit("multi-user.target") @@ -107,20 +96,7 @@ import ./make-test-python.nix ({ pkgs, latestKernel ? false, ... } : { machine.fail("systemctl kexec") - # Test hardened memory allocator - def runMallocTestProg(prog_name, error_text): - text = "fatal allocator error: " + error_text - if not text in machine.fail( - "${hardened-malloc-tests}/bin/" - + prog_name - + " 2>&1" - ): - raise Exception("Hardened malloc does not work for {}".format(error_text)) - - with subtest("The hardened memory allocator works"): - runMallocTestProg("double_free_large", "invalid free") - runMallocTestProg("unaligned_free_small", "invalid unaligned free") - runMallocTestProg("write_after_free_small", "detected write after free") + machine.succeed("${hardened-malloc-tests}/bin/run-tests") ''; }) diff --git a/pkgs/development/libraries/graphene-hardened-malloc/default.nix b/pkgs/development/libraries/graphene-hardened-malloc/default.nix index 726666ec06f3..35a4d9362680 100644 --- a/pkgs/development/libraries/graphene-hardened-malloc/default.nix +++ b/pkgs/development/libraries/graphene-hardened-malloc/default.nix @@ -1,15 +1,23 @@ -{ lib, stdenv, fetchurl }: +{ lib, stdenv, fetchurl, python3, runCommand, makeWrapper, stress-ng }: -stdenv.mkDerivation rec { +lib.fix (self: stdenv.mkDerivation rec { pname = "graphene-hardened-malloc"; - version = "2"; + version = "8"; src = fetchurl { url = "https://github.com/GrapheneOS/hardened_malloc/archive/${version}.tar.gz"; - sha256 = "0zsl4vl65ic6lw5rzcjzvcxg8makg683abnwvy60zfap8hvijvjb"; + sha256 = "0lipyd2pb1bmghkyv9zmg25jwcglj7m281f01zlh3ghz3xlfh0ym"; }; + doCheck = true; + checkInputs = [ python3 ]; + # these tests cover use as a build-time-linked library + checkPhase = '' + make test + ''; + installPhase = '' + install -Dm444 -t $out/include include/* install -Dm444 -t $out/lib libhardened_malloc.so mkdir -p $out/bin @@ -19,28 +27,51 @@ stdenv.mkDerivation rec { separateDebugInfo = true; - doInstallCheck = true; - installCheckPhase = '' - pushd test - make - $out/bin/preload-hardened-malloc ./offset + passthru = { + ld-preload-tests = stdenv.mkDerivation { + name = "${self.name}-ld-preload-tests"; + src = self.src; - pushd simple-memory-corruption - make + nativeBuildInputs = [ makeWrapper ]; - # these tests don't actually appear to generate overflows currently - rm read_after_free_small string_overflow eight_byte_overflow_large + # reuse the projects tests to cover use with LD_PRELOAD. we have + # to convince the test programs to build as though they're naive + # standalone executables. this includes disabling tests for + # malloc_object_size, which doesn't make sense to use via LD_PRELOAD. + buildPhase = '' + pushd test/simple-memory-corruption + make LDLIBS= LDFLAGS=-Wl,--unresolved-symbols=ignore-all CXXFLAGS=-lstdc++ + substituteInPlace test_smc.py \ + --replace 'test_malloc_object_size' 'dont_test_malloc_object_size' \ + --replace 'test_invalid_malloc_object_size' 'dont_test_invalid_malloc_object_size' + popd # test/simple-memory-corruption + ''; - for t in `find . -regex ".*/[a-z_]+"` ; do - echo "Running $t..." - # the program being aborted (as it should be) would result in an exit code > 128 - (($out/bin/preload-hardened-malloc $t) && false) \ - || (test $? -gt 128 || (echo "$t was not aborted" && false)) - done - popd + installPhase = '' + mkdir -p $out/test + cp -r test/simple-memory-corruption $out/test/simple-memory-corruption - popd - ''; + mkdir -p $out/bin + makeWrapper ${python3.interpreter} $out/bin/run-tests \ + --add-flags "-I -m unittest discover --start-directory $out/test/simple-memory-corruption" + ''; + }; + tests = { + ld-preload = runCommand "ld-preload-test-run" {} '' + ${self}/bin/preload-hardened-malloc ${self.ld-preload-tests}/bin/run-tests + touch $out + ''; + # to compensate for the lack of tests of correct normal malloc operation + stress = runCommand "stress-test-run" {} '' + ${self}/bin/preload-hardened-malloc ${stress-ng}/bin/stress-ng \ + --no-rand-seed \ + --malloc 8 \ + --malloc-ops 1000000 \ + --verify + touch $out + ''; + }; + }; meta = with lib; { homepage = "https://github.com/GrapheneOS/hardened_malloc"; @@ -54,4 +85,4 @@ stdenv.mkDerivation rec { maintainers = with maintainers; [ ris ]; platforms = [ "x86_64-linux" "aarch64-linux" ]; }; -} +})