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       result &= INTERCEPT_NT(manager, NtOpenKeyEx, OPEN_KEY_EX_ID, 20);
     68     return result;
     69   }
     70 
     71   return false;
     72 }
     73 
     74 bool RegistryDispatcher::NtCreateKey(
     75     IPCInfo* ipc, base::string16* name, DWORD attributes, HANDLE root,
     76     DWORD desired_access, DWORD title_index, DWORD create_options) {
     77   base::win::ScopedHandle root_handle;
     78   base::string16 real_path = *name;
     79 
     80   // If there is a root directory, we need to duplicate the handle to make
     81   // it valid in this process.
     82   if (root) {
     83     if (!::DuplicateHandle(ipc->client_info->process, root,
     84                            ::GetCurrentProcess(), &root, 0, FALSE,
     85                            DUPLICATE_SAME_ACCESS))
     86       return false;
     87 
     88     root_handle.Set(root);
     89   }
     90 
     91   if (!GetCompletePath(root, *name, &real_path))
     92     return false;
     93 
     94   const wchar_t* regname = real_path.c_str();
     95   CountedParameterSet<OpenKey> params;
     96   params[OpenKey::NAME] = ParamPickerMake(regname);
     97   params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
     98 
     99   EvalResult result = policy_base_->EvalPolicy(IPC_NTCREATEKEY_TAG,
    100                                                params.GetBase());
    101 
    102   HANDLE handle;
    103   NTSTATUS nt_status;
    104   ULONG disposition = 0;
    105   if (!RegistryPolicy::CreateKeyAction(result, *ipc->client_info, *name,
    106                                        attributes, root, desired_access,
    107                                        title_index, create_options, &handle,
    108                                        &nt_status, &disposition)) {
    109     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    110     return true;
    111   }
    112 
    113   // Return operation status on the IPC.
    114   ipc->return_info.extended[0].unsigned_int = disposition;
    115   ipc->return_info.nt_status = nt_status;
    116   ipc->return_info.handle = handle;
    117   return true;
    118 }
    119 
    120 bool RegistryDispatcher::NtOpenKey(IPCInfo* ipc, base::string16* name,
    121                                    DWORD attributes, HANDLE root,
    122                                    DWORD desired_access) {
    123   base::win::ScopedHandle root_handle;
    124   base::string16 real_path = *name;
    125 
    126   // If there is a root directory, we need to duplicate the handle to make
    127   // it valid in this process.
    128   if (root) {
    129     if (!::DuplicateHandle(ipc->client_info->process, root,
    130                            ::GetCurrentProcess(), &root, 0, FALSE,
    131                            DUPLICATE_SAME_ACCESS))
    132       return false;
    133       root_handle.Set(root);
    134   }
    135 
    136   if (!GetCompletePath(root, *name, &real_path))
    137     return false;
    138 
    139   const wchar_t* regname = real_path.c_str();
    140   CountedParameterSet<OpenKey> params;
    141   params[OpenKey::NAME] = ParamPickerMake(regname);
    142   params[OpenKey::ACCESS] = ParamPickerMake(desired_access);
    143 
    144   EvalResult result = policy_base_->EvalPolicy(IPC_NTOPENKEY_TAG,
    145                                                params.GetBase());
    146   HANDLE handle;
    147   NTSTATUS nt_status;
    148   if (!RegistryPolicy::OpenKeyAction(result, *ipc->client_info, *name,
    149                                      attributes, root, desired_access, &handle,
    150                                      &nt_status)) {
    151     ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
    152     return true;
    153   }
    154 
    155   // Return operation status on the IPC.
    156   ipc->return_info.nt_status = nt_status;
    157   ipc->return_info.handle = handle;
    158   return true;
    159 }
    160 
    161 }  // namespace sandbox
    162