зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1479960 - Add unit tests for shared memory freezing. r=froydnj
Also refactor SharedMemoryBasic::SystemProtect to allow testing cases that are expected to fail. Depends on D26748 Differential Revision: https://phabricator.services.mozilla.com/D26749 --HG-- rename : ipc/moz.build => ipc/gtest/moz.build extra : moz-landing-system : lando
This commit is contained in:
Родитель
1388eadfff
Коммит
d9d1bec632
|
@ -83,6 +83,8 @@ class SharedMemory {
|
|||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedMemory)
|
||||
|
||||
static void SystemProtect(char* aAddr, size_t aSize, int aRights);
|
||||
static MOZ_MUST_USE bool SystemProtectFallible(char* aAddr, size_t aSize,
|
||||
int aRights);
|
||||
static size_t SystemPageSize();
|
||||
static size_t PageAlignedSize(size_t aSize);
|
||||
|
||||
|
|
|
@ -13,12 +13,19 @@ namespace mozilla {
|
|||
namespace ipc {
|
||||
|
||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||
MOZ_CRASH("can't mprotect()");
|
||||
}
|
||||
}
|
||||
|
||||
bool SharedMemory::SystemProtectFallible(char* aAddr, size_t aSize,
|
||||
int aRights) {
|
||||
int flags = 0;
|
||||
if (aRights & RightsRead) flags |= PROT_READ;
|
||||
if (aRights & RightsWrite) flags |= PROT_WRITE;
|
||||
if (RightsNone == aRights) flags = PROT_NONE;
|
||||
|
||||
if (0 < mprotect(aAddr, aSize, flags)) MOZ_CRASH("can't mprotect()");
|
||||
return 0 == mprotect(aAddr, aSize, flags);
|
||||
}
|
||||
|
||||
size_t SharedMemory::SystemPageSize() { return sysconf(_SC_PAGESIZE); }
|
||||
|
|
|
@ -12,6 +12,13 @@ namespace mozilla {
|
|||
namespace ipc {
|
||||
|
||||
void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
||||
if (!SystemProtectFallible(aAddr, aSize, aRights)) {
|
||||
MOZ_CRASH("can't VirtualProtect()");
|
||||
}
|
||||
}
|
||||
|
||||
bool SharedMemory::SystemProtectFallible(char* aAddr, size_t aSize,
|
||||
int aRights) {
|
||||
DWORD flags;
|
||||
if ((aRights & RightsRead) && (aRights & RightsWrite))
|
||||
flags = PAGE_READWRITE;
|
||||
|
@ -21,8 +28,7 @@ void SharedMemory::SystemProtect(char* aAddr, size_t aSize, int aRights) {
|
|||
flags = PAGE_NOACCESS;
|
||||
|
||||
DWORD oldflags;
|
||||
if (!VirtualProtect(aAddr, aSize, flags, &oldflags))
|
||||
MOZ_CRASH("can't VirtualProtect()");
|
||||
return VirtualProtect(aAddr, aSize, flags, &oldflags);
|
||||
}
|
||||
|
||||
size_t SharedMemory::SystemPageSize() {
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "base/shared_memory.h"
|
||||
|
||||
#include "base/process_util.h"
|
||||
#include "mozilla/ipc/SharedMemory.h"
|
||||
|
||||
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)
|
||||
{
|
||||
base::SharedMemory shm;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_TRUE(mem);
|
||||
*mem = 'A';
|
||||
|
||||
// Freeze
|
||||
ASSERT_TRUE(shm.Freeze());
|
||||
ASSERT_FALSE(shm.memory());
|
||||
|
||||
// Re-create as writeable
|
||||
auto handle = base::SharedMemory::NULLHandle();
|
||||
ASSERT_TRUE(shm.GiveToProcess(base::GetCurrentProcId(), &handle));
|
||||
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm.IsValid());
|
||||
ASSERT_TRUE(shm.SetHandle(handle, /* read-only */ false));
|
||||
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)
|
||||
{
|
||||
base::SharedMemory shm;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shm.CreateFreezeable(1));
|
||||
ASSERT_TRUE(shm.Map(1));
|
||||
auto mem = reinterpret_cast<char*>(shm.memory());
|
||||
ASSERT_TRUE(mem);
|
||||
*mem = 'A';
|
||||
|
||||
// Freeze
|
||||
ASSERT_TRUE(shm.Freeze());
|
||||
ASSERT_FALSE(shm.memory());
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
#ifndef XP_WIN
|
||||
// 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.
|
||||
TEST(IPCSharedMemory, Reprotect)
|
||||
{
|
||||
base::SharedMemory shm;
|
||||
|
||||
// Create and initialize
|
||||
ASSERT_TRUE(shm.CreateFreezeable(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 = base::SharedMemory::NULLHandle();
|
||||
ASSERT_TRUE(shm.GiveToProcess(base::GetCurrentProcId(), &handle));
|
||||
ASSERT_TRUE(shm.IsHandleValid(handle));
|
||||
ASSERT_FALSE(shm.IsValid());
|
||||
ASSERT_TRUE(shm.SetHandle(handle, /* read-only */ true));
|
||||
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
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,15 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
Library('ipctest')
|
||||
|
||||
SOURCES += [
|
||||
'TestSharedMemory.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul-gtest'
|
|
@ -5,6 +5,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DIRS += [
|
||||
'app',
|
||||
'chromium',
|
||||
'glue',
|
||||
'ipdl',
|
||||
|
@ -17,7 +18,9 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
|
|||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DIRS += ['mscom']
|
||||
|
||||
DIRS += ['app']
|
||||
TEST_DIRS += [
|
||||
'gtest',
|
||||
]
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "IPC")
|
||||
|
|
Загрузка…
Ссылка в новой задаче