Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2011 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.
      4 
      5 #include "sandbox/win/src/process_thread_policy.h"
      6 
      7 #include <string>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 #include "sandbox/win/src/ipc_tags.h"
     11 #include "sandbox/win/src/nt_internals.h"
     12 #include "sandbox/win/src/policy_engine_opcodes.h"
     13 #include "sandbox/win/src/policy_params.h"
     14 #include "sandbox/win/src/sandbox_types.h"
     15 #include "sandbox/win/src/win_utils.h"
     16 
     17 namespace {
     18 
     19 // These are the only safe rights that can be given to a sandboxed
     20 // process for the process created by the broker. All others are potential
     21 // vectors of privilege elevation.
     22 const DWORD kProcessRights = SYNCHRONIZE |
     23                              PROCESS_QUERY_INFORMATION |
     24                              PROCESS_QUERY_LIMITED_INFORMATION |
     25                              PROCESS_TERMINATE |
     26                              PROCESS_SUSPEND_RESUME;
     27 
     28 const DWORD kThreadRights = SYNCHRONIZE |
     29                             THREAD_TERMINATE |
     30                             THREAD_SUSPEND_RESUME |
     31                             THREAD_QUERY_INFORMATION |
     32                             THREAD_QUERY_LIMITED_INFORMATION |
     33                             THREAD_SET_LIMITED_INFORMATION;
     34 
     35 // Creates a child process and duplicates the handles to 'target_process'. The
     36 // remaining parameters are the same as CreateProcess().
     37 BOOL CreateProcessExWHelper(HANDLE target_process, BOOL give_full_access,
     38                             LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
     39                             LPSECURITY_ATTRIBUTES lpProcessAttributes,
     40                             LPSECURITY_ATTRIBUTES lpThreadAttributes,
     41                             BOOL bInheritHandles, DWORD dwCreationFlags,
     42                             LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
     43                             LPSTARTUPINFOW lpStartupInfo,
     44                             LPPROCESS_INFORMATION lpProcessInformation) {
     45   if (!::CreateProcessW(lpApplicationName, lpCommandLine, lpProcessAttributes,
     46                         lpThreadAttributes, bInheritHandles, dwCreationFlags,
     47                         lpEnvironment, lpCurrentDirectory, lpStartupInfo,
     48                         lpProcessInformation)) {
     49     return FALSE;
     50   }
     51 
     52   DWORD process_access = kProcessRights;
     53   DWORD thread_access = kThreadRights;
     54   if (give_full_access) {
     55     process_access = PROCESS_ALL_ACCESS;
     56     thread_access = THREAD_ALL_ACCESS;
     57   }
     58   if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hProcess,
     59                          target_process, &lpProcessInformation->hProcess,
     60                          process_access, FALSE, DUPLICATE_CLOSE_SOURCE)) {
     61     ::CloseHandle(lpProcessInformation->hThread);
     62     return FALSE;
     63   }
     64   if (!::DuplicateHandle(::GetCurrentProcess(), lpProcessInformation->hThread,
     65                          target_process, &lpProcessInformation->hThread,
     66                          thread_access, FALSE, DUPLICATE_CLOSE_SOURCE)) {
     67     return FALSE;
     68   }
     69   return TRUE;
     70 }
     71 
     72 }
     73 
     74 namespace sandbox {
     75 
     76 bool ProcessPolicy::GenerateRules(const wchar_t* name,
     77                                   TargetPolicy::Semantics semantics,
     78                                   LowLevelPolicy* policy) {
     79   scoped_ptr<PolicyRule> process;
     80   switch (semantics) {
     81     case TargetPolicy::PROCESS_MIN_EXEC: {
     82       process.reset(new PolicyRule(GIVE_READONLY));
     83       break;
     84     };
     85     case TargetPolicy::PROCESS_ALL_EXEC: {
     86       process.reset(new PolicyRule(GIVE_ALLACCESS));
     87       break;
     88     };
     89     default: {
     90       return false;
     91     };
     92   }
     93 
     94   if (!process->AddStringMatch(IF, NameBased::NAME, name, CASE_INSENSITIVE)) {
     95     return false;
     96   }
     97   if (!policy->AddRule(IPC_CREATEPROCESSW_TAG, process.get())) {
     98     return false;
     99   }
    100   return true;
    101 }
    102 
    103 NTSTATUS ProcessPolicy::OpenThreadAction(const ClientInfo& client_info,
    104                                          uint32 desired_access,
    105                                          uint32 thread_id,
    106                                          HANDLE* handle) {
    107   *handle = NULL;
    108 
    109   NtOpenThreadFunction NtOpenThread = NULL;
    110   ResolveNTFunctionPtr("NtOpenThread", &NtOpenThread);
    111 
    112   OBJECT_ATTRIBUTES attributes = {0};
    113   attributes.Length = sizeof(attributes);
    114   CLIENT_ID client_id = {0};
    115   client_id.UniqueProcess = reinterpret_cast<PVOID>(
    116                                 static_cast<ULONG_PTR>(client_info.process_id));
    117   client_id.UniqueThread =
    118       reinterpret_cast<PVOID>(static_cast<ULONG_PTR>(thread_id));
    119 
    120   HANDLE local_handle;
    121   NTSTATUS status = NtOpenThread(&local_handle, desired_access, &attributes,
    122                                  &client_id);
    123   if (NT_SUCCESS(status)) {
    124     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    125                            client_info.process, handle, 0, FALSE,
    126                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    127       return STATUS_ACCESS_DENIED;
    128     }
    129   }
    130 
    131   return status;
    132 }
    133 
    134 NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info,
    135                                           uint32 desired_access,
    136                                           uint32 process_id,
    137                                           HANDLE* handle) {
    138   *handle = NULL;
    139 
    140   NtOpenProcessFunction NtOpenProcess = NULL;
    141   ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess);
    142 
    143   if (client_info.process_id != process_id)
    144     return STATUS_ACCESS_DENIED;
    145 
    146   OBJECT_ATTRIBUTES attributes = {0};
    147   attributes.Length = sizeof(attributes);
    148   CLIENT_ID client_id = {0};
    149   client_id.UniqueProcess = reinterpret_cast<PVOID>(
    150                                 static_cast<ULONG_PTR>(client_info.process_id));
    151   HANDLE local_handle;
    152   NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes,
    153                                   &client_id);
    154   if (NT_SUCCESS(status)) {
    155     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    156                            client_info.process, handle, 0, FALSE,
    157                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    158       return STATUS_ACCESS_DENIED;
    159     }
    160   }
    161 
    162   return status;
    163 }
    164 
    165 NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info,
    166                                                HANDLE process,
    167                                                uint32 desired_access,
    168                                                HANDLE* handle) {
    169   *handle = NULL;
    170   NtOpenProcessTokenFunction NtOpenProcessToken = NULL;
    171   ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken);
    172 
    173   if (CURRENT_PROCESS != process)
    174     return STATUS_ACCESS_DENIED;
    175 
    176   HANDLE local_handle;
    177   NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access,
    178                                        &local_handle);
    179   if (NT_SUCCESS(status)) {
    180     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    181                            client_info.process, handle, 0, FALSE,
    182                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    183       return STATUS_ACCESS_DENIED;
    184     }
    185   }
    186   return status;
    187 }
    188 
    189 NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info,
    190                                                  HANDLE process,
    191                                                  uint32 desired_access,
    192                                                  uint32 attributes,
    193                                                  HANDLE* handle) {
    194   *handle = NULL;
    195   NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL;
    196   ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx);
    197 
    198   if (CURRENT_PROCESS != process)
    199     return STATUS_ACCESS_DENIED;
    200 
    201   HANDLE local_handle;
    202   NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access,
    203                                          attributes, &local_handle);
    204   if (NT_SUCCESS(status)) {
    205     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    206                            client_info.process, handle, 0, FALSE,
    207                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    208       return STATUS_ACCESS_DENIED;
    209     }
    210   }
    211   return status;
    212 }
    213 
    214 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result,
    215                                           const ClientInfo& client_info,
    216                                           const base::string16 &app_name,
    217                                           const base::string16 &command_line,
    218                                           PROCESS_INFORMATION* process_info) {
    219   // The only action supported is ASK_BROKER which means create the process.
    220   if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) {
    221     return ERROR_ACCESS_DENIED;
    222   }
    223 
    224   STARTUPINFO startup_info = {0};
    225   startup_info.cb = sizeof(startup_info);
    226   scoped_ptr<wchar_t, base::FreeDeleter>
    227       cmd_line(_wcsdup(command_line.c_str()));
    228 
    229   BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result);
    230   if (!CreateProcessExWHelper(client_info.process, should_give_full_access,
    231                               app_name.c_str(), cmd_line.get(), NULL, NULL,
    232                               FALSE, 0, NULL, NULL, &startup_info,
    233                               process_info)) {
    234     return ERROR_ACCESS_DENIED;
    235   }
    236   return ERROR_SUCCESS;
    237 }
    238 
    239 }  // namespace sandbox
    240