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
16namespace sandbox {
17
18NTSTATUS 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  wchar_t* name = NULL;
39  do {
40    if (!ValidParameter(file, sizeof(HANDLE), WRITE))
41      break;
42    if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
43      break;
44
45    void* memory = GetGlobalIPCMemory();
46    if (NULL == memory)
47      break;
48
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    if (SBOX_ALL_OK != code)
73      break;
74
75    if (!NT_SUCCESS(answer.nt_status))
76        return answer.nt_status;
77
78    __try {
79      *file = answer.handle;
80      io_status->Status = answer.nt_status;
81      io_status->Information = answer.extended[0].ulong_ptr;
82      status = io_status->Status;
83    } __except(EXCEPTION_EXECUTE_HANDLER) {
84      break;
85    }
86  } while (false);
87
88  if (name)
89    operator delete(name, NT_ALLOC);
90
91  return status;
92}
93
94NTSTATUS 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  wchar_t* name = NULL;
110  do {
111    if (!ValidParameter(file, sizeof(HANDLE), WRITE))
112      break;
113    if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
114      break;
115
116    void* memory = GetGlobalIPCMemory();
117    if (NULL == memory)
118      break;
119
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    if (SBOX_ALL_OK != code)
141      break;
142
143    if (!NT_SUCCESS(answer.nt_status))
144      return answer.nt_status;
145
146    __try {
147      *file = answer.handle;
148      io_status->Status = answer.nt_status;
149      io_status->Information = answer.extended[0].ulong_ptr;
150      status = io_status->Status;
151    } __except(EXCEPTION_EXECUTE_HANDLER) {
152      break;
153    }
154  } while (false);
155
156  if (name)
157    operator delete(name, NT_ALLOC);
158
159  return status;
160}
161
162NTSTATUS 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  wchar_t* name = NULL;
176  do {
177    if (!ValidParameter(file_attributes, sizeof(FILE_BASIC_INFORMATION), WRITE))
178      break;
179
180    void* memory = GetGlobalIPCMemory();
181    if (NULL == memory)
182      break;
183
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  if (name)
216    operator delete(name, NT_ALLOC);
217
218  return status;
219}
220
221NTSTATUS WINAPI TargetNtQueryFullAttributesFile(
222    NtQueryFullAttributesFileFunction orig_QueryFullAttributes,
223    POBJECT_ATTRIBUTES object_attributes,
224    PFILE_NETWORK_OPEN_INFORMATION file_attributes) {
225  // Check if the process can query it first.
226  NTSTATUS status = orig_QueryFullAttributes(object_attributes,
227                                             file_attributes);
228  if (STATUS_ACCESS_DENIED != status)
229    return status;
230
231  // We don't trust that the IPC can work this early.
232  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
233    return status;
234
235  wchar_t* name = NULL;
236  do {
237    if (!ValidParameter(file_attributes, sizeof(FILE_NETWORK_OPEN_INFORMATION),
238                        WRITE))
239      break;
240
241    void* memory = GetGlobalIPCMemory();
242    if (NULL == memory)
243      break;
244
245    uint32 attributes = 0;
246    NTSTATUS ret = AllocAndCopyName(object_attributes, &name, &attributes,
247                                    NULL);
248    if (!NT_SUCCESS(ret) || NULL == name)
249      break;
250
251    InOutCountedBuffer file_info(file_attributes,
252                                 sizeof(FILE_NETWORK_OPEN_INFORMATION));
253
254    ULONG broker = FALSE;
255    CountedParameterSet<FileName> params;
256    params[FileName::NAME] = ParamPickerMake(name);
257    params[FileName::BROKER] = ParamPickerMake(broker);
258
259    if (!QueryBroker(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase()))
260      break;
261
262    SharedMemIPCClient ipc(memory);
263    CrossCallReturn answer = {0};
264    ResultCode code = CrossCall(ipc, IPC_NTQUERYFULLATTRIBUTESFILE_TAG, name,
265                                attributes, file_info, &answer);
266
267    operator delete(name, NT_ALLOC);
268
269    if (SBOX_ALL_OK != code)
270      break;
271
272    return answer.nt_status;
273  } while (false);
274
275  if (name)
276    operator delete(name, NT_ALLOC);
277
278  return status;
279}
280
281NTSTATUS WINAPI TargetNtSetInformationFile(
282    NtSetInformationFileFunction orig_SetInformationFile, HANDLE file,
283    PIO_STATUS_BLOCK io_status, PVOID file_info, ULONG length,
284    FILE_INFORMATION_CLASS file_info_class) {
285  // Check if the process can open it first.
286  NTSTATUS status = orig_SetInformationFile(file, io_status, file_info, length,
287                                            file_info_class);
288  if (STATUS_ACCESS_DENIED != status)
289    return status;
290
291  // We don't trust that the IPC can work this early.
292  if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
293    return status;
294
295  wchar_t* name = NULL;
296  do {
297    void* memory = GetGlobalIPCMemory();
298    if (NULL == memory)
299      break;
300
301    if (!ValidParameter(io_status, sizeof(IO_STATUS_BLOCK), WRITE))
302      break;
303
304    if (!ValidParameter(file_info, length, READ))
305      break;
306
307    FILE_RENAME_INFORMATION* file_rename_info =
308        reinterpret_cast<FILE_RENAME_INFORMATION*>(file_info);
309    OBJECT_ATTRIBUTES object_attributes;
310    UNICODE_STRING object_name;
311    InitializeObjectAttributes(&object_attributes, &object_name, 0, NULL, NULL);
312
313    __try {
314      if (!IsSupportedRenameCall(file_rename_info, length, file_info_class))
315        break;
316
317      object_attributes.RootDirectory = file_rename_info->RootDirectory;
318      object_name.Buffer = file_rename_info->FileName;
319      object_name.Length = object_name.MaximumLength =
320          static_cast<USHORT>(file_rename_info->FileNameLength);
321    } __except(EXCEPTION_EXECUTE_HANDLER) {
322      break;
323    }
324
325    NTSTATUS ret = AllocAndCopyName(&object_attributes, &name, NULL, NULL);
326    if (!NT_SUCCESS(ret) || !name)
327      break;
328
329    ULONG broker = FALSE;
330    CountedParameterSet<FileName> params;
331    params[FileName::NAME] = ParamPickerMake(name);
332    params[FileName::BROKER] = ParamPickerMake(broker);
333
334    if (!QueryBroker(IPC_NTSETINFO_RENAME_TAG, params.GetBase()))
335      break;
336
337    InOutCountedBuffer io_status_buffer(io_status, sizeof(IO_STATUS_BLOCK));
338    // This is actually not an InOut buffer, only In, but using InOut facility
339    // really helps to simplify the code.
340    InOutCountedBuffer file_info_buffer(file_info, length);
341
342    SharedMemIPCClient ipc(memory);
343    CrossCallReturn answer = {0};
344    ResultCode code = CrossCall(ipc, IPC_NTSETINFO_RENAME_TAG, file,
345                                io_status_buffer, file_info_buffer, length,
346                                file_info_class, &answer);
347
348    if (SBOX_ALL_OK != code)
349      break;
350
351    status = answer.nt_status;
352  } while (false);
353
354  if (name)
355    operator delete(name, NT_ALLOC);
356
357  return status;
358}
359
360}  // namespace sandbox
361