microsoft / verona

Research programming language for concurrent ownership

Home Page:https://microsoft.github.io/verona/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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! :)