Home | History | Annotate | Download | only in src
      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/win/src/filesystem_dispatcher.h"
      6 
      7 #include "sandbox/win/src/crosscall_client.h"
      8 #include "sandbox/win/src/filesystem_interception.h"
      9 #include "sandbox/win/src/filesystem_policy.h"
     10 #include "sandbox/win/src/interception.h"
     11 #include "sandbox/win/src/interceptors.h"
     12 #include "sandbox/win/src/ipc_tags.h"
     13 #include "sandbox/win/src/policy_broker.h"
     14 #include "sandbox/win/src/policy_params.h"
     15 #include "sandbox/win/src/sandbox.h"
     16 #include "sandbox/win/src/sandbox_nt_util.h"
     17 
     18 namespace sandbox {
     19 
     20 FilesystemDispatcher::FilesystemDispatcher(PolicyBase* policy_base)
     21     : policy_base_(policy_base) {
     22   static const IPCCall create_params = {
     23     {IPC_NTCREATEFILE_TAG, WCHAR_TYPE, ULONG_TYPE, ULONG_TYPE, ULONG_TYPE,
     24      ULONG_TYPE, ULONG_TYPE, ULONG_TYPE},
     25     reinterpret_cast<CallbackGeneric>(&FilesystemDispatcher::NtCreateFile)
     26   };
     27 
     28   static const IPCCall open_file = {
     29     {IPC_NTOPENFILE_TAG, WCHAR_TYPE, ULONG_TYPE, ULONG_TYPE, ULONG_TYPE,
     30      ULONG_TYPE},
     31     reinterpret_cast<CallbackGeneric>(&FilesystemDispatcher::NtOpenFile)
     32   };
     33 
     34   static const IPCCall attribs = {
     35     {IPC_NTQUERYATTRIBUTESFILE_TAG, WCHAR_TYPE, ULONG_TYPE, INOUTPTR_TYPE},
     36     reinterpret_cast<CallbackGeneric>(
     37         &FilesystemDispatcher::NtQueryAttributesFile)
     38   };
     39 
     40   static const IPCCall full_attribs = {
     41     {IPC_NTQUERYFULLATTRIBUTESFILE_TAG, WCHAR_TYPE, ULONG_TYPE, INOUTPTR_TYPE},
     42     reinterpret_cast<CallbackGeneric>(
     43           &FilesystemDispatcher::NtQueryFullAttributesFile)
     44   };
     45 
     46   static const IPCCall set_info = {
     47     {IPC_NTSETINFO_RENAME_TAG, VOIDPTR_TYPE, INOUTPTR_TYPE, INOUTPTR_TYPE,
     48      ULONG_TYPE, ULONG_TYPE},
     49     reinterpret_cast<CallbackGeneric>(
     50         &FilesystemDispatcher::NtSetInformationFile)
     51   };
     52 
     53   ipc_calls_.push_back(create_params);
     54   ipc_calls_.push_back(open_file);
     55   ipc_calls_.push_back(attribs);
     56   ipc_calls_.push_back(full_attribs);
     57   ipc_calls_.push_back(set_info);
     58 }
     59 
     60 bool FilesystemDispatcher::SetupService(InterceptionManager* manager,
     61                                         int service) {
     62   switch (service) {
     63     case IPC_NTCREATEFILE_TAG:
     64       return INTERCEPT_NT(manager, NtCreateFile, CREATE_FILE_ID, 48);
     65 
     66     case IPC_NTOPENFILE_TAG:
     67       return INTERCEPT_NT(manager, NtOpenFile, OPEN_FILE_ID, 28);
     68 
     69     case IPC_NTQUERYATTRIBUTESFILE_TAG:
     70       return INTERCEPT_NT(manager, NtQueryAttributesFile, QUERY_ATTRIB_FILE_ID,
     71                           12);
     72 
     73     case IPC_NTQUERYFULLATTRIBUTESFILE_TAG:
     74         return INTERCEPT_NT(manager, NtQueryFullAttributesFile,
     75                             QUERY_FULL_ATTRIB_FILE_ID, 12);
     76 
     77     case IPC_NTSETINFO_RENAME_TAG:
     78       return INTERCEPT_NT(manager, NtSetInformationFile, SET_INFO_FILE_ID, 24);
     79 
     80     default:
     81       return false;
     82   }
     83 }
     84 
     85 bool FilesystemDispatcher::NtCreateFile(
     86     IPCInfo* ipc, std::wstring* name, DWORD attributes, DWORD desired_access,
     87     DWORD file_attributes, DWORD share_access, DWORD create_disposition,
     88     DWORD create_options) {
     89   if (!PreProcessName(*name, name)) {
     90     // The path requested might contain a reparse point.
     91     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
     92     return true;
     93   }
     94 
     95   const wchar_t* filename = name->c_str();
     96 
     97   ULONG broker = TRUE;
     98   CountedParameterSet<OpenFile> params;
     99   params[OpenFile::NAME] = ParamPickerMake(filename);
    100   params[OpenFile::ACCESS] = ParamPickerMake(desired_access);
    101   params[OpenFile::OPTIONS] = ParamPickerMake(create_options);
    102   params[OpenFile::BROKER] = ParamPickerMake(broker);
    103 
    104   // To evaluate the policy we need to call back to the policy object. We
    105   // are just middlemen in the operation since is the FileSystemPolicy which
    106   // knows what to do.
    107   EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEFILE_TAG,
    108                                                params.GetBase());
    109   HANDLE handle;
    110   ULONG_PTR io_information = 0;
    111   NTSTATUS nt_status;
    112   if (!FileSystemPolicy::CreateFileAction(result, *ipc->client_info, *name,
    113                                           attributes, desired_access,
    114                                           file_attributes, share_access,
    115                                           create_disposition, create_options,
    116                                           &handle, &nt_status,
    117                                           &io_information)) {
    118     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    119     return true;
    120   }
    121   // Return operation status on the IPC.
    122   ipc->return_info.extended[0].ulong_ptr = io_information;
    123   ipc->return_info.nt_status = nt_status;
    124   ipc->return_info.handle = handle;
    125   return true;
    126 }
    127 
    128 bool FilesystemDispatcher::NtOpenFile(
    129     IPCInfo* ipc, std::wstring* name, DWORD attributes, DWORD desired_access,
    130     DWORD share_access, DWORD open_options) {
    131   if (!PreProcessName(*name, name)) {
    132     // The path requested might contain a reparse point.
    133     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    134     return true;
    135   }
    136 
    137   const wchar_t* filename = name->c_str();
    138 
    139   ULONG broker = TRUE;
    140   CountedParameterSet<OpenFile> params;
    141   params[OpenFile::NAME] = ParamPickerMake(filename);
    142   params[OpenFile::ACCESS] = ParamPickerMake(desired_access);
    143   params[OpenFile::OPTIONS] = ParamPickerMake(open_options);
    144   params[OpenFile::BROKER] = ParamPickerMake(broker);
    145 
    146   // To evaluate the policy we need to call back to the policy object. We
    147   // are just middlemen in the operation since is the FileSystemPolicy which
    148   // knows what to do.
    149   EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENFILE_TAG,
    150                                                params.GetBase());
    151   HANDLE handle;
    152   ULONG_PTR io_information = 0;
    153   NTSTATUS nt_status;
    154   if (!FileSystemPolicy::OpenFileAction(result, *ipc->client_info, *name,
    155                                         attributes, desired_access,
    156                                         share_access, open_options, &handle,
    157                                         &nt_status, &io_information)) {
    158     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    159     return true;
    160   }
    161   // Return operation status on the IPC.
    162   ipc->return_info.extended[0].ulong_ptr = io_information;
    163   ipc->return_info.nt_status = nt_status;
    164   ipc->return_info.handle = handle;
    165   return true;
    166 }
    167 
    168 bool FilesystemDispatcher::NtQueryAttributesFile(
    169     IPCInfo* ipc, std::wstring* name, DWORD attributes, CountedBuffer* info) {
    170   if (sizeof(FILE_BASIC_INFORMATION) != info->Size())
    171     return false;
    172 
    173   if (!PreProcessName(*name, name)) {
    174     // The path requested might contain a reparse point.
    175     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    176     return true;
    177   }
    178 
    179   ULONG broker = TRUE;
    180   const wchar_t* filename = name->c_str();
    181   CountedParameterSet<FileName> params;
    182   params[FileName::NAME] = ParamPickerMake(filename);
    183   params[FileName::BROKER] = ParamPickerMake(broker);
    184 
    185   // To evaluate the policy we need to call back to the policy object. We
    186   // are just middlemen in the operation since is the FileSystemPolicy which
    187   // knows what to do.
    188   EvalResult result = policy_base_->EvalPolicy(IPC_NTQUERYATTRIBUTESFILE_TAG,
    189                                                params.GetBase());
    190 
    191   FILE_BASIC_INFORMATION* information =
    192         reinterpret_cast<FILE_BASIC_INFORMATION*>(info->Buffer());
    193   NTSTATUS nt_status;
    194   if (!FileSystemPolicy::QueryAttributesFileAction(result, *ipc->client_info,
    195                                                    *name, attributes,
    196                                                    information, &nt_status)) {
    197     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    198     return true;
    199   }
    200 
    201   // Return operation status on the IPC.
    202   ipc->return_info.nt_status = nt_status;
    203   return true;
    204 }
    205 
    206 bool FilesystemDispatcher::NtQueryFullAttributesFile(
    207     IPCInfo* ipc, std::wstring* name, DWORD attributes, CountedBuffer* info) {
    208   if (sizeof(FILE_NETWORK_OPEN_INFORMATION) != info->Size())
    209     return false;
    210 
    211   if (!PreProcessName(*name, name)) {
    212     // The path requested might contain a reparse point.
    213     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    214     return true;
    215   }
    216 
    217   ULONG broker = TRUE;
    218   const wchar_t* filename = name->c_str();
    219   CountedParameterSet<FileName> params;
    220   params[FileName::NAME] = ParamPickerMake(filename);
    221   params[FileName::BROKER] = ParamPickerMake(broker);
    222 
    223   // To evaluate the policy we need to call back to the policy object. We
    224   // are just middlemen in the operation since is the FileSystemPolicy which
    225   // knows what to do.
    226   EvalResult result = policy_base_->EvalPolicy(
    227                           IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase());
    228 
    229   FILE_NETWORK_OPEN_INFORMATION* information =
    230         reinterpret_cast<FILE_NETWORK_OPEN_INFORMATION*>(info->Buffer());
    231   NTSTATUS nt_status;
    232   if (!FileSystemPolicy::QueryFullAttributesFileAction(result,
    233                                                        *ipc->client_info,
    234                                                        *name, attributes,
    235                                                        information,
    236                                                        &nt_status)) {
    237     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    238     return true;
    239   }
    240 
    241   // Return operation status on the IPC.
    242   ipc->return_info.nt_status = nt_status;
    243   return true;
    244 }
    245 
    246 bool FilesystemDispatcher::NtSetInformationFile(
    247     IPCInfo* ipc, HANDLE handle, CountedBuffer* status, CountedBuffer* info,
    248     DWORD length, DWORD info_class) {
    249   if (sizeof(IO_STATUS_BLOCK) != status->Size())
    250     return false;
    251   if (length != info->Size())
    252     return false;
    253 
    254   FILE_RENAME_INFORMATION* rename_info =
    255       reinterpret_cast<FILE_RENAME_INFORMATION*>(info->Buffer());
    256 
    257   if (!IsSupportedRenameCall(rename_info, length, info_class))
    258     return false;
    259 
    260   std::wstring name;
    261   name.assign(rename_info->FileName, rename_info->FileNameLength /
    262                                      sizeof(rename_info->FileName[0]));
    263   if (!PreProcessName(name, &name)) {
    264     // The path requested might contain a reparse point.
    265     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    266     return true;
    267   }
    268 
    269   ULONG broker = TRUE;
    270   const wchar_t* filename = name.c_str();
    271   CountedParameterSet<FileName> params;
    272   params[FileName::NAME] = ParamPickerMake(filename);
    273   params[FileName::BROKER] = ParamPickerMake(broker);
    274 
    275   // To evaluate the policy we need to call back to the policy object. We
    276   // are just middlemen in the operation since is the FileSystemPolicy which
    277   // knows what to do.
    278   EvalResult result = policy_base_->EvalPolicy(IPC_NTSETINFO_RENAME_TAG,
    279                                                params.GetBase());
    280 
    281   IO_STATUS_BLOCK* io_status =
    282         reinterpret_cast<IO_STATUS_BLOCK*>(status->Buffer());
    283   NTSTATUS nt_status;
    284   if (!FileSystemPolicy::SetInformationFileAction(result, *ipc->client_info,
    285                                                   handle, rename_info, length,
    286                                                   info_class, io_status,
    287                                                   &nt_status)) {
    288     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    289     return true;
    290   }
    291 
    292   // Return operation status on the IPC.
    293   ipc->return_info.nt_status = nt_status;
    294   return true;
    295 }
    296 
    297 }  // namespace sandbox
    298