Bug 1284897 - Add mechanism to libsandbox_s to track names of files that have been given special sandbox access permissions (PermissionsService). r=bobowen, r=glandium

Hook this into the browser via the XREAppData. This patch does not include the changes to Chromium source code.
This commit is contained in:
David Parks 2017-02-14 15:08:40 -08:00
parent cb9c91b2bb
commit e9bcaf4cbe
13 changed files with 368 additions and 0 deletions

View File

@ -217,6 +217,8 @@ static int do_main(int argc, char* argv[], char* envp[])
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
sandbox::BrokerServices* brokerServices =
sandboxing::GetInitializedBrokerServices();
sandboxing::PermissionsService* permissionsService =
sandboxing::GetPermissionsService();
#if defined(MOZ_CONTENT_SANDBOX)
if (!brokerServices) {
Output("Couldn't initialize the broker services.\n");
@ -224,6 +226,7 @@ static int do_main(int argc, char* argv[], char* envp[])
}
#endif
config.sandboxBrokerServices = brokerServices;
config.sandboxPermissionsService = permissionsService;
#endif
#ifdef LIBFUZZER

View File

@ -0,0 +1,136 @@
/* -*- 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/. */
/* SandboxPermissions.cpp - Special permissions granted to sandboxed processes */
#include "permissionsService.h"
#include <algorithm>
#include <winternl.h>
namespace mozilla {
namespace sandboxing {
static const std::wstring ZONE_IDENTIFIER_STR(L":ZONE.IDENTIFIER");
static const std::wstring ZONE_ID_DATA_STR(L":ZONE.IDENTIFIER:$DATA");
bool
StringEndsWith(const std::wstring& str, const std::wstring& strEnding)
{
if (strEnding.size() > str.size()) {
return false;
}
return std::equal(strEnding.rbegin(), strEnding.rend(), str.rbegin());
}
// Converts NT device internal filenames to normal user-space by stripping
// the prefixes and suffixes from the file name.
std::wstring
GetPlainFileName(const wchar_t* aNTFileName)
{
while (*aNTFileName == L'\\' || *aNTFileName == L'.' ||
*aNTFileName == L'?' || *aNTFileName == L':' ) {
++aNTFileName;
}
std::wstring nameCopy(aNTFileName);
std::transform(nameCopy.begin(), nameCopy.end(), nameCopy.begin(), towupper);
if (StringEndsWith(nameCopy, ZONE_ID_DATA_STR)) {
nameCopy = nameCopy.substr(0, nameCopy.size() - ZONE_ID_DATA_STR.size());
} else if (StringEndsWith(nameCopy, ZONE_IDENTIFIER_STR)) {
nameCopy = nameCopy.substr(0, nameCopy.size() - ZONE_IDENTIFIER_STR.size());
}
return nameCopy;
}
/* static */ PermissionsService*
PermissionsService::GetInstance()
{
static PermissionsService sPermissionsService;
return &sPermissionsService;
}
PermissionsService::PermissionsService() :
mFileAccessViolationFunc(nullptr)
{
}
void
PermissionsService::GrantFileAccess(uint32_t aProcessId,
const wchar_t* aFilename,
bool aPermitWrite)
{
FilePermissionMap& permissions = mProcessFilePermissions[aProcessId];
std::wstring filename = GetPlainFileName(aFilename);
permissions[filename] |= aPermitWrite;
}
void
PermissionsService::SetFileAccessViolationFunc(FileAccessViolationFunc aFavFunc)
{
mFileAccessViolationFunc = aFavFunc;
}
void
PermissionsService::ReportBlockedFile(bool aNeedsWrite)
{
if (mFileAccessViolationFunc) {
mFileAccessViolationFunc(aNeedsWrite);
}
}
bool
PermissionsService::UserGrantedFileAccess(uint32_t aProcessId,
const wchar_t* aFilename,
uint32_t aAccess,
uint32_t aDisposition)
{
// There are 3 types of permissions:
// * Those available w/ read-only permission
// * Those available w/ read-only AND read-write permission
// * Those always forbidden.
const uint32_t FORBIDDEN_FLAGS =
FILE_EXECUTE | FILE_LIST_DIRECTORY | FILE_TRAVERSE | STANDARD_RIGHTS_EXECUTE;
const uint32_t NEEDS_WRITE_FLAGS =
FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA |
DELETE | STANDARD_RIGHTS_WRITE;
bool needsWrite =
(aAccess & NEEDS_WRITE_FLAGS) || (aDisposition != FILE_OPEN);
if (aAccess & FORBIDDEN_FLAGS) {
ReportBlockedFile(needsWrite);
return false;
}
auto permissions = mProcessFilePermissions.find(aProcessId);
if (permissions == mProcessFilePermissions.end()) {
ReportBlockedFile(needsWrite);
return false; // process has no special file access at all
}
std::wstring filename = GetPlainFileName(aFilename);
auto itPermission = permissions->second.find(filename);
if (itPermission == permissions->second.end()) {
ReportBlockedFile(needsWrite);
return false; // process has no access to this file
}
// We have read permission. Check for write permission if requested.
if (!needsWrite || itPermission->second) {
return true;
}
// We needed write access but didn't have it.
ReportBlockedFile(needsWrite);
return false;
}
void
PermissionsService::RemovePermissionsForProcess(uint32_t aProcessId)
{
mProcessFilePermissions.erase(aProcessId);
}
} // namespace sandboxing
} // namespace mozilla

View File

@ -0,0 +1,78 @@
/* -*- 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/. */
#ifndef mozilla_sandboxing_permissionsService_h
#define mozilla_sandboxing_permissionsService_h
#include <unordered_map>
namespace mozilla {
namespace sandboxing {
/*
* Represents additional permissions granted to sandboxed processes.
* The members are virtual so that the object can be created in any
* library that links with libsandbox_s and then shared with and used
* by libXUL, which does not link with libsandbox_s.
*/
class PermissionsService
{
public:
static PermissionsService* GetInstance();
/*
* Allow future access to aFilename by the plugin process.
*/
virtual void GrantFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
bool aPermitWrite);
/*
* Type of callback function that the sandbox uses to report file
* accesses that were denied.
* Parameter is a boolean indicating the access request was read-only
* (false) or read-write (true)
*/
typedef void (*FileAccessViolationFunc)(bool);
/*
* Sets the callback function that is called whenever a file access is
* denied by the sandbox.
*/
virtual void SetFileAccessViolationFunc(FileAccessViolationFunc aFavFunc);
/*
* Returns true if the user has granted the sandboxed plugin process the
* requested permission to open the file.
* Calls aFavFunc with file info if the file access was blocked.
*/
virtual bool UserGrantedFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
uint32_t aAccess, uint32_t aDisposition);
/*
* Clears all special file access for the given plugin process.
*/
virtual void RemovePermissionsForProcess(uint32_t aProcessId);
private:
PermissionsService();
void ReportBlockedFile(bool aNeedsWrite);
// Maps from filenames to a boolean indicating read-only permission (false) or
// read-write permission (true).
typedef std::unordered_map<std::wstring, bool> FilePermissionMap;
// Maps from process ID to map of user-granted file permissions for
// that process.
typedef std::unordered_map<uint32_t, FilePermissionMap> ProcessFilePermissionMap;
ProcessFilePermissionMap mProcessFilePermissions;
FileAccessViolationFunc mFileAccessViolationFunc;
};
} // namespace sandboxing
} // namespace mozilla
#endif // mozilla_sandboxing_permissionsService_h

View File

@ -19,6 +19,7 @@ elif CONFIG['OS_ARCH'] == 'WINNT':
DIRS += [
'win/src/sandboxbroker',
'win/src/sandboxpermissions',
'win/src/sandboxtarget',
]
@ -29,6 +30,7 @@ elif CONFIG['OS_ARCH'] == 'WINNT':
EXPORTS.mozilla.sandboxing += [
'chromium-shim/sandbox/win/loggingCallbacks.h',
'chromium-shim/sandbox/win/loggingTypes.h',
'chromium-shim/sandbox/win/permissionsService.h',
'chromium-shim/sandbox/win/sandboxLogging.h',
'win/SandboxInitialization.h',
]
@ -36,6 +38,7 @@ elif CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [
'chromium-shim/base/files/file_path.cpp',
'chromium-shim/base/logging.cpp',
'chromium-shim/sandbox/win/permissionsService.cpp',
'chromium-shim/sandbox/win/sandboxLogging.cpp',
'chromium/base/at_exit.cc',
'chromium/base/base_switches.cc',

View File

@ -7,6 +7,7 @@
#include "SandboxInitialization.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "mozilla/sandboxing/permissionsService.h"
namespace mozilla {
namespace sandboxing {
@ -77,5 +78,10 @@ GetInitializedBrokerServices()
return sInitializedBrokerServices;
}
PermissionsService* GetPermissionsService()
{
return PermissionsService::GetInstance();
}
} // sandboxing
} // mozilla

View File

@ -21,6 +21,8 @@ namespace mozilla {
// sandbox for our namespace painful.
namespace sandboxing {
class PermissionsService;
/**
* Initializes (if required) and returns the Chromium sandbox TargetServices.
*
@ -41,6 +43,8 @@ void LowerSandbox();
*/
sandbox::BrokerServices* GetInitializedBrokerServices();
PermissionsService* GetPermissionsService();
} // sandboxing
} // mozilla

View File

@ -0,0 +1,22 @@
# -*- 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/.
SOURCES += [
'sandboxPermissions.cpp',
]
EXPORTS += [
'sandboxPermissions.h',
]
for var in ('UNICODE', '_UNICODE'):
DEFINES[var] = True
LOCAL_INCLUDES += [
'/security/sandbox/win',
]
FINAL_LIBRARY = 'xul'

View File

@ -0,0 +1,39 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 "sandboxPermissions.h"
#include "mozilla/Assertions.h"
#include "mozilla/sandboxing/permissionsService.h"
namespace mozilla
{
sandboxing::PermissionsService* SandboxPermissions::sPermissionsService = nullptr;
void
SandboxPermissions::Initialize(sandboxing::PermissionsService* aPermissionsService,
FileAccessViolationFunc aFileAccessViolationFunc)
{
sPermissionsService = aPermissionsService;
sPermissionsService->SetFileAccessViolationFunc(aFileAccessViolationFunc);
}
void
SandboxPermissions::GrantFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
bool aPermitWrite)
{
MOZ_ASSERT(sPermissionsService, "Must initialize sandbox PermissionsService");
sPermissionsService->GrantFileAccess(aProcessId, aFilename, aPermitWrite);
}
void
SandboxPermissions::RemovePermissionsForProcess(uint32_t aProcessId)
{
MOZ_ASSERT(sPermissionsService, "Must initialize sandbox PermissionsService");
sPermissionsService->RemovePermissionsForProcess(aProcessId);
}
} // namespace mozilla

View File

@ -0,0 +1,57 @@
/* -*- 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/. */
#ifndef mozilla_sandboxing_sandboxPermissions_h
#define mozilla_sandboxing_sandboxPermissions_h
#include <stdint.h>
#include <windows.h>
namespace mozilla {
namespace sandboxing {
class PermissionsService;
}
/*
* This object wraps a PermissionsService object. This object is available
* in libXUL but PermissionsService is not.
*/
class SandboxPermissions
{
public:
/*
* Type of callback function that the sandbox uses to report file
* accesses that were denied.
* Parameter is a boolean indicating the access request was read-only
* (false) or read-write (true)
*/
typedef void (*FileAccessViolationFunc)(bool);
/*
* Prepare this object by providing it with the internal permissions service.
*/
static void Initialize(sandboxing::PermissionsService* aPermissionsService,
FileAccessViolationFunc aFileAccessViolationFunc);
/*
* Allow future access to aFilename by the process with the given ID.
*/
void GrantFileAccess(uint32_t aProcessId, const wchar_t* aFilename,
bool aPermitWrite);
/*
* Clears all special file access for the given process.
*/
void RemovePermissionsForProcess(uint32_t aProcessId);
private:
static sandboxing::PermissionsService* sPermissionsService;
};
} // mozilla
#endif // mozilla_sandboxing_sandboxPermissions_h

View File

@ -31,11 +31,18 @@ class BrokerServices;
namespace mozilla {
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
namespace sandboxing {
class PermissionsService;
}
#endif
struct BootstrapConfig
{
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
/* Chromium sandbox BrokerServices. */
sandbox::BrokerServices* sandboxBrokerServices;
sandboxing::PermissionsService* sandboxPermissionsService;
#endif
/* Pointer to static XRE AppData from application.ini.h */
const StaticXREAppData* appData;

View File

@ -214,6 +214,7 @@
#include "mozilla/SandboxInfo.h"
#elif defined(XP_WIN)
#include "SandboxBroker.h"
#include "SandboxPermissions.h"
#endif
#endif
@ -3318,6 +3319,10 @@ XREMain::XRE_mainInit(bool* aExitFlag)
NS_WARNING("Failed to initialize broker services, sandboxed processes will "
"fail to start.");
}
if (mAppData->sandboxPermissionsService) {
SandboxPermissions::Initialize(mAppData->sandboxPermissionsService,
nullptr);
}
#endif
#ifdef XP_MACOSX
@ -4606,6 +4611,7 @@ XREMain::XRE_main(int argc, char* argv[], const BootstrapConfig& aConfig)
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
mAppData->sandboxBrokerServices = aConfig.sandboxBrokerServices;
mAppData->sandboxPermissionsService = aConfig.sandboxPermissionsService;
#endif
mozilla::IOInterposerInit ioInterposerGuard;

View File

@ -17,6 +17,11 @@
namespace sandbox {
class BrokerServices;
}
namespace mozilla {
namespace sandboxing {
class PermissionsService;
}
}
#endif
namespace mozilla {
@ -194,6 +199,7 @@ public:
* Chromium sandbox BrokerServices.
*/
sandbox::BrokerServices* sandboxBrokerServices = nullptr;
mozilla::sandboxing::PermissionsService* sandboxPermissionsService;
#endif
};

View File

@ -49,6 +49,7 @@ XREAppData::operator=(const XREAppData& aOther)
UAName = aOther.UAName;
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
sandboxBrokerServices = aOther.sandboxBrokerServices;
sandboxPermissionsService = aOther.sandboxPermissionsService;
#endif
return *this;
}