• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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().
CreateProcessExWHelper(HANDLE target_process,BOOL give_full_access,LPCWSTR lpApplicationName,LPWSTR lpCommandLine,LPSECURITY_ATTRIBUTES lpProcessAttributes,LPSECURITY_ATTRIBUTES lpThreadAttributes,BOOL bInheritHandles,DWORD dwCreationFlags,LPVOID lpEnvironment,LPCWSTR lpCurrentDirectory,LPSTARTUPINFOW lpStartupInfo,LPPROCESS_INFORMATION lpProcessInformation)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 
GenerateRules(const wchar_t * name,TargetPolicy::Semantics semantics,LowLevelPolicy * policy)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 
OpenThreadAction(const ClientInfo & client_info,uint32 desired_access,uint32 thread_id,HANDLE * handle)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 
OpenProcessAction(const ClientInfo & client_info,uint32 desired_access,uint32 process_id,HANDLE * handle)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 
OpenProcessTokenAction(const ClientInfo & client_info,HANDLE process,uint32 desired_access,HANDLE * handle)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 
OpenProcessTokenExAction(const ClientInfo & client_info,HANDLE process,uint32 desired_access,uint32 attributes,HANDLE * handle)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 
CreateProcessWAction(EvalResult eval_result,const ClientInfo & client_info,const base::string16 & app_name,const base::string16 & command_line,PROCESS_INFORMATION * process_info)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