|
1 // Copyright (c) 2006-2008 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/filesystem_interception.h" |
|
6 |
|
7 #include "sandbox/win/src/crosscall_client.h" |
|
8 #include "sandbox/win/src/ipc_tags.h" |
|
9 #include "sandbox/win/src/policy_params.h" |
|
10 #include "sandbox/win/src/policy_target.h" |
|
11 #include "sandbox/win/src/sandbox_factory.h" |
|
12 #include "sandbox/win/src/sandbox_nt_util.h" |
|
13 #include "sandbox/win/src/sharedmem_ipc_client.h" |
|
14 #include "sandbox/win/src/target_services.h" |
|
15 |
|
16 namespace sandbox { |
|
17 |
|
18 NTSTATUS WINAPI TargetNtCreateFile(NtCreateFileFunction orig_CreateFile, |
|
19 PHANDLE file, ACCESS_MASK desired_access, |
|
20 POBJECT_ATTRIBUTES object_attributes, |
|
21 PIO_STATUS_BLOCK io_status, |
|
22 PLARGE_INTEGER allocation_size, |
|
23 ULONG file_attributes, ULONG sharing, |
|
24 ULONG disposition, ULONG options, |
|
25 PVOID ea_buffer, ULONG ea_length) { |
|
26 // Check if the process can open it first. |
|
27 NTSTATUS status = orig_CreateFile(file, desired_access, object_attributes, |
|
28 io_status, allocation_size, |
|
29 file_attributes, sharing, disposition, |
|
30 options, ea_buffer, ea_length); |
|
31 if (STATUS_ACCESS_DENIED != status) |
|
32 return status; |
|
33 |
|
34 // We don't trust that the IPC can work this early. |
|
35 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
|
36 return status; |
|
37 |
|
38 do { |
|
39 if (!ValidParameter(file, sizeof(HANDLE), WRITE)) |
|
40 break; |
|
41 if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE)) |
|
42 break; |
|
43 |
|
44 void* memory = GetGlobalIPCMemory(); |
|
45 if (NULL == memory) |
|
46 break; |
|
47 |
|
48 wchar_t* name; |
|
49 uint32 attributes = 0; |
|
50 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, |
|
51 NULL); |
|
52 if (!NT_SUCCESS(ret) || NULL == name) |
|
53 break; |
|
54 |
|
55 ULONG broker = FALSE; |
|
56 CountedParameterSet<OpenFile> params; |
|
57 params[OpenFile::NAME] = ParamPickerMake(name); |
|
58 params[OpenFile::ACCESS] = ParamPickerMake(desired_access); |
|
59 params[OpenFile::OPTIONS] = ParamPickerMake(options); |
|
60 params[OpenFile::BROKER] = ParamPickerMake(broker); |
|
61 |
|
62 if (!QueryBroker(IPC_NTCREATEFILE_TAG, params.GetBase())) |
|
63 break; |
|
64 |
|
65 SharedMemIPCClient ipc(memory); |
|
66 CrossCallReturn answer = {0}; |
|
67 // The following call must match in the parameters with |
|
68 // FilesystemDispatcher::ProcessNtCreateFile. |
|
69 ResultCode code = CrossCall(ipc, IPC_NTCREATEFILE_TAG, name, attributes, |
|
70 desired_access, file_attributes, sharing, |
|
71 disposition, options, &answer); |
|
72 |
|
73 operator delete(name, NT_ALLOC); |
|
74 |
|
75 if (SBOX_ALL_OK != code) |
|
76 break; |
|
77 |
|
78 if (!NT_SUCCESS(answer.nt_status)) |
|
79 return answer.nt_status; |
|
80 |
|
81 __try { |
|
82 *file = answer.handle; |
|
83 io_status->Status = answer.nt_status; |
|
84 io_status->Information = answer.extended[0].ulong_ptr; |
|
85 status = io_status->Status; |
|
86 } __except(EXCEPTION_EXECUTE_HANDLER) { |
|
87 break; |
|
88 } |
|
89 } while (false); |
|
90 |
|
91 return status; |
|
92 } |
|
93 |
|
94 NTSTATUS WINAPI TargetNtOpenFile(NtOpenFileFunction orig_OpenFile, PHANDLE file, |
|
95 ACCESS_MASK desired_access, |
|
96 POBJECT_ATTRIBUTES object_attributes, |
|
97 PIO_STATUS_BLOCK io_status, ULONG sharing, |
|
98 ULONG options) { |
|
99 // Check if the process can open it first. |
|
100 NTSTATUS status = orig_OpenFile(file, desired_access, object_attributes, |
|
101 io_status, sharing, options); |
|
102 if (STATUS_ACCESS_DENIED != status) |
|
103 return status; |
|
104 |
|
105 // We don't trust that the IPC can work this early. |
|
106 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
|
107 return status; |
|
108 |
|
109 do { |
|
110 if (!ValidParameter(file, sizeof(HANDLE), WRITE)) |
|
111 break; |
|
112 if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE)) |
|
113 break; |
|
114 |
|
115 void* memory = GetGlobalIPCMemory(); |
|
116 if (NULL == memory) |
|
117 break; |
|
118 |
|
119 wchar_t* name; |
|
120 uint32 attributes; |
|
121 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, |
|
122 NULL); |
|
123 if (!NT_SUCCESS(ret) || NULL == name) |
|
124 break; |
|
125 |
|
126 ULONG broker = FALSE; |
|
127 CountedParameterSet<OpenFile> params; |
|
128 params[OpenFile::NAME] = ParamPickerMake(name); |
|
129 params[OpenFile::ACCESS] = ParamPickerMake(desired_access); |
|
130 params[OpenFile::OPTIONS] = ParamPickerMake(options); |
|
131 params[OpenFile::BROKER] = ParamPickerMake(broker); |
|
132 |
|
133 if (!QueryBroker(IPC_NTOPENFILE_TAG, params.GetBase())) |
|
134 break; |
|
135 |
|
136 SharedMemIPCClient ipc(memory); |
|
137 CrossCallReturn answer = {0}; |
|
138 ResultCode code = CrossCall(ipc, IPC_NTOPENFILE_TAG, name, attributes, |
|
139 desired_access, sharing, options, &answer); |
|
140 |
|
141 operator delete(name, NT_ALLOC); |
|
142 |
|
143 if (SBOX_ALL_OK != code) |
|
144 break; |
|
145 |
|
146 if (!NT_SUCCESS(answer.nt_status)) |
|
147 return answer.nt_status; |
|
148 |
|
149 __try { |
|
150 *file = answer.handle; |
|
151 io_status->Status = answer.nt_status; |
|
152 io_status->Information = answer.extended[0].ulong_ptr; |
|
153 status = io_status->Status; |
|
154 } __except(EXCEPTION_EXECUTE_HANDLER) { |
|
155 break; |
|
156 } |
|
157 } while (false); |
|
158 |
|
159 return status; |
|
160 } |
|
161 |
|
162 NTSTATUS WINAPI TargetNtQueryAttributesFile( |
|
163 NtQueryAttributesFileFunction orig_QueryAttributes, |
|
164 POBJECT_ATTRIBUTES object_attributes, |
|
165 PFILE_BASIC_INFORMATION file_attributes) { |
|
166 // Check if the process can query it first. |
|
167 NTSTATUS status = orig_QueryAttributes(object_attributes, file_attributes); |
|
168 if (STATUS_ACCESS_DENIED != status) |
|
169 return status; |
|
170 |
|
171 // We don't trust that the IPC can work this early. |
|
172 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
|
173 return status; |
|
174 |
|
175 do { |
|
176 if (!ValidParameter(file_attributes, sizeof(FILE_BASIC_INFORMATION), WRITE)) |
|
177 break; |
|
178 |
|
179 void* memory = GetGlobalIPCMemory(); |
|
180 if (NULL == memory) |
|
181 break; |
|
182 |
|
183 wchar_t* name = NULL; |
|
184 uint32 attributes = 0; |
|
185 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, |
|
186 NULL); |
|
187 if (!NT_SUCCESS(ret) || NULL == name) |
|
188 break; |
|
189 |
|
190 InOutCountedBuffer file_info(file_attributes, |
|
191 sizeof(FILE_BASIC_INFORMATION)); |
|
192 |
|
193 ULONG broker = FALSE; |
|
194 CountedParameterSet<FileName> params; |
|
195 params[FileName::NAME] = ParamPickerMake(name); |
|
196 params[FileName::BROKER] = ParamPickerMake(broker); |
|
197 |
|
198 if (!QueryBroker(IPC_NTQUERYATTRIBUTESFILE_TAG, params.GetBase())) |
|
199 break; |
|
200 |
|
201 SharedMemIPCClient ipc(memory); |
|
202 CrossCallReturn answer = {0}; |
|
203 ResultCode code = CrossCall(ipc, IPC_NTQUERYATTRIBUTESFILE_TAG, name, |
|
204 attributes, file_info, &answer); |
|
205 |
|
206 operator delete(name, NT_ALLOC); |
|
207 |
|
208 if (SBOX_ALL_OK != code) |
|
209 break; |
|
210 |
|
211 return answer.nt_status; |
|
212 |
|
213 } while (false); |
|
214 |
|
215 return status; |
|
216 } |
|
217 |
|
218 NTSTATUS WINAPI TargetNtQueryFullAttributesFile( |
|
219 NtQueryFullAttributesFileFunction orig_QueryFullAttributes, |
|
220 POBJECT_ATTRIBUTES object_attributes, |
|
221 PFILE_NETWORK_OPEN_INFORMATION file_attributes) { |
|
222 // Check if the process can query it first. |
|
223 NTSTATUS status = orig_QueryFullAttributes(object_attributes, |
|
224 file_attributes); |
|
225 if (STATUS_ACCESS_DENIED != status) |
|
226 return status; |
|
227 |
|
228 // We don't trust that the IPC can work this early. |
|
229 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
|
230 return status; |
|
231 |
|
232 do { |
|
233 if (!ValidParameter(file_attributes, sizeof(FILE_NETWORK_OPEN_INFORMATION), |
|
234 WRITE)) |
|
235 break; |
|
236 |
|
237 void* memory = GetGlobalIPCMemory(); |
|
238 if (NULL == memory) |
|
239 break; |
|
240 |
|
241 wchar_t* name = NULL; |
|
242 uint32 attributes = 0; |
|
243 NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes, |
|
244 NULL); |
|
245 if (!NT_SUCCESS(ret) || NULL == name) |
|
246 break; |
|
247 |
|
248 InOutCountedBuffer file_info(file_attributes, |
|
249 sizeof(FILE_NETWORK_OPEN_INFORMATION)); |
|
250 |
|
251 ULONG broker = FALSE; |
|
252 CountedParameterSet<FileName> params; |
|
253 params[FileName::NAME] = ParamPickerMake(name); |
|
254 params[FileName::BROKER] = ParamPickerMake(broker); |
|
255 |
|
256 if (!QueryBroker(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase())) |
|
257 break; |
|
258 |
|
259 SharedMemIPCClient ipc(memory); |
|
260 CrossCallReturn answer = {0}; |
|
261 ResultCode code = CrossCall(ipc, IPC_NTQUERYFULLATTRIBUTESFILE_TAG, name, |
|
262 attributes, file_info, &answer); |
|
263 |
|
264 operator delete(name, NT_ALLOC); |
|
265 |
|
266 if (SBOX_ALL_OK != code) |
|
267 break; |
|
268 |
|
269 return answer.nt_status; |
|
270 } while (false); |
|
271 |
|
272 return status; |
|
273 } |
|
274 |
|
275 NTSTATUS WINAPI TargetNtSetInformationFile( |
|
276 NtSetInformationFileFunction orig_SetInformationFile, HANDLE file, |
|
277 PIO_STATUS_BLOCK io_status, PVOID file_info, ULONG length, |
|
278 FILE_INFORMATION_CLASS file_info_class) { |
|
279 // Check if the process can open it first. |
|
280 NTSTATUS status = orig_SetInformationFile(file, io_status, file_info, length, |
|
281 file_info_class); |
|
282 if (STATUS_ACCESS_DENIED != status) |
|
283 return status; |
|
284 |
|
285 // We don't trust that the IPC can work this early. |
|
286 if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled()) |
|
287 return status; |
|
288 |
|
289 do { |
|
290 void* memory = GetGlobalIPCMemory(); |
|
291 if (NULL == memory) |
|
292 break; |
|
293 |
|
294 if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE)) |
|
295 break; |
|
296 |
|
297 if (!ValidParameter(file_info, length, READ)) |
|
298 break; |
|
299 |
|
300 FILE_RENAME_INFORMATION* file_rename_info = |
|
301 reinterpret_cast<FILE_RENAME_INFORMATION*>(file_info); |
|
302 OBJECT_ATTRIBUTES object_attributes; |
|
303 UNICODE_STRING object_name; |
|
304 InitializeObjectAttributes(&object_attributes, &object_name, 0, NULL, NULL); |
|
305 |
|
306 __try { |
|
307 if (!IsSupportedRenameCall(file_rename_info, length, file_info_class)) |
|
308 break; |
|
309 |
|
310 object_attributes.RootDirectory = file_rename_info->RootDirectory; |
|
311 object_name.Buffer = file_rename_info->FileName; |
|
312 object_name.Length = object_name.MaximumLength = |
|
313 static_cast<USHORT>(file_rename_info->FileNameLength); |
|
314 } __except(EXCEPTION_EXECUTE_HANDLER) { |
|
315 break; |
|
316 } |
|
317 |
|
318 wchar_t* name; |
|
319 NTSTATUS ret = AllocAndCopyName(&object_attributes, &name, NULL, NULL); |
|
320 if (!NT_SUCCESS(ret) || !name) |
|
321 break; |
|
322 |
|
323 ULONG broker = FALSE; |
|
324 CountedParameterSet<FileName> params; |
|
325 params[FileName::NAME] = ParamPickerMake(name); |
|
326 params[FileName::BROKER] = ParamPickerMake(broker); |
|
327 |
|
328 if (!QueryBroker(IPC_NTSETINFO_RENAME_TAG, params.GetBase())) |
|
329 break; |
|
330 |
|
331 InOutCountedBuffer io_status_buffer(io_status, sizeof(IO_STATUS_BLOCK)); |
|
332 // This is actually not an InOut buffer, only In, but using InOut facility |
|
333 // really helps to simplify the code. |
|
334 InOutCountedBuffer file_info_buffer(file_info, length); |
|
335 |
|
336 SharedMemIPCClient ipc(memory); |
|
337 CrossCallReturn answer = {0}; |
|
338 ResultCode code = CrossCall(ipc, IPC_NTSETINFO_RENAME_TAG, file, |
|
339 io_status_buffer, file_info_buffer, length, |
|
340 file_info_class, &answer); |
|
341 |
|
342 if (SBOX_ALL_OK != code) |
|
343 break; |
|
344 |
|
345 status = answer.nt_status; |
|
346 } while (false); |
|
347 |
|
348 return status; |
|
349 } |
|
350 |
|
351 } // namespace sandbox |