/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef XP_LINUX # include <errno.h> # include <linux/magic.h> # include <stdio.h> # include <string.h> # include <sys/statfs.h> # include <sys/utsname.h> #endif
#ifdef XP_WIN # include <windows.h> #endif
namespace mozilla {
// Try to map a frozen shm for writing. Threat model: the process is // compromised and then receives a frozen handle.
TEST(IPCSharedMemory, FreezeAndMapRW)
{ auto shm = MakeRefPtr<ipc::SharedMemory>();
// Create and initialize
ASSERT_TRUE(shm->CreateFreezable(1));
ASSERT_TRUE(shm->Map(1)); auto* mem = reinterpret_cast<char*>(shm->Memory());
ASSERT_TRUE(mem);
*mem = 'A';
// Re-create as writeable auto handle = shm->TakeHandleAndUnmap();
ASSERT_TRUE(shm->IsHandleValid(handle));
ASSERT_FALSE(shm->IsValid());
ASSERT_TRUE(shm->SetHandle(std::move(handle),
ipc::SharedMemory::OpenRights::RightsReadWrite));
ASSERT_TRUE(shm->IsValid());
// This should fail
EXPECT_FALSE(shm->Map(1));
}
// Try to restore write permissions to a frozen mapping. Threat // model: the process has mapped frozen shm normally and then is // compromised, or as for FreezeAndMapRW (see also the // proof-of-concept at https://crbug.com/project-zero/1671 ).
TEST(IPCSharedMemory, FreezeAndReprotect)
{ auto shm = MakeRefPtr<ipc::SharedMemory>();
// Create and initialize
ASSERT_TRUE(shm->CreateFreezable(1));
ASSERT_TRUE(shm->Map(1)); auto* mem = reinterpret_cast<char*>(shm->Memory());
ASSERT_TRUE(mem);
*mem = 'A';
// Re-map
ASSERT_TRUE(shm->Map(1));
mem = reinterpret_cast<char*>(shm->Memory());
ASSERT_EQ(*mem, 'A');
// Try to alter protection; should fail
EXPECT_FALSE(ipc::SharedMemory::SystemProtectFallible(
mem, 1, ipc::SharedMemory::RightsReadWrite));
}
#if !defined(XP_WIN) && !defined(XP_DARWIN) // This essentially tests whether FreezeAndReprotect would have failed // without the freeze. // // It doesn't work on Windows: VirtualProtect can't exceed the permissions set // in MapViewOfFile regardless of the security status of the original handle. // // It doesn't work on MacOS: we can set a higher max_protection for the memory // when creating the handle, but we wouldn't want to do this for freezable // handles (to prevent creating additional RW mappings that break the memory // freezing invariants).
TEST(IPCSharedMemory, Reprotect)
{ auto shm = MakeRefPtr<ipc::SharedMemory>();
// Create and initialize
ASSERT_TRUE(shm->CreateFreezable(1));
ASSERT_TRUE(shm->Map(1)); auto* mem = reinterpret_cast<char*>(shm->Memory());
ASSERT_TRUE(mem);
*mem = 'A';
// Re-create as read-only auto handle = shm->TakeHandleAndUnmap();
ASSERT_TRUE(shm->IsHandleValid(handle));
ASSERT_FALSE(shm->IsValid());
ASSERT_TRUE(shm->SetHandle(std::move(handle),
ipc::SharedMemory::OpenRights::RightsReadOnly));
ASSERT_TRUE(shm->IsValid());
// Re-map
ASSERT_TRUE(shm->Map(1));
mem = reinterpret_cast<char*>(shm->Memory());
ASSERT_EQ(*mem, 'A');
// Try to alter protection; should succeed, because not frozen
EXPECT_TRUE(ipc::SharedMemory::SystemProtectFallible(
mem, 1, ipc::SharedMemory::RightsReadWrite));
} #endif
#ifdef XP_WIN // Try to regain write permissions on a read-only handle using // DuplicateHandle; this will succeed if the object has no DACL. // See also https://crbug.com/338538
TEST(IPCSharedMemory, WinUnfreeze)
{ auto shm = MakeRefPtr<ipc::SharedMemory>();
// Create and initialize
ASSERT_TRUE(shm->CreateFreezable(1));
ASSERT_TRUE(shm->Map(1)); auto* mem = reinterpret_cast<char*>(shm->Memory());
ASSERT_TRUE(mem);
*mem = 'A';
// Test that a read-only copy sees changes made to the writeable // mapping in the case that the page wasn't accessed before the copy.
TEST(IPCSharedMemory, ROCopyAndWrite)
{ auto shmRW = MakeRefPtr<ipc::SharedMemory>(); auto shmRO = MakeRefPtr<ipc::SharedMemory>();
// Test that a read-only copy sees changes made to the writeable // mapping in the case that the page was accessed before the copy // (and, before that, sees the state as of when the copy was made).
TEST(IPCSharedMemory, ROCopyAndRewrite)
{ auto shmRW = MakeRefPtr<ipc::SharedMemory>(); auto shmRO = MakeRefPtr<ipc::SharedMemory>();
// See FreezeAndMapRW.
TEST(IPCSharedMemory, ROCopyAndMapRW)
{ auto shmRW = MakeRefPtr<ipc::SharedMemory>(); auto shmRO = MakeRefPtr<ipc::SharedMemory>();
// Re-create as writeable auto handle = shmRO->TakeHandleAndUnmap();
ASSERT_TRUE(shmRO->IsHandleValid(handle));
ASSERT_FALSE(shmRO->IsValid());
ASSERT_TRUE(shmRO->SetHandle(std::move(handle),
ipc::SharedMemory::OpenRights::RightsReadWrite));
ASSERT_TRUE(shmRO->IsValid());
// This should fail
EXPECT_FALSE(shmRO->Map(1));
}
// See FreezeAndReprotect
TEST(IPCSharedMemory, ROCopyAndReprotect)
{ auto shmRW = MakeRefPtr<ipc::SharedMemory>(); auto shmRO = MakeRefPtr<ipc::SharedMemory>();
// Test that memfd_create is used where expected. // // More precisely: if memfd_create support is expected, verify that // shared memory isn't subject to a filesystem size limit.
TEST_F(IPCSharedMemoryLinuxTest, IsMemfd) { auto shm = MakeRefPtr<ipc::SharedMemory>();
ASSERT_TRUE(shm->Create(1));
UniqueFileHandle fd = shm->TakeHandleAndUnmap();
ASSERT_TRUE(fd);
struct statfs fs;
ASSERT_EQ(fstatfs(fd.get(), &fs), 0) << strerror(errno);
EXPECT_EQ(fs.f_type, TMPFS_MAGIC); static constexpr decltype(fs.f_blocks) kNoLimit = 0; if (ShouldHaveMemfd()) {
EXPECT_EQ(fs.f_blocks, kNoLimit);
} else { // On older kernels, we expect the memfd / no-limit test to fail. // (In theory it could succeed if backported memfd support exists; // if that ever happens, this check can be removed.)
EXPECT_NE(fs.f_blocks, kNoLimit);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.