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       ::CloseHandle(local_handle);
    128       return STATUS_ACCESS_DENIED;
    129     }
    130   }
    131 
    132   return status;
    133 }
    134 
    135 NTSTATUS ProcessPolicy::OpenProcessAction(const ClientInfo& client_info,
    136                                           uint32 desired_access,
    137                                           uint32 process_id,
    138                                           HANDLE* handle) {
    139   *handle = NULL;
    140 
    141   NtOpenProcessFunction NtOpenProcess = NULL;
    142   ResolveNTFunctionPtr("NtOpenProcess", &NtOpenProcess);
    143 
    144   if (client_info.process_id != process_id)
    145     return STATUS_ACCESS_DENIED;
    146 
    147   OBJECT_ATTRIBUTES attributes = {0};
    148   attributes.Length = sizeof(attributes);
    149   CLIENT_ID client_id = {0};
    150   client_id.UniqueProcess = reinterpret_cast<PVOID>(
    151                                 static_cast<ULONG_PTR>(client_info.process_id));
    152   HANDLE local_handle;
    153   NTSTATUS status = NtOpenProcess(&local_handle, desired_access, &attributes,
    154                                   &client_id);
    155   if (NT_SUCCESS(status)) {
    156     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    157                            client_info.process, handle, 0, FALSE,
    158                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    159       ::CloseHandle(local_handle);
    160       return STATUS_ACCESS_DENIED;
    161     }
    162   }
    163 
    164   return status;
    165 }
    166 
    167 NTSTATUS ProcessPolicy::OpenProcessTokenAction(const ClientInfo& client_info,
    168                                                HANDLE process,
    169                                                uint32 desired_access,
    170                                                HANDLE* handle) {
    171   *handle = NULL;
    172   NtOpenProcessTokenFunction NtOpenProcessToken = NULL;
    173   ResolveNTFunctionPtr("NtOpenProcessToken", &NtOpenProcessToken);
    174 
    175   if (CURRENT_PROCESS != process)
    176     return STATUS_ACCESS_DENIED;
    177 
    178   HANDLE local_handle;
    179   NTSTATUS status = NtOpenProcessToken(client_info.process, desired_access,
    180                                        &local_handle);
    181   if (NT_SUCCESS(status)) {
    182     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    183                            client_info.process, handle, 0, FALSE,
    184                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    185       ::CloseHandle(local_handle);
    186       return STATUS_ACCESS_DENIED;
    187     }
    188   }
    189   return status;
    190 }
    191 
    192 NTSTATUS ProcessPolicy::OpenProcessTokenExAction(const ClientInfo& client_info,
    193                                                  HANDLE process,
    194                                                  uint32 desired_access,
    195                                                  uint32 attributes,
    196                                                  HANDLE* handle) {
    197   *handle = NULL;
    198   NtOpenProcessTokenExFunction NtOpenProcessTokenEx = NULL;
    199   ResolveNTFunctionPtr("NtOpenProcessTokenEx", &NtOpenProcessTokenEx);
    200 
    201   if (CURRENT_PROCESS != process)
    202     return STATUS_ACCESS_DENIED;
    203 
    204   HANDLE local_handle;
    205   NTSTATUS status = NtOpenProcessTokenEx(client_info.process, desired_access,
    206                                          attributes, &local_handle);
    207   if (NT_SUCCESS(status)) {
    208     if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    209                            client_info.process, handle, 0, FALSE,
    210                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    211       ::CloseHandle(local_handle);
    212       return STATUS_ACCESS_DENIED;
    213     }
    214   }
    215   return status;
    216 }
    217 
    218 DWORD ProcessPolicy::CreateProcessWAction(EvalResult eval_result,
    219                                           const ClientInfo& client_info,
    220                                           const base::string16 &app_name,
    221                                           const base::string16 &command_line,
    222                                           PROCESS_INFORMATION* process_info) {
    223   // The only action supported is ASK_BROKER which means create the process.
    224   if (GIVE_ALLACCESS != eval_result && GIVE_READONLY != eval_result) {
    225     return ERROR_ACCESS_DENIED;
    226   }
    227 
    228   STARTUPINFO startup_info = {0};
    229   startup_info.cb = sizeof(startup_info);
    230   scoped_ptr<wchar_t, base::FreeDeleter>
    231       cmd_line(_wcsdup(command_line.c_str()));
    232 
    233   BOOL should_give_full_access = (GIVE_ALLACCESS == eval_result);
    234   if (!CreateProcessExWHelper(client_info.process, should_give_full_access,
    235                               app_name.c_str(), cmd_line.get(), NULL, NULL,
    236                               FALSE, 0, NULL, NULL, &startup_info,
    237                               process_info)) {
    238     return ERROR_ACCESS_DENIED;
    239   }
    240   return ERROR_SUCCESS;
    241 }
    242 
    243 }  // namespace sandbox
    244