This reverts commit 6911114d8c.
Broke the QEMU sanitizer bots due to a missing header dependency. This
actually needs to be fixed on the bot-side, but for now reverting this
patch until I can fix up the bot.
This patch moves -fsanitize=scudo to link the standalone scudo library,
rather than the original compiler-rt based library. This is one of the
major remaining roadblocks to deleting the compiler-rt based scudo,
which should not be used any more. The standalone Scudo is better in
pretty much every way and is much more suitable for production usage.
As well as patching the litmus tests for checking that the
scudo_standalone lib is linked instead of the scudo lib, this patch also
ports all the scudo lit tests to run under scudo standalone.
This patch also adds a feature to scudo standalone that was under test
in the original scudo - that arguments passed to an aligned operator new
were checked that the alignment was a power of two.
Some lit tests could not be migrated, due to the following issues:
1. Features that aren't supported in scudo standalone, like the rss
limit.
2. Different quarantine implementation where the test needs some more
thought.
3. Small bugs in scudo standalone that should probably be fixed, like
the Secondary allocator having a full page on the LHS of an allocation
that only contains the chunk header, so underflows by <= a page aren't
caught.
4. Slight differences in behaviour that's technically correct, like
'realloc(malloc(1), 0)' returns nullptr in standalone, but a real
pointer in old scudo.
5. Some tests that might be migratable, but not easily.
Tests that are obviously not applicable to scudo standalone (like
testing that no sanitizer symbols made it into the DSO) have been
deleted.
After this patch, the remaining work is:
1. Update the Scudo documentation. The flags have changed, etc.
2. Delete the old version of scudo.
3. Patch up the tests in lit-unmigrated, or fix Scudo standalone.
Reviewed By: cryptoad, vitalybuka
Differential Revision: https://reviews.llvm.org/D102543
Now that everything is forcibly linker initialized, it feels like a
good time to get rid of the `init`/`initLinkerInitialized` split.
This allows to get rid of various `memset` construct in `init` that
gcc complains about (this fixes a Fuchsia open issue).
I added various `DCHECK`s to ensure that we would get a zero-inited
object when entering `init`, which required ensuring that
`unmapTestOnly` leaves the object in a good state (tests are currently
the only location where an allocator can be "de-initialized").
Running the tests with `--gtest_repeat=` showed no issue.
Differential Revision: https://reviews.llvm.org/D103119
Cast of signed types to u64 breaks comparison.
Also remove double () around operands.
Reviewed By: cryptoad, hctim
Differential Revision: https://reviews.llvm.org/D103060
Make sure that if SCUDO_DEBUG=1 in tests
then we had the same in the scudo
library itself.
Reviewed By: cryptoad, hctim
Differential Revision: https://reviews.llvm.org/D103061
Said function had a few shortfalls:
- didn't set an abort message on Android
- was logged on several lines
- didn't provide extra information like the size requested if OOM'ing
This improves the function to address those points.
Differential Revision: https://reviews.llvm.org/D103034
When trying to track down a vaddr-poisoning bug, I found that that the
secondary cache isn't emptied on test teardown. We should probably do
that to make the tests hermetic. Otherwise, repeating the tests lots of
times using --gtest_repeat fails after the mmap vaddr space is
exhausted.
To repro:
$ ninja check-scudo_standalone # build
$ ./projects/compiler-rt/lib/scudo/standalone/tests/ScudoUnitTest-x86_64-Test \
--gtest_filter=ScudoSecondaryTest.*:-ScudoSecondaryTest.SecondaryCombinations \
--gtest_repeat=10000
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D102874
Fix buildbot failure
https://lab.llvm.org/buildbot/#/builders/57/builds/6542/steps/6/logs/stdio
/llvm-project/llvm/utils/unittest/googletest/include/gtest/gtest.h:1629:28:
error: comparison of integers of different signs: 'const unsigned long'
and 'const int' [-Werror,-Wsign-compare]
GTEST_IMPL_CMP_HELPER_(GT, >);
~~~~~~~~~~~~~~~~~~~~~~~~~~^~
/llvm-project/llvm/utils/unittest/googletest/include/gtest/gtest.h:1609:12:
note: expanded from macro 'GTEST_IMPL_CMP_HELPER_'
if (val1 op val2) {\
~~~~ ^ ~~~~
/llvm-project/compiler-rt/lib/scudo/standalone/tests/common_test.cpp:30:3:
note: in instantiation of function template specialization
'testing::internal::CmpHelperGT<unsigned long, int>' requested here
EXPECT_GT(OnStart, 0);
^
Reviewed By: vitalybuka
Differential Revision: https://reviews.llvm.org/D103029
The Fuchsia allocator config was using the default size class map.
This CL gives Fuchsia its own size class map and changes a couple of
things in the default one:
- make `SizeDelta` configurable in `Config` for a fixed size class map
as it currently is for a table size class map;
- switch `SizeDelta` to 0 for the default config, it allows for size
classes that allow for power of 2s, and overall better wrt pages
filling;
- increase the max number of caches pointers to 14 in the default,
this makes the transfer batch 64/128 bytes on 32/64-bit platforms,
which is cache-line friendly (previous size was 48/96 bytes).
The Fuchsia size class map remains untouched for now, this doesn't
impact Android which uses the table size class map.
Differential Revision: https://reviews.llvm.org/D102783
Put allocate/deallocate next to memory
access inside EXPECT_DEATH block.
This way we reduce probability that memory is not mapped
by unrelated code.
It's still not absolutely guaranty that mmap does not
happen so we repeat it few times to be sure.
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D102886
Looks like secondary pointers don't get unmapped on one of the arm32
bots. In the interests of landing some dependent patches, disable this
test on arm32 so that it can be tested in isolation later.
Reviewed By: cryptoad, vitalybuka
Split from differential patchset (1/2): https://reviews.llvm.org/D102648
While developing a change to the allocator I ended up breaking
realloc on secondary allocations with increasing sizes. That didn't
cause any of the unit tests to fail, which indicated that we're
missing some test coverage here. Add a unit test for that case.
Differential Revision: https://reviews.llvm.org/D102716
This removes one of the last dependencies on old Scudo, and should allow
us to delete the old Scudo soon.
Reviewed By: vitalybuka, cryptoad
Differential Revision: https://reviews.llvm.org/D102349
With zero-sized allocations we don't actually end up storing the
address tag to the memory tag space, so store it in the first byte of
the chunk instead so that we can find it later in getInlineErrorInfo().
Differential Revision: https://reviews.llvm.org/D102442
It's more likely that we have a UAF than an OOB in blocks that are
more than 1 block away from the fault address, so the UAF should
appear first in the error report.
Differential Revision: https://reviews.llvm.org/D102379
The bounds check that we previously had here was suitable for secondary
allocations but not for UAF on primary allocations, where it is likely
to result in false positives. Fix it by using a different bounds check
for UAF that requires the fault address to be in bounds.
Differential Revision: https://reviews.llvm.org/D102376
This patch does a few cleanup things:
1. The non-standalone scudo has a problem where GWP-ASan allocations
may not meet alignment requirements where Scudo was requested to have
alignment >= 16. Use the new GWP-ASan API to fix this.
2. The standalone variant loses some debugging information inside of
GWP-ASan because we ask GWP-ASan to allocate an aligned size in the
frontend. This means reports end up with 'UaF on a 16-byte allocation'
for a 1-byte allocation with 16-byte alignment. Also use the new API to
fix this.
3. Add post-alloc hooks for GWP-ASan intercepted allocations, and add
stats tracking for GWP-ASan allocations.
4. Add a small test that checks the alignment of the frontend
allocator, so that it can be used under GWP-ASan torture mode.
5. Add GWP-ASan torture mode as a testing configuration to catch these
regressions.
Depends on D94830, D95889.
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D95884
GWP-ASan is the "production" variant as compiled by compiler-rt, and it's useful to be able to benchmark changes in GWP-ASan or Scudo's GWP-ASan hooks across versions. GWP-ASan is sampled, and sampled allocations are much slower, but given the amount of allocations that happen under test here - we actually get a reasonable representation of GWP-ASan's negligent performance impact between runs.
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D101865
Fixes compilation on Android which has a TSDSharedRegistry object in the config.
Reviewed By: cryptoad, vitalybuka
Differential Revision: https://reviews.llvm.org/D101951
Operator new must align allocations for types with large alignment.
Before c++17 behavior was implementation defined and both clang and gc++
before 11 ignored alignment. Miss-aligned objects mysteriously crashed
tests on Ubuntu 14.
Alternatives are compile with -std=c++17 or -faligned-new, but they were
discarded as less portable.
Reviewed By: hctim
Differential Revision: https://reviews.llvm.org/D101874
The Scudo C unit tests are currently non-hermetic. In particular, adding
or removing a transfer batch is a global state of the allocator that
persists between tests. This can cause flakiness in
ScudoWrappersCTest.MallInfo, because the creation or teardown of a batch
causes mallinfo's uordblks or fordblks to move up or down by the size of
a transfer batch on malloc/free.
It's my opinion that uordblks and fordblks should track the statistics
related to the user's malloc() and free() usage, and not the state of
the internal allocator structures. Thus, excluding the transfer batches
from stat collection does the trick and makes these tests pass.
Repro instructions of the bug:
1. ninja ./projects/compiler-rt/lib/scudo/standalone/tests/ScudoCUnitTest-x86_64-Test
2. ./projects/compiler-rt/lib/scudo/standalone/tests/ScudoCUnitTest-x86_64-Test --gtest_filter=ScudoWrappersCTest.MallInfo
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D101653
This patch does a few cleanup things:
1. The non-standalone scudo has a problem where GWP-ASan allocations
may not meet alignment requirements where Scudo was requested to have
alignment >= 16. Use the new GWP-ASan API to fix this.
2. The standalone variant loses some debugging information inside of
GWP-ASan because we ask GWP-ASan to allocate an aligned size in the
frontend. This means reports end up with 'UaF on a 16-byte allocation'
for a 1-byte allocation with 16-byte alignment. Also use the new API to
fix this.
3. Add post-alloc hooks for GWP-ASan intercepted allocations, and add
stats tracking for GWP-ASan allocations.
4. Add a small test that checks the alignment of the frontend
allocator, so that it can be used under GWP-ASan torture mode.
5. Add GWP-ASan torture mode as a testing configuration to catch these
regressions.
Depends on D94830, D95889.
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D95884
From a cache perspective it's better to store the header immediately
after loading it. If we delay this operation until after we've
retagged it's more likely that our header will have been evicted from
the cache and we'll need to fetch it again in order to perform the
compare-exchange operation.
For similar reasons, store the deallocation stack before retagging
instead of afterwards.
Differential Revision: https://reviews.llvm.org/D101137
It looks like there's some old version of gcc that doesn't like this
static_assert (I couldn't reproduce the issue with gcc 8, 9 or 10).
Work around the issue by only checking the static_assert under clang,
which should provide sufficient coverage.
Should hopefully fix this buildbot:
https://lab.llvm.org/buildbot/#/builders/112/builds/5356
With AndroidSizeClassMap all of the LSBs are in the range 4-6 so we
only need 2 bits of information per size class. Furthermore we have
32 size classes, which conveniently lets us fit all of the information
into a 64-bit integer. Do so if possible so that we can avoid a table
lookup entirely.
Differential Revision: https://reviews.llvm.org/D101105
In the most common case we call computeOddEvenMaskForPointerMaybe()
from quarantineOrDeallocateChunk(), in which case we need to look up
the class size from the SizeClassMap in order to compute the LSB. Since
we need to do a lookup anyway, we may as well look up the LSB itself
and avoid computing it every time.
While here, switch to a slightly more efficient way of computing the
odd/even mask.
Differential Revision: https://reviews.llvm.org/D101018
Since we already have a tagged pointer available to us, we can just
extract the tag from it and avoid an LDG instruction.
Differential Revision: https://reviews.llvm.org/D101014
Now that we have a more efficient implementation of storeTags(),
we should start using it from resizeTaggedChunk(). With that, plus
a new storeTag() function, resizeTaggedChunk() can be made generic,
and so can prepareTaggedChunk(). Make it so.
Now that the functions are generic, move them to combined.h so that
memtag.h no longer needs to know about chunks.
Differential Revision: https://reviews.llvm.org/D100911
DC GZVA can operate on multiple granules at a time (corresponding to
the CPU's cache line size) so we can generally expect it to be faster
than STZG in a loop.
Differential Revision: https://reviews.llvm.org/D100910
An empty macro that expands to just `... else ;` can get
warnings from some compilers (e.g. GCC's -Wempty-body).
Reviewed By: cryptoad, vitalybuka
Differential Revision: https://reviews.llvm.org/D100693
While attempting to roll the latest Scudo in Fuchsia, some issues
arose. While trying to debug them, it appeared that `DCHECK`s were
also never exercised in Fuchsia. This CL fixes the following
problems:
- the size of a block in the TransferBatch class must be a multiple
of the compact pointer scale. In some cases, it wasn't true, which
lead to obscure crashes. Now, we round up `sizeof(TransferBatch)`.
This only materialized in Fuchsia due to the specific parameters
of the `DefaultConfig`;
- 2 `DCHECK` statements in Fuchsia were incorrect;
- `map()` & co. require a size multiple of a page (as enforced in
Fuchsia `DCHECK`s), which wasn't the case for `PackedCounters`.
- In the Secondary, a parameter was marked as `UNUSED` while it is
actually used.
Differential Revision: https://reviews.llvm.org/D100524
The GNU assembler can't parse `.arch_extension ...` before a `;`.
So instead uniformly use raw string syntax with separate lines
instead of `;` separators in the assembly code.
Reviewed By: pcc
Differential Revision: https://reviews.llvm.org/D100413
D99763 fixed `SizeClassAllocatorLocalCache::drain` but with the
assumption that `BatchClassId` is 0 - which is currently true. I would
rather not make the assumption so that if we ever change the ID of
the batch class, the loop would still work. Since `BatchClassId` is
used more often in `local_cache.h`, introduce a constant so that we
don't have to specify `SizeClassMap::` every time.
Differential Revision: https://reviews.llvm.org/D100062
The check was removed in D99786 as it seems that quarantine is
irrelevant for the just created allocator. However there is internal
issues with tagged memory access.
We should be able to fix iterateOverChunks for taggin later.
Existing implementations took up to 30 minutues to execute on my setup.
Now it's more convenient to debug a single test.
Reviewed By: cryptoad
Differential Revision: https://reviews.llvm.org/D99786
Android's native bridge (i.e. AArch64 emulator) doesn't support TBI so
we need a way to disable TBI on Linux when targeting the native bridge.
This can also be used to test the no-TBI code path on Linux (currently
only used on Fuchsia), or make Scudo compatible with very old
(pre-commit d50240a5f6ceaf690a77b0fccb17be51cfa151c2 from June 2013)
Linux kernels that do not enable TBI.
Differential Revision: https://reviews.llvm.org/D98732
Since we are looking to remove the old Scudo, we have to have a .so for
parity purposes as some platforms use it.
I tested this on Fuchsia & Linux, not on Android though.
Differential Revision: https://reviews.llvm.org/D98456
There is no centralized store of information related to secondary
allocations. Moreover the allocations themselves become inaccessible
when the allocation is freed in order to implement UAF detection,
so we can't store information there to be used in case of UAF
anyway.
Therefore our storage location for tracking stack traces of secondary
allocations is a ring buffer. The ring buffer is copied to the process
creating the crash dump when a fault occurs.
The ring buffer is also used to store stack traces for primary
deallocations. Stack traces for primary allocations continue to be
stored inline.
In order to support the scenario where an access to the ring buffer
is interrupted by a concurrently occurring crash, the ring buffer is
accessed in a lock-free manner.
Differential Revision: https://reviews.llvm.org/D94212
This patch enhances the secondary allocator to be able to detect buffer
overflow, and (on hardware supporting memory tagging) use-after-free
and buffer underflow.
Use-after-free detection is implemented by setting memory page
protection to PROT_NONE on free. Because this must be done immediately
rather than after the memory has been quarantined, we no longer use the
combined allocator quarantine for secondary allocations. Instead, a
quarantine has been added to the secondary allocator cache.
Buffer overflow detection is implemented by aligning the allocation
to the right of the writable pages, so that any overflows will
spill into the guard page to the right of the allocation, which
will have PROT_NONE page protection. Because this would require the
secondary allocator to produce a header at the correct position,
the responsibility for ensuring chunk alignment has been moved to
the secondary allocator.
Buffer underflow detection has been implemented on hardware supporting
memory tagging by tagging the memory region between the start of the
mapping and the start of the allocation with a non-zero tag. Due to
the cost of pre-tagging secondary allocations and the memory bandwidth
cost of tagged accesses, the allocation itself uses a tag of 0 and
only the first four pages have memory tagging enabled.
This is a reland of commit 7a0da88943 which was reverted in commit
9678b07e42. This reland includes the following changes:
- Fix the calculation of BlockSize which led to incorrect statistics
returned by mallinfo().
- Add -Wno-pedantic to silence GCC warning.
- Optionally add some slack at the end of secondary allocations to help
work around buggy applications that read off the end of their
allocation.
Differential Revision: https://reviews.llvm.org/D93731
As of 4f395db86b which contains updates to
-Wfree-nonheap-object, a line in this test will trigger the warning. This
particular line is ok though since it's meant to test a free on a bad pointer.
Differential Revision: https://reviews.llvm.org/D97516
This CL introduces configuration options to allow pointers to be
compacted in the thread-specific caches and transfer batches. This
offers the possibility to have them use 32-bit of space instead of
64-bit for the 64-bit Primary, thus cutting the size of the caches
and batches by nearly half (and as such the memory used in size
class 0). The cost is an additional read from the region information
in the fast path.
This is not a new idea, as it's being used in the sanitizer_common
64-bit primary. The difference here is that it is configurable via
the allocator config, with the possibility of not compacting at all.
This CL enables compacting pointers in the Android and Fuchsia default
configurations.
Differential Revision: https://reviews.llvm.org/D96435
This patch enhances the secondary allocator to be able to detect buffer
overflow, and (on hardware supporting memory tagging) use-after-free
and buffer underflow.
Use-after-free detection is implemented by setting memory page
protection to PROT_NONE on free. Because this must be done immediately
rather than after the memory has been quarantined, we no longer use the
combined allocator quarantine for secondary allocations. Instead, a
quarantine has been added to the secondary allocator cache.
Buffer overflow detection is implemented by aligning the allocation
to the right of the writable pages, so that any overflows will
spill into the guard page to the right of the allocation, which
will have PROT_NONE page protection. Because this would require the
secondary allocator to produce a header at the correct position,
the responsibility for ensuring chunk alignment has been moved to
the secondary allocator.
Buffer underflow detection has been implemented on hardware supporting
memory tagging by tagging the memory region between the start of the
mapping and the start of the allocation with a non-zero tag. Due to
the cost of pre-tagging secondary allocations and the memory bandwidth
cost of tagged accesses, the allocation itself uses a tag of 0 and
only the first four pages have memory tagging enabled.
Differential Revision: https://reviews.llvm.org/D93731
GNU binutils accepts only `.arch_extension memtag` while Clang
accepts either that or `.arch_extension mte` to mean the same thing.
Reviewed By: pcc
Differential Revision: https://reviews.llvm.org/D95996
Adds a new allocation API to GWP-ASan that handles size+alignment
restrictions.
Reviewed By: cryptoad, eugenis
Differential Revision: https://reviews.llvm.org/D94830
With D92696, the Scudo Standalone GWP-ASan flag parsing was changed to
the new GWP-ASan optional one. We do not necessarily want this, as this
duplicates flag parsing code in Scudo Standalone when using the
GWP-ASan integration.
This CL reverts the changes within Scudo Standalone, and increases
`MaxFlags` to 20 as an addionnal option got us to the current max.
Differential Revision: https://reviews.llvm.org/D95542
zxtest doesn't have `EXPECT_DEATH` and the Scudo unit-tests were
defining it as a no-op.
This enables death tests on Fuchsia by using `ASSERT_DEATH` instead.
I used a lambda to wrap the expressions as this appears to not be
working the same way as `EXPECT_DEATH`.
Additionnally, a death test using `alarm` was failing with the change,
as it's currently not implemented in Fuchsia, so move that test within
a `!SCUDO_FUCHSIA` block.
Differential Revision: https://reviews.llvm.org/D94362
In preparation for the inbuilt options parser, this is a minor refactor
of optional components including:
- Putting certain optional elements in the right header files,
according to their function and their dependencies.
- Cleaning up some old and mostly-dead code.
- Moving some functions into anonymous namespaces to prevent symbol
export.
Reviewed By: cryptoad, eugenis
Differential Revision: https://reviews.llvm.org/D94117
The primary and secondary allocators will need to share this bit,
so move the management of the bit to the combined allocator and
make useMemoryTagging() a free function.
Differential Revision: https://reviews.llvm.org/D93730
Kernel support for MTE has been released in Linux 5.10. This means
that it is a stable API and we no longer need to make the support
conditional on a macro. We do need to provide conditional definitions
of the new macros though in order to avoid a dependency on new
kernel headers.
Differential Revision: https://reviews.llvm.org/D93513
canAllocate() does not take into account the header size so it does
not return the right answer in borderline cases. There was already
code handling this correctly in isTaggedAllocation() so split it out
into a separate function and call it from the test.
Furthermore the test was incorrect when MTE is enabled because MTE
does not pattern fill primary allocations. Fix it.
Differential Revision: https://reviews.llvm.org/D93437