security/sandbox/win/src/restricted_token_utils.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 #include <aclapi.h>
     6 #include <sddl.h>
     7 #include <vector>
     9 #include "sandbox/win/src/restricted_token_utils.h"
    11 #include "base/logging.h"
    12 #include "base/win/scoped_handle.h"
    13 #include "base/win/scoped_process_information.h"
    14 #include "base/win/windows_version.h"
    15 #include "sandbox/win/src/job.h"
    16 #include "sandbox/win/src/restricted_token.h"
    17 #include "sandbox/win/src/security_level.h"
    18 #include "sandbox/win/src/sid.h"
    20 namespace sandbox {
    22 DWORD CreateRestrictedToken(HANDLE *token_handle,
    23                             TokenLevel security_level,
    24                             IntegrityLevel integrity_level,
    25                             TokenType token_type) {
    26   if (!token_handle)
    27     return ERROR_BAD_ARGUMENTS;
    29   RestrictedToken restricted_token;
    30   restricted_token.Init(NULL);  // Initialized with the current process token
    32   std::vector<std::wstring> privilege_exceptions;
    33   std::vector<Sid> sid_exceptions;
    35   bool deny_sids = true;
    36   bool remove_privileges = true;
    38   switch (security_level) {
    39     case USER_UNPROTECTED: {
    40       deny_sids = false;
    41       remove_privileges = false;
    42       break;
    43     }
    44     case USER_RESTRICTED_SAME_ACCESS: {
    45       deny_sids = false;
    46       remove_privileges = false;
    48       unsigned err_code = restricted_token.AddRestrictingSidAllSids();
    49       if (ERROR_SUCCESS != err_code)
    50         return err_code;
    52       break;
    53     }
    54     case USER_NON_ADMIN: {
    55       sid_exceptions.push_back(WinBuiltinUsersSid);
    56       sid_exceptions.push_back(WinWorldSid);
    57       sid_exceptions.push_back(WinInteractiveSid);
    58       sid_exceptions.push_back(WinAuthenticatedUserSid);
    59       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
    60       break;
    61     }
    62     case USER_INTERACTIVE: {
    63       sid_exceptions.push_back(WinBuiltinUsersSid);
    64       sid_exceptions.push_back(WinWorldSid);
    65       sid_exceptions.push_back(WinInteractiveSid);
    66       sid_exceptions.push_back(WinAuthenticatedUserSid);
    67       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
    68       restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
    69       restricted_token.AddRestrictingSid(WinWorldSid);
    70       restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
    71       restricted_token.AddRestrictingSidCurrentUser();
    72       restricted_token.AddRestrictingSidLogonSession();
    73       break;
    74     }
    75     case USER_LIMITED: {
    76       sid_exceptions.push_back(WinBuiltinUsersSid);
    77       sid_exceptions.push_back(WinWorldSid);
    78       sid_exceptions.push_back(WinInteractiveSid);
    79       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
    80       restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
    81       restricted_token.AddRestrictingSid(WinWorldSid);
    82       restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
    84       // This token has to be able to create objects in BNO.
    85       // Unfortunately, on vista, it needs the current logon sid
    86       // in the token to achieve this. You should also set the process to be
    87       // low integrity level so it can't access object created by other
    88       // processes.
    89       if (base::win::GetVersion() >= base::win::VERSION_VISTA)
    90         restricted_token.AddRestrictingSidLogonSession();
    91       break;
    92     }
    93     case USER_RESTRICTED: {
    94       privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
    95       restricted_token.AddUserSidForDenyOnly();
    96       restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
    97       break;
    98     }
    99     case USER_LOCKDOWN: {
   100       restricted_token.AddUserSidForDenyOnly();
   101       restricted_token.AddRestrictingSid(WinNullSid);
   102       break;
   103     }
   104     default: {
   105       return ERROR_BAD_ARGUMENTS;
   106     }
   107   }
   109   DWORD err_code = ERROR_SUCCESS;
   110   if (deny_sids) {
   111     err_code = restricted_token.AddAllSidsForDenyOnly(&sid_exceptions);
   112     if (ERROR_SUCCESS != err_code)
   113       return err_code;
   114   }
   116   if (remove_privileges) {
   117     err_code = restricted_token.DeleteAllPrivileges(&privilege_exceptions);
   118     if (ERROR_SUCCESS != err_code)
   119       return err_code;
   120   }
   122   restricted_token.SetIntegrityLevel(integrity_level);
   124   switch (token_type) {
   125     case PRIMARY: {
   126       err_code = restricted_token.GetRestrictedTokenHandle(token_handle);
   127       break;
   128     }
   129     case IMPERSONATION: {
   130       err_code = restricted_token.GetRestrictedTokenHandleForImpersonation(
   131           token_handle);
   132       break;
   133     }
   134     default: {
   135       err_code = ERROR_BAD_ARGUMENTS;
   136       break;
   137     }
   138   }
   140   return err_code;
   141 }
   143 DWORD StartRestrictedProcessInJob(wchar_t *command_line,
   144                                   TokenLevel primary_level,
   145                                   TokenLevel impersonation_level,
   146                                   JobLevel job_level,
   147                                   HANDLE *const job_handle_ret) {
   148   Job job;
   149   DWORD err_code = job.Init(job_level, NULL, 0);
   150   if (ERROR_SUCCESS != err_code)
   151     return err_code;
   153   if (JOB_UNPROTECTED != job_level) {
   154     // Share the Desktop handle to be able to use MessageBox() in the sandboxed
   155     // application.
   156     err_code = job.UserHandleGrantAccess(GetDesktopWindow());
   157     if (ERROR_SUCCESS != err_code)
   158       return err_code;
   159   }
   161   // Create the primary (restricted) token for the process
   162   HANDLE primary_token_handle = NULL;
   163   err_code = CreateRestrictedToken(&primary_token_handle,
   164                                    primary_level,
   165                                    INTEGRITY_LEVEL_LAST,
   166                                    PRIMARY);
   167   if (ERROR_SUCCESS != err_code) {
   168     return err_code;
   169   }
   170   base::win::ScopedHandle primary_token(primary_token_handle);
   172   // Create the impersonation token (restricted) to be able to start the
   173   // process.
   174   HANDLE impersonation_token_handle;
   175   err_code = CreateRestrictedToken(&impersonation_token_handle,
   176                                    impersonation_level,
   177                                    INTEGRITY_LEVEL_LAST,
   178                                    IMPERSONATION);
   179   if (ERROR_SUCCESS != err_code) {
   180     return err_code;
   181   }
   182   base::win::ScopedHandle impersonation_token(impersonation_token_handle);
   184   // Start the process
   185   STARTUPINFO startup_info = {0};
   186   base::win::ScopedProcessInformation process_info;
   187   DWORD flags = CREATE_SUSPENDED;
   189   if (base::win::GetVersion() < base::win::VERSION_WIN8) {
   190     // Windows 8 implements nested jobs, but for older systems we need to
   191     // break out of any job we're in to enforce our restrictions.
   192     flags |= CREATE_BREAKAWAY_FROM_JOB;
   193   }
   195   if (!::CreateProcessAsUser(primary_token.Get(),
   196                              NULL,   // No application name.
   197                              command_line,
   198                              NULL,   // No security attribute.
   199                              NULL,   // No thread attribute.
   200                              FALSE,  // Do not inherit handles.
   201                              flags,
   202                              NULL,   // Use the environment of the caller.
   203                              NULL,   // Use current directory of the caller.
   204                              &startup_info,
   205                              process_info.Receive())) {
   206     return ::GetLastError();
   207   }
   209   // Change the token of the main thread of the new process for the
   210   // impersonation token with more rights.
   211   {
   212     HANDLE temp_thread = process_info.thread_handle();
   213     if (!::SetThreadToken(&temp_thread, impersonation_token.Get())) {
   214       ::TerminateProcess(process_info.process_handle(),
   215                          0);  // exit code
   216       return ::GetLastError();
   217     }
   218   }
   220   err_code = job.AssignProcessToJob(process_info.process_handle());
   221   if (ERROR_SUCCESS != err_code) {
   222     ::TerminateProcess(process_info.process_handle(),
   223                        0);  // exit code
   224     return ::GetLastError();
   225   }
   227   // Start the application
   228   ::ResumeThread(process_info.thread_handle());
   230   (*job_handle_ret) = job.Detach();
   232   return ERROR_SUCCESS;
   233 }
   235 DWORD SetObjectIntegrityLabel(HANDLE handle, SE_OBJECT_TYPE type,
   236                               const wchar_t* ace_access,
   237                               const wchar_t* integrity_level_sid) {
   238   // Build the SDDL string for the label.
   239   std::wstring sddl = L"S:(";     // SDDL for a SACL.
   240   sddl += SDDL_MANDATORY_LABEL;   // Ace Type is "Mandatory Label".
   241   sddl += L";;";                  // No Ace Flags.
   242   sddl += ace_access;             // Add the ACE access.
   243   sddl += L";;;";                 // No ObjectType and Inherited Object Type.
   244   sddl += integrity_level_sid;    // Trustee Sid.
   245   sddl += L")";
   247   DWORD error = ERROR_SUCCESS;
   248   PSECURITY_DESCRIPTOR sec_desc = NULL;
   250   PACL sacl = NULL;
   251   BOOL sacl_present = FALSE;
   252   BOOL sacl_defaulted = FALSE;
   254   if (::ConvertStringSecurityDescriptorToSecurityDescriptorW(sddl.c_str(),
   255                                                              SDDL_REVISION,
   256                                                              &sec_desc, NULL)) {
   257     if (::GetSecurityDescriptorSacl(sec_desc, &sacl_present, &sacl,
   258                                     &sacl_defaulted)) {
   259       error = ::SetSecurityInfo(handle, type,
   260                                 LABEL_SECURITY_INFORMATION, NULL, NULL, NULL,
   261                                 sacl);
   262     } else {
   263       error = ::GetLastError();
   264     }
   266     ::LocalFree(sec_desc);
   267   } else {
   268     return::GetLastError();
   269   }
   271   return error;
   272 }
   274 const wchar_t* GetIntegrityLevelString(IntegrityLevel integrity_level) {
   275   switch (integrity_level) {
   276     case INTEGRITY_LEVEL_SYSTEM:
   277       return L"S-1-16-16384";
   278     case INTEGRITY_LEVEL_HIGH:
   279       return L"S-1-16-12288";
   280     case INTEGRITY_LEVEL_MEDIUM:
   281       return L"S-1-16-8192";
   282     case INTEGRITY_LEVEL_MEDIUM_LOW:
   283       return L"S-1-16-6144";
   284     case INTEGRITY_LEVEL_LOW:
   285       return L"S-1-16-4096";
   286     case INTEGRITY_LEVEL_BELOW_LOW:
   287       return L"S-1-16-2048";
   288     case INTEGRITY_LEVEL_UNTRUSTED:
   289       return L"S-1-16-0";
   290     case INTEGRITY_LEVEL_LAST:
   291       return NULL;
   292   }
   294   NOTREACHED();
   295   return NULL;
   296 }
   297 DWORD SetTokenIntegrityLevel(HANDLE token, IntegrityLevel integrity_level) {
   298   if (base::win::GetVersion() < base::win::VERSION_VISTA)
   299     return ERROR_SUCCESS;
   301   const wchar_t* integrity_level_str = GetIntegrityLevelString(integrity_level);
   302   if (!integrity_level_str) {
   303     // No mandatory level specified, we don't change it.
   304     return ERROR_SUCCESS;
   305   }
   307   PSID integrity_sid = NULL;
   308   if (!::ConvertStringSidToSid(integrity_level_str, &integrity_sid))
   309     return ::GetLastError();
   311   TOKEN_MANDATORY_LABEL label = {0};
   312   label.Label.Attributes = SE_GROUP_INTEGRITY;
   313   label.Label.Sid = integrity_sid;
   315   DWORD size = sizeof(TOKEN_MANDATORY_LABEL) + ::GetLengthSid(integrity_sid);
   316   BOOL result = ::SetTokenInformation(token, TokenIntegrityLevel, &label,
   317                                       size);
   318   ::LocalFree(integrity_sid);
   320   return result ? ERROR_SUCCESS : ::GetLastError();
   321 }
   323 DWORD SetProcessIntegrityLevel(IntegrityLevel integrity_level) {
   324   if (base::win::GetVersion() < base::win::VERSION_VISTA)
   325     return ERROR_SUCCESS;
   327   // We don't check for an invalid level here because we'll just let it
   328   // fail on the SetTokenIntegrityLevel call later on.
   329   if (integrity_level == INTEGRITY_LEVEL_LAST) {
   330     // No mandatory level specified, we don't change it.
   331     return ERROR_SUCCESS;
   332   }
   334   HANDLE token_handle;
   335   if (!::OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_DEFAULT,
   336                           &token_handle))
   337     return ::GetLastError();
   339   base::win::ScopedHandle token(token_handle);
   341   return SetTokenIntegrityLevel(token.Get(), integrity_level);
   342 }
   344 }  // namespace sandbox

mercurial