Commit e74d3916 authored by James Forshaw's avatar James Forshaw Committed by Commit Bot

Add new Non Admin Restricted security level.

This CL adds a new security level to the sandbox to create a non-admin
token which also has restricted SIDs. This shouldn't change the security
properties of the token but it will ensure that it passes the AppLocker
check and allow a child process with non-admin token to start.

Bug: 1007260
Change-Id: I9d8b79f46407764cb7c539c0ecddf6a6c555220c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1838553Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Commit-Queue: James Forshaw <forshaw@chromium.org>
Cr-Commit-Position: refs/heads/master@{#702537}
parent 58b42178
......@@ -15,27 +15,14 @@
namespace {
// Calls GetTokenInformation with the desired |info_class| and returns a buffer
// with the result.
// Wrapper for utility version to unwrap ScopedHandle.
std::unique_ptr<BYTE[]> GetTokenInfo(const base::win::ScopedHandle& token,
TOKEN_INFORMATION_CLASS info_class,
DWORD* error) {
// Get the required buffer size.
DWORD size = 0;
::GetTokenInformation(token.Get(), info_class, nullptr, 0, &size);
if (!size) {
*error = ::GetLastError();
std::unique_ptr<BYTE[]> buffer;
*error = sandbox::GetTokenInformation(token.Get(), info_class, &buffer);
if (*error != ERROR_SUCCESS)
return nullptr;
}
std::unique_ptr<BYTE[]> buffer(new BYTE[size]);
if (!::GetTokenInformation(token.Get(), info_class, buffer.get(), size,
&size)) {
*error = ::GetLastError();
return nullptr;
}
*error = ERROR_SUCCESS;
return buffer;
}
......
......@@ -12,6 +12,7 @@
#include "sandbox/win/src/sandbox.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "sandbox/win/src/target_services.h"
#include "sandbox/win/src/win_utils.h"
#include "sandbox/win/tests/common/controller.h"
#include "testing/gtest/include/gtest/gtest.h"
......@@ -61,6 +62,24 @@ SBOX_TESTS_COMMAND int RestrictedTokenTest_openprocess(int argc,
return SBOX_TEST_DENIED;
}
// Opens a the process token and checks if it's restricted.
SBOX_TESTS_COMMAND int RestrictedTokenTest_IsRestricted(int argc,
wchar_t** argv) {
HANDLE token_handle;
if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token_handle))
return SBOX_TEST_FIRST_ERROR;
base::win::ScopedHandle token(token_handle);
std::unique_ptr<BYTE[]> groups;
if (GetTokenInformation(token_handle, TokenRestrictedSids, &groups) !=
ERROR_SUCCESS) {
return SBOX_TEST_SECOND_ERROR;
}
auto* token_groups = reinterpret_cast<PTOKEN_GROUPS>(groups.get());
return token_groups->GroupCount > 0 ? SBOX_TEST_SUCCEEDED : SBOX_TEST_FAILED;
}
TEST(RestrictedTokenTest, OpenLowPrivilegedProcess) {
// Test limited privilege to renderer open.
ASSERT_EQ(SBOX_TEST_SUCCEEDED,
......@@ -77,4 +96,14 @@ TEST(RestrictedTokenTest, OpenLowPrivilegedProcess) {
RunOpenProcessTest(true, true, PROCESS_ALL_ACCESS));
}
TEST(RestrictedTokenTest, CheckNonAdminRestricted) {
TestRunner runner(JOB_NONE, USER_RESTRICTED_SAME_ACCESS, USER_NON_ADMIN);
EXPECT_EQ(SBOX_TEST_FAILED,
runner.RunTest(L"RestrictedTokenTest_IsRestricted"));
TestRunner runner_restricted(JOB_NONE, USER_RESTRICTED_SAME_ACCESS,
USER_RESTRICTED_NON_ADMIN);
EXPECT_EQ(SBOX_TEST_SUCCEEDED,
runner_restricted.RunTest(L"RestrictedTokenTest_IsRestricted"));
}
} // namespace sandbox
......@@ -92,6 +92,21 @@ DWORD CreateRestrictedToken(HANDLE effective_token,
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
break;
}
case USER_RESTRICTED_NON_ADMIN: {
sid_exceptions.push_back(WinBuiltinUsersSid);
sid_exceptions.push_back(WinWorldSid);
sid_exceptions.push_back(WinInteractiveSid);
sid_exceptions.push_back(WinAuthenticatedUserSid);
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
restricted_token.AddRestrictingSid(WinWorldSid);
restricted_token.AddRestrictingSid(WinInteractiveSid);
restricted_token.AddRestrictingSid(WinAuthenticatedUserSid);
restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
restricted_token.AddRestrictingSidCurrentUser();
restricted_token.AddRestrictingSidLogonSession();
break;
}
case USER_INTERACTIVE: {
sid_exceptions.push_back(WinBuiltinUsersSid);
sid_exceptions.push_back(WinWorldSid);
......
......@@ -50,6 +50,8 @@ std::string GetTokenLevelInEnglish(TokenLevel token) {
return "Restricted Same Access";
case USER_UNPROTECTED:
return "Unprotected";
case USER_RESTRICTED_NON_ADMIN:
return "Restricted Non Admin";
case USER_LAST:
default:
DCHECK(false) << "Unknown TokenType";
......
......@@ -58,6 +58,14 @@ enum IntegrityLevel {
// | | Authent-users | |
// | | User | |
// ----------------------------|--------------|----------------|----------|
// USER_RESTRICTED_NON_ADMIN | Users | All except: | Traverse |
// | Everyone | Users | |
// | Interactive | Everyone | |
// | Local | Interactive | |
// | Authent-users| Local | |
// | User | Authent-users | |
// | | User | |
// ----------------------------|--------------|----------------|----------|
// USER_NON_ADMIN | None | All except: | Traverse |
// | | Users | |
// | | Everyone | |
......@@ -86,6 +94,7 @@ enum TokenLevel {
USER_RESTRICTED,
USER_LIMITED,
USER_INTERACTIVE,
USER_RESTRICTED_NON_ADMIN,
USER_NON_ADMIN,
USER_RESTRICTED_SAME_ACCESS,
USER_UNPROTECTED,
......
......@@ -545,6 +545,26 @@ void* GetProcessBaseAddress(HANDLE process) {
return base_address;
}
DWORD GetTokenInformation(HANDLE token,
TOKEN_INFORMATION_CLASS info_class,
std::unique_ptr<BYTE[]>* buffer) {
// Get the required buffer size.
DWORD size = 0;
::GetTokenInformation(token, info_class, nullptr, 0, &size);
if (!size) {
return ::GetLastError();
}
auto temp_buffer = std::make_unique<BYTE[]>(size);
if (!::GetTokenInformation(token, info_class, temp_buffer.get(), size,
&size)) {
return ::GetLastError();
}
*buffer = std::move(temp_buffer);
return ERROR_SUCCESS;
}
} // namespace sandbox
void ResolveNTFunctionPtr(const char* name, void* ptr) {
......
......@@ -7,6 +7,7 @@
#include <stddef.h>
#include <windows.h>
#include <memory>
#include <string>
#include "base/macros.h"
......@@ -141,6 +142,12 @@ DWORD GetLastErrorFromNtStatus(NTSTATUS status);
// the base address. This should only be called on new, suspended processes.
void* GetProcessBaseAddress(HANDLE process);
// Calls GetTokenInformation with the desired |info_class| and returns a
// |buffer| and the Win32 error code.
DWORD GetTokenInformation(HANDLE token,
TOKEN_INFORMATION_CLASS info_class,
std::unique_ptr<BYTE[]>* buffer);
} // namespace sandbox
// Resolves a function name in NTDLL to a function pointer. The second parameter
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment