sandbox can violate of sizeclass assert in snmalloc
saaramar opened this issue · comments
There is an assert on sizeclass in snmalloc:
constexpr static sizeclass_t from_small_class(smallsizeclass_t sc)
{
SNMALLOC_ASSERT(sc < TAG);
// Note could use `+` or `|`. Using `+` as will combine nicely with array
// offset.
return {TAG + sc};
}
The validations on AllocChunk arguments are as follows (run
in libsandbox):
auto is_metaentry_valid =
[&](size_t size, SharedAllocConfig::Pagemap::Entry& metaentry) {
auto sizeclass = metaentry.get_sizeclass();
auto remote = metaentry.get_remote();
return ((remote == nullptr) ||
s->contains(remote, sizeof(snmalloc::RemoteAllocator))) &&
(snmalloc::sizeclass_full_to_size(sizeclass) <= size);
};
While there is a check for snmalloc::sizeclass_full_to_size(sizeclass) <= size
, there is no check that enforces the snmalloc assumption sc < TAG
, which means an attacker could execute the following code in the sandbox and violate this assumption:
void try_alloc(const void *base, const void *top)
{
snmalloc::UNUSED(top);
auto* header =
static_cast<sandbox::SharedMemoryRegion*>(const_cast<void*>(base));
uintptr_t ras = FrontendMetaEntry<FrontendSlabMetadata>::encode(
reinterpret_cast<snmalloc::RemoteAllocator *>(header->start),
sizeclass_t::from_small_class(0xffffffffffffffff));
uintptr_t addr = sendRequest({AllocChunk, {MIN_CHUNK_SIZE, 0, ras}}).ret;
snmalloc::UNUSED(addr);
}
Running this in debug build triggers the assert:
root@a4d27c2670f1:/verona/experiments/process_sandbox/build-ninja# ./tests/test-sandbox-rpc-sizeclass
assert fail: sc < TAG in ../../../external/snmalloc/src/snmalloc/backend_helpers/../mem/sizeclasstable.h on 71
I don't think this is a bug. The assert is being triggered by the from_small_class
call, which is executing in the child. The child does something bad and crashes. Is there a way for the child to trigger this error in the parent?
Great point, this one actually triggered in the child. Therefore, I'm closing this. Thanks! :)