Home | History | Annotate | Download | only in src
      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/registry_dispatcher.h"
      6 
      7 #include "base/win/scoped_handle.h"
      8 #include "base/win/windows_version.h"
      9 #include "sandbox/win/src/crosscall_client.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/sandbox_nt_util.h"
     14 #include "sandbox/win/src/policy_broker.h"
     15 #include "sandbox/win/src/policy_params.h"
     16 #include "sandbox/win/src/sandbox.h"
     17 #include "sandbox/win/src/registry_interception.h"
     18 #include "sandbox/win/src/registry_policy.h"
     19 
     20 namespace {
     21 
     22 // Builds a path using the root directory and the name.
     23 bool GetCompletePath(HANDLE root, const base::string16& name,
     24                      base::string16* complete_name) {
     25   if (root) {
     26     if (!sandbox::GetPathFromHandle(root, complete_name))
     27       return false;
     28 
     29     *complete_name += L"\\";
     30     *complete_name += name;
     31   } else {
     32     *complete_name = name;
     33   }
     34 
     35   return true;
     36 }
     37 
     38 }
     39 
     40 namespace sandbox {
     41 
     42 RegistryDispatcher::RegistryDispatcher(PolicyBase* policy_base)
     43     : policy_base_(policy_base) {
     44   static const IPCCall create_params = {
     45     {IPC_NTCREATEKEY_TAG, WCHAR_TYPE, ULONG_TYPE, VOIDPTR_TYPE, ULONG_TYPE,
     46      ULONG_TYPE, ULONG_TYPE},
     47     reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtCreateKey)
     48   };
     49 
     50   static const IPCCall open_params = {
     51     {IPC_NTOPENKEY_TAG, WCHAR_TYPE, ULONG_TYPE, VOIDPTR_TYPE, ULONG_TYPE},
     52     reinterpret_cast<CallbackGeneric>(&RegistryDispatcher::NtOpenKey)
     53   };
     54 
     55   ipc_calls_.push_back(create_params);
     56   ipc_calls_.push_back(open_params);
     57 }
     58 
     59 bool RegistryDispatcher::SetupService(InterceptionManager* manager,
     60                                       int service) {
     61   if (IPC_NTCREATEKEY_TAG == service)
     62     return INTERCEPT_NT(manager, NtCreateKey, CREATE_KEY_ID, 32);
     63 
     64   if (IPC_NTOPENKEY_TAG == service) {
     65     bool result = INTERCEPT_NT(manager, NtOpenKey, OPEN_KEY_ID, 16);
     66     if (base::win::GetVersion() >= base::win::VERSION_WIN7 ||
     67         (base::win::GetVersion() == base::win::VERSION_VISTA &&
     68          base::win::OSInfo::GetInstance()->version_type() ==
     69              base::win::SUITE_SERVER))
     70       result &= INTERCEPT_NT(manager, NtOpenKeyEx, OPEN_KEY_EX_ID, 20);
     71     return result;
     72   }
     73 
     74   return false;
     75 }
     76 
     77 bool RegistryDispatcher::NtCreateKey(
     78     IPCInfo* ipc, base::string16* name, DWORD attributes, HANDLE root,
     79     DWORD desired_access, DWORD title_index, DWORD create_options) {
     80   base::win::ScopedHandle root_handle;
     81   base::string16 real_path = *name;
     82 
     83   // If there is a root directory, we need to duplicate the handle to make
     84   // it valid in this process.
     85   if (root) {
     86     if (!::DuplicateHandle(ipc->client_info->process, root,
     87                            ::GetCurrentProcess(), &root, 0, FALSE,
     88                            DUPLICATE_SAME_ACCESS))
     89       return false;
     90 
     91     root_handle.Set(root);
     92   }
     93 
     94   if (!GetCompletePath(root, *name, &real_path))
     95     return false;
     96 
     97   const wchar_t* regname = real_path.c_str();
     98   CountedParameterSet<OpenKey> params;
     99   params[OpenKey::NAME] = ParamPickerMake(regname);
    100   params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
    101 
    102   EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEKEY_TAG,
    103                                                params.GetBase());
    104 
    105   HANDLE handle;
    106   NTSTATUS nt_status;
    107   ULONG disposition = 0;
    108   if (!RegistryPolicy::CreateKeyAction(result, *ipc->client_info, *name,
    109                                        attributes, root, desired_access,
    110                                        title_index, create_options, &handle,
    111                                        &nt_status, &disposition)) {
    112     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    113     return true;
    114   }
    115 
    116   // Return operation status on the IPC.
    117   ipc->return_info.extended[0].unsigned_int = disposition;
    118   ipc->return_info.nt_status = nt_status;
    119   ipc->return_info.handle = handle;
    120   return true;
    121 }
    122 
    123 bool RegistryDispatcher::NtOpenKey(IPCInfo* ipc, base::string16* name,
    124                                    DWORD attributes, HANDLE root,
    125                                    DWORD desired_access) {
    126   base::win::ScopedHandle root_handle;
    127   base::string16 real_path = *name;
    128 
    129   // If there is a root directory, we need to duplicate the handle to make
    130   // it valid in this process.
    131   if (root) {
    132     if (!::DuplicateHandle(ipc->client_info->process, root,
    133                            ::GetCurrentProcess(), &root, 0, FALSE,
    134                            DUPLICATE_SAME_ACCESS))
    135       return false;
    136       root_handle.Set(root);
    137   }
    138 
    139   if (!GetCompletePath(root, *name, &real_path))
    140     return false;
    141 
    142   const wchar_t* regname = real_path.c_str();
    143   CountedParameterSet<OpenKey> params;
    144   params[OpenKey::NAME] = ParamPickerMake(regname);
    145   params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
    146 
    147   EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENKEY_TAG,
    148                                                params.GetBase());
    149   HANDLE handle;
    150   NTSTATUS nt_status;
    151   if (!RegistryPolicy::OpenKeyAction(result, *ipc->client_info, *name,
    152                                      attributes, root, desired_access, &handle,
    153                                      &nt_status)) {
    154     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    155     return true;
    156   }
    157 
    158   // Return operation status on the IPC.
    159   ipc->return_info.nt_status = nt_status;
    160   ipc->return_info.handle = handle;
    161   return true;
    162 }
    163 
    164 }  // namespace sandbox
    165