OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2010 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/src/process_thread_dispatcher.h" | |
6 | |
7 #include "base/basictypes.h" | |
8 #include "base/logging.h" | |
9 #include "sandbox/src/crosscall_client.h" | |
10 #include "sandbox/src/interception.h" | |
11 #include "sandbox/src/interceptors.h" | |
12 #include "sandbox/src/ipc_tags.h" | |
13 #include "sandbox/src/policy_broker.h" | |
14 #include "sandbox/src/policy_params.h" | |
15 #include "sandbox/src/process_thread_interception.h" | |
16 #include "sandbox/src/process_thread_policy.h" | |
17 #include "sandbox/src/sandbox.h" | |
18 | |
19 namespace { | |
20 | |
21 // Extracts the application name from a command line. | |
22 // | |
23 // The application name is the first element of the command line. If | |
24 // there is no quotes, the first element is delimited by the first space. | |
25 // If there are quotes, the first element is delimited by the quotes. | |
26 // | |
27 // The create process call is smarter than us. It tries really hard to launch | |
28 // the process even if the command line is wrong. For example: | |
29 // "c:\program files\test param" will first try to launch c:\program.exe then | |
30 // c:\program files\test.exe. We don't do that, we stop after at the first | |
31 // space when there is no quotes. | |
32 std::wstring GetPathFromCmdLine(const std::wstring &cmd_line) { | |
33 std::wstring exe_name; | |
34 // Check if it starts with '"'. | |
35 if (cmd_line[0] == L'\"') { | |
36 // Find the position of the second '"', this terminates the path. | |
37 std::wstring::size_type pos = cmd_line.find(L'\"', 1); | |
38 if (std::wstring::npos == pos) | |
39 return cmd_line; | |
40 exe_name = cmd_line.substr(1, pos - 1); | |
41 } else { | |
42 // There is no '"', that means that the appname is terminated at the | |
43 // first space. | |
44 std::wstring::size_type pos = cmd_line.find(L' '); | |
45 if (std::wstring::npos == pos) { | |
46 // There is no space, the cmd_line contains only the app_name | |
47 exe_name = cmd_line; | |
48 } else { | |
49 exe_name = cmd_line.substr(0, pos); | |
50 } | |
51 } | |
52 | |
53 return exe_name; | |
54 } | |
55 | |
56 // Returns true is the path in parameter is relative. False if it's | |
57 // absolute. | |
58 bool IsPathRelative(const std::wstring &path) { | |
59 // A path is Relative if it's not a UNC path beginnning with \\ or a | |
60 // path beginning with a drive. (i.e. X:\) | |
61 if (path.find(L"\\\\") == 0 || path.find(L":\\") == 1) | |
62 return false; | |
63 return true; | |
64 } | |
65 | |
66 // Converts a relative path to an absolute path. | |
67 bool ConvertToAbsolutePath(const std::wstring child_current_directory, | |
68 bool use_env_path, std::wstring *path) { | |
69 wchar_t file_buffer[MAX_PATH]; | |
70 wchar_t *file_part = NULL; | |
71 | |
72 // Here we should start by looking at the path where the child application was | |
73 // started. We don't have this information yet. | |
74 DWORD result = 0; | |
75 if (use_env_path) { | |
76 // Try with the complete path | |
77 result = ::SearchPath(NULL, path->c_str(), NULL, MAX_PATH, file_buffer, | |
78 &file_part); | |
79 } | |
80 | |
81 if (0 == result) { | |
82 // Try with the current directory of the child | |
83 result = ::SearchPath(child_current_directory.c_str(), path->c_str(), NULL, | |
84 MAX_PATH, file_buffer, &file_part); | |
85 } | |
86 | |
87 if (0 == result || result >= MAX_PATH) | |
88 return false; | |
89 | |
90 *path = file_buffer; | |
91 return true; | |
92 } | |
93 | |
94 } // namespace | |
95 namespace sandbox { | |
96 | |
97 ThreadProcessDispatcher::ThreadProcessDispatcher(PolicyBase* policy_base) | |
98 : policy_base_(policy_base) { | |
99 static const IPCCall open_thread = { | |
100 {IPC_NTOPENTHREAD_TAG, ULONG_TYPE, ULONG_TYPE}, | |
101 reinterpret_cast<CallbackGeneric>( | |
102 &ThreadProcessDispatcher::NtOpenThread) | |
103 }; | |
104 | |
105 static const IPCCall open_process = { | |
106 {IPC_NTOPENPROCESS_TAG, ULONG_TYPE, ULONG_TYPE}, | |
107 reinterpret_cast<CallbackGeneric>( | |
108 &ThreadProcessDispatcher::NtOpenProcess) | |
109 }; | |
110 | |
111 static const IPCCall process_token = { | |
112 {IPC_NTOPENPROCESSTOKEN_TAG, VOIDPTR_TYPE, ULONG_TYPE}, | |
113 reinterpret_cast<CallbackGeneric>( | |
114 &ThreadProcessDispatcher::NtOpenProcessToken) | |
115 }; | |
116 | |
117 static const IPCCall process_tokenex = { | |
118 {IPC_NTOPENPROCESSTOKENEX_TAG, VOIDPTR_TYPE, ULONG_TYPE, ULONG_TYPE}, | |
119 reinterpret_cast<CallbackGeneric>( | |
120 &ThreadProcessDispatcher::NtOpenProcessTokenEx) | |
121 }; | |
122 | |
123 static const IPCCall create_params = { | |
124 {IPC_CREATEPROCESSW_TAG, WCHAR_TYPE, WCHAR_TYPE, WCHAR_TYPE, INOUTPTR_TYPE}, | |
125 reinterpret_cast<CallbackGeneric>( | |
126 &ThreadProcessDispatcher::CreateProcessW) | |
127 }; | |
128 | |
129 ipc_calls_.push_back(open_thread); | |
130 ipc_calls_.push_back(open_process); | |
131 ipc_calls_.push_back(process_token); | |
132 ipc_calls_.push_back(process_tokenex); | |
133 ipc_calls_.push_back(create_params); | |
134 } | |
135 | |
136 bool ThreadProcessDispatcher::SetupService(InterceptionManager* manager, | |
137 int service) { | |
138 switch (service) { | |
139 case IPC_NTOPENTHREAD_TAG: | |
140 case IPC_NTOPENPROCESS_TAG: | |
141 case IPC_NTOPENPROCESSTOKEN_TAG: | |
142 case IPC_NTOPENPROCESSTOKENEX_TAG: | |
143 // There is no explicit policy for these services. | |
144 NOTREACHED(); | |
145 return false; | |
146 | |
147 case IPC_CREATEPROCESSW_TAG: | |
148 return INTERCEPT_EAT(manager, L"kernel32.dll", CreateProcessW, | |
149 CREATE_PROCESSW_ID, 44) && | |
150 INTERCEPT_EAT(manager, L"kernel32.dll", CreateProcessA, | |
151 CREATE_PROCESSA_ID, 44); | |
152 | |
153 default: | |
154 return false; | |
155 } | |
156 } | |
157 | |
158 bool ThreadProcessDispatcher::NtOpenThread(IPCInfo* ipc, DWORD desired_access, | |
159 DWORD thread_id) { | |
160 HANDLE handle; | |
161 NTSTATUS ret = ProcessPolicy::OpenThreadAction(*ipc->client_info, | |
162 desired_access, thread_id, | |
163 &handle); | |
164 ipc->return_info.nt_status = ret; | |
165 ipc->return_info.handle = handle; | |
166 return true; | |
167 } | |
168 | |
169 bool ThreadProcessDispatcher::NtOpenProcess(IPCInfo* ipc, DWORD desired_access, | |
170 DWORD process_id) { | |
171 HANDLE handle; | |
172 NTSTATUS ret = ProcessPolicy::OpenProcessAction(*ipc->client_info, | |
173 desired_access, process_id, | |
174 &handle); | |
175 ipc->return_info.nt_status = ret; | |
176 ipc->return_info.handle = handle; | |
177 return true; | |
178 } | |
179 | |
180 bool ThreadProcessDispatcher::NtOpenProcessToken(IPCInfo* ipc, HANDLE process, | |
181 DWORD desired_access) { | |
182 HANDLE handle; | |
183 NTSTATUS ret = ProcessPolicy::OpenProcessTokenAction(*ipc->client_info, | |
184 process, desired_access, | |
185 &handle); | |
186 ipc->return_info.nt_status = ret; | |
187 ipc->return_info.handle = handle; | |
188 return true; | |
189 } | |
190 | |
191 bool ThreadProcessDispatcher::NtOpenProcessTokenEx(IPCInfo* ipc, HANDLE process, | |
192 DWORD desired_access, | |
193 DWORD attributes) { | |
194 HANDLE handle; | |
195 NTSTATUS ret = ProcessPolicy::OpenProcessTokenExAction(*ipc->client_info, | |
196 process, | |
197 desired_access, | |
198 attributes, &handle); | |
199 ipc->return_info.nt_status = ret; | |
200 ipc->return_info.handle = handle; | |
201 return true; | |
202 } | |
203 | |
204 bool ThreadProcessDispatcher::CreateProcessW(IPCInfo* ipc, std::wstring* name, | |
205 std::wstring* cmd_line, | |
206 std::wstring* cur_dir, | |
207 CountedBuffer* info) { | |
208 if (sizeof(PROCESS_INFORMATION) != info->Size()) | |
209 return false; | |
210 | |
211 // Check if there is an application name. | |
212 std::wstring exe_name; | |
213 if (!name->empty()) | |
214 exe_name = *name; | |
215 else | |
216 exe_name = GetPathFromCmdLine(*cmd_line); | |
217 | |
218 if (IsPathRelative(exe_name)) { | |
219 if (!ConvertToAbsolutePath(*cur_dir, name->empty(), &exe_name)) { | |
220 // Cannot find the path. Maybe the file does not exist. | |
221 ipc->return_info.win32_result = ERROR_FILE_NOT_FOUND; | |
222 return true; | |
223 } | |
224 } | |
225 | |
226 const wchar_t* const_exe_name = exe_name.c_str(); | |
227 CountedParameterSet<NameBased> params; | |
228 params[NameBased::NAME] = ParamPickerMake(const_exe_name); | |
229 | |
230 EvalResult eval = policy_base_->EvalPolicy(IPC_CREATEPROCESSW_TAG, | |
231 params.GetBase()); | |
232 | |
233 PROCESS_INFORMATION* proc_info = | |
234 reinterpret_cast<PROCESS_INFORMATION*>(info->Buffer()); | |
235 // Here we force the app_name to be the one we used for the policy lookup. | |
236 // If our logic was wrong, at least we wont allow create a random process. | |
237 DWORD ret = ProcessPolicy::CreateProcessWAction(eval, *ipc->client_info, | |
238 exe_name, *cmd_line, | |
239 proc_info); | |
240 | |
241 ipc->return_info.win32_result = ret; | |
242 return true; | |
243 } | |
244 | |
245 } // namespace sandbox | |
OLD | NEW |