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 @@ ...@@ -15,27 +15,14 @@
namespace { namespace {
// Calls GetTokenInformation with the desired |info_class| and returns a buffer // Wrapper for utility version to unwrap ScopedHandle.
// with the result.
std::unique_ptr<BYTE[]> GetTokenInfo(const base::win::ScopedHandle& token, std::unique_ptr<BYTE[]> GetTokenInfo(const base::win::ScopedHandle& token,
TOKEN_INFORMATION_CLASS info_class, TOKEN_INFORMATION_CLASS info_class,
DWORD* error) { DWORD* error) {
// Get the required buffer size. std::unique_ptr<BYTE[]> buffer;
DWORD size = 0; *error = sandbox::GetTokenInformation(token.Get(), info_class, &buffer);
::GetTokenInformation(token.Get(), info_class, nullptr, 0, &size); if (*error != ERROR_SUCCESS)
if (!size) {
*error = ::GetLastError();
return nullptr; 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; return buffer;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "sandbox/win/src/sandbox.h" #include "sandbox/win/src/sandbox.h"
#include "sandbox/win/src/sandbox_factory.h" #include "sandbox/win/src/sandbox_factory.h"
#include "sandbox/win/src/target_services.h" #include "sandbox/win/src/target_services.h"
#include "sandbox/win/src/win_utils.h"
#include "sandbox/win/tests/common/controller.h" #include "sandbox/win/tests/common/controller.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -61,6 +62,24 @@ SBOX_TESTS_COMMAND int RestrictedTokenTest_openprocess(int argc, ...@@ -61,6 +62,24 @@ SBOX_TESTS_COMMAND int RestrictedTokenTest_openprocess(int argc,
return SBOX_TEST_DENIED; 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(RestrictedTokenTest, OpenLowPrivilegedProcess) {
// Test limited privilege to renderer open. // Test limited privilege to renderer open.
ASSERT_EQ(SBOX_TEST_SUCCEEDED, ASSERT_EQ(SBOX_TEST_SUCCEEDED,
...@@ -77,4 +96,14 @@ TEST(RestrictedTokenTest, OpenLowPrivilegedProcess) { ...@@ -77,4 +96,14 @@ TEST(RestrictedTokenTest, OpenLowPrivilegedProcess) {
RunOpenProcessTest(true, true, PROCESS_ALL_ACCESS)); 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 } // namespace sandbox
...@@ -92,6 +92,21 @@ DWORD CreateRestrictedToken(HANDLE effective_token, ...@@ -92,6 +92,21 @@ DWORD CreateRestrictedToken(HANDLE effective_token,
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME); privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
break; 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: { case USER_INTERACTIVE: {
sid_exceptions.push_back(WinBuiltinUsersSid); sid_exceptions.push_back(WinBuiltinUsersSid);
sid_exceptions.push_back(WinWorldSid); sid_exceptions.push_back(WinWorldSid);
......
...@@ -50,6 +50,8 @@ std::string GetTokenLevelInEnglish(TokenLevel token) { ...@@ -50,6 +50,8 @@ std::string GetTokenLevelInEnglish(TokenLevel token) {
return "Restricted Same Access"; return "Restricted Same Access";
case USER_UNPROTECTED: case USER_UNPROTECTED:
return "Unprotected"; return "Unprotected";
case USER_RESTRICTED_NON_ADMIN:
return "Restricted Non Admin";
case USER_LAST: case USER_LAST:
default: default:
DCHECK(false) << "Unknown TokenType"; DCHECK(false) << "Unknown TokenType";
......
...@@ -58,6 +58,14 @@ enum IntegrityLevel { ...@@ -58,6 +58,14 @@ enum IntegrityLevel {
// | | Authent-users | | // | | Authent-users | |
// | | User | | // | | 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 | // USER_NON_ADMIN | None | All except: | Traverse |
// | | Users | | // | | Users | |
// | | Everyone | | // | | Everyone | |
...@@ -86,6 +94,7 @@ enum TokenLevel { ...@@ -86,6 +94,7 @@ enum TokenLevel {
USER_RESTRICTED, USER_RESTRICTED,
USER_LIMITED, USER_LIMITED,
USER_INTERACTIVE, USER_INTERACTIVE,
USER_RESTRICTED_NON_ADMIN,
USER_NON_ADMIN, USER_NON_ADMIN,
USER_RESTRICTED_SAME_ACCESS, USER_RESTRICTED_SAME_ACCESS,
USER_UNPROTECTED, USER_UNPROTECTED,
......
...@@ -545,6 +545,26 @@ void* GetProcessBaseAddress(HANDLE process) { ...@@ -545,6 +545,26 @@ void* GetProcessBaseAddress(HANDLE process) {
return base_address; 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 } // namespace sandbox
void ResolveNTFunctionPtr(const char* name, void* ptr) { void ResolveNTFunctionPtr(const char* name, void* ptr) {
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <windows.h> #include <windows.h>
#include <memory>
#include <string> #include <string>
#include "base/macros.h" #include "base/macros.h"
...@@ -141,6 +142,12 @@ DWORD GetLastErrorFromNtStatus(NTSTATUS status); ...@@ -141,6 +142,12 @@ DWORD GetLastErrorFromNtStatus(NTSTATUS status);
// the base address. This should only be called on new, suspended processes. // the base address. This should only be called on new, suspended processes.
void* GetProcessBaseAddress(HANDLE process); 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 } // namespace sandbox
// Resolves a function name in NTDLL to a function pointer. The second parameter // 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