Home | History | Annotate | Download | only in src
      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 <string>
      6 
      7 #include "sandbox/win/src/registry_policy.h"
      8 
      9 #include "base/logging.h"
     10 #include "sandbox/win/src/ipc_tags.h"
     11 #include "sandbox/win/src/policy_engine_opcodes.h"
     12 #include "sandbox/win/src/policy_params.h"
     13 #include "sandbox/win/src/sandbox_utils.h"
     14 #include "sandbox/win/src/sandbox_types.h"
     15 #include "sandbox/win/src/win_utils.h"
     16 
     17 namespace {
     18 
     19 static const DWORD kAllowedRegFlags = KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS |
     20                                       KEY_NOTIFY | KEY_READ | GENERIC_READ |
     21                                       GENERIC_EXECUTE | READ_CONTROL;
     22 
     23 // Opens the key referenced by |obj_attributes| with |access| and
     24 // checks what permission was given. Remove the WRITE flags and update
     25 // |access| with the new value.
     26 NTSTATUS TranslateMaximumAllowed(OBJECT_ATTRIBUTES* obj_attributes,
     27                                  DWORD* access) {
     28   NtOpenKeyFunction NtOpenKey = NULL;
     29   ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
     30 
     31   NtCloseFunction NtClose = NULL;
     32   ResolveNTFunctionPtr("NtClose", &NtClose);
     33 
     34   NtQueryObjectFunction NtQueryObject = NULL;
     35   ResolveNTFunctionPtr("NtQueryObject", &NtQueryObject);
     36 
     37   // Open the key.
     38   HANDLE handle;
     39   NTSTATUS status = NtOpenKey(&handle, *access, obj_attributes);
     40   if (!NT_SUCCESS(status))
     41     return status;
     42 
     43   OBJECT_BASIC_INFORMATION info = {0};
     44   status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info),
     45                          NULL);
     46   NtClose(handle);
     47   if (!NT_SUCCESS(status))
     48     return status;
     49 
     50   *access = info.GrantedAccess & kAllowedRegFlags;
     51   return STATUS_SUCCESS;
     52 }
     53 
     54 NTSTATUS NtCreateKeyInTarget(HANDLE* target_key_handle,
     55                              ACCESS_MASK desired_access,
     56                              OBJECT_ATTRIBUTES* obj_attributes,
     57                              ULONG title_index,
     58                              UNICODE_STRING* class_name,
     59                              ULONG create_options,
     60                              ULONG* disposition,
     61                              HANDLE target_process) {
     62   NtCreateKeyFunction NtCreateKey = NULL;
     63   ResolveNTFunctionPtr("NtCreateKey", &NtCreateKey);
     64 
     65   if (MAXIMUM_ALLOWED & desired_access) {
     66     NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
     67     if (!NT_SUCCESS(status))
     68       return STATUS_ACCESS_DENIED;
     69   }
     70 
     71   HANDLE local_handle = INVALID_HANDLE_VALUE;
     72   NTSTATUS status = NtCreateKey(&local_handle, desired_access, obj_attributes,
     73                                 title_index, class_name, create_options,
     74                                 disposition);
     75   if (!NT_SUCCESS(status))
     76     return status;
     77 
     78   if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
     79                          target_process, target_key_handle, 0, FALSE,
     80                          DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
     81     return STATUS_ACCESS_DENIED;
     82   }
     83   return STATUS_SUCCESS;
     84 }
     85 
     86 NTSTATUS NtOpenKeyInTarget(HANDLE* target_key_handle,
     87                            ACCESS_MASK desired_access,
     88                            OBJECT_ATTRIBUTES* obj_attributes,
     89                            HANDLE target_process) {
     90   NtOpenKeyFunction NtOpenKey = NULL;
     91   ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
     92 
     93   if (MAXIMUM_ALLOWED & desired_access) {
     94     NTSTATUS status = TranslateMaximumAllowed(obj_attributes, &desired_access);
     95     if (!NT_SUCCESS(status))
     96       return STATUS_ACCESS_DENIED;
     97   }
     98 
     99   HANDLE local_handle = INVALID_HANDLE_VALUE;
    100   NTSTATUS status = NtOpenKey(&local_handle, desired_access, obj_attributes);
    101 
    102   if (!NT_SUCCESS(status))
    103     return status;
    104 
    105   if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    106                          target_process, target_key_handle, 0, FALSE,
    107                          DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    108     return STATUS_ACCESS_DENIED;
    109   }
    110   return STATUS_SUCCESS;
    111 }
    112 
    113 }
    114 
    115 namespace sandbox {
    116 
    117 bool RegistryPolicy::GenerateRules(const wchar_t* name,
    118                                    TargetPolicy::Semantics semantics,
    119                                    LowLevelPolicy* policy) {
    120   base::string16 resovled_name(name);
    121   if (resovled_name.empty()) {
    122     return false;
    123   }
    124 
    125   if (!ResolveRegistryName(resovled_name, &resovled_name))
    126     return false;
    127 
    128   name = resovled_name.c_str();
    129 
    130   EvalResult result = ASK_BROKER;
    131 
    132   PolicyRule open(result);
    133   PolicyRule create(result);
    134 
    135   switch (semantics) {
    136     case TargetPolicy::REG_ALLOW_READONLY: {
    137       // We consider all flags that are not known to be readonly as potentially
    138       // used for write. Here we also support MAXIMUM_ALLOWED, but we are going
    139       // to expand it to read-only before the call.
    140       DWORD restricted_flags = ~(kAllowedRegFlags | MAXIMUM_ALLOWED);
    141       open.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
    142       create.AddNumberMatch(IF_NOT, OpenKey::ACCESS, restricted_flags, AND);
    143       break;
    144     }
    145     case TargetPolicy::REG_ALLOW_ANY: {
    146       break;
    147     }
    148     default: {
    149       NOTREACHED();
    150       return false;
    151     }
    152   }
    153 
    154   if (!create.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
    155       !policy->AddRule(IPC_NTCREATEKEY_TAG, &create)) {
    156     return false;
    157   }
    158 
    159   if (!open.AddStringMatch(IF, OpenKey::NAME, name, CASE_INSENSITIVE) ||
    160       !policy->AddRule(IPC_NTOPENKEY_TAG, &open)) {
    161     return false;
    162   }
    163 
    164   return true;
    165 }
    166 
    167 bool RegistryPolicy::CreateKeyAction(EvalResult eval_result,
    168                                      const ClientInfo& client_info,
    169                                      const base::string16 &key,
    170                                      uint32 attributes,
    171                                      HANDLE root_directory,
    172                                      uint32 desired_access,
    173                                      uint32 title_index,
    174                                      uint32 create_options,
    175                                      HANDLE* handle,
    176                                      NTSTATUS* nt_status,
    177                                      ULONG* disposition) {
    178   // The only action supported is ASK_BROKER which means create the requested
    179   // file as specified.
    180   if (ASK_BROKER != eval_result) {
    181     *nt_status = STATUS_ACCESS_DENIED;
    182     return false;
    183   }
    184 
    185   // We don't support creating link keys, volatile keys or backup/restore.
    186   if (create_options) {
    187     *nt_status = STATUS_ACCESS_DENIED;
    188     return false;
    189   }
    190 
    191   UNICODE_STRING uni_name = {0};
    192   OBJECT_ATTRIBUTES obj_attributes = {0};
    193   InitObjectAttribs(key, attributes, root_directory, &obj_attributes,
    194                     &uni_name);
    195   *nt_status = NtCreateKeyInTarget(handle, desired_access, &obj_attributes,
    196                                    title_index, NULL, create_options,
    197                                    disposition, client_info.process);
    198   return true;
    199 }
    200 
    201 bool RegistryPolicy::OpenKeyAction(EvalResult eval_result,
    202                                    const ClientInfo& client_info,
    203                                    const base::string16 &key,
    204                                    uint32 attributes,
    205                                    HANDLE root_directory,
    206                                    uint32 desired_access,
    207                                    HANDLE* handle,
    208                                    NTSTATUS* nt_status) {
    209   // The only action supported is ASK_BROKER which means open the requested
    210   // file as specified.
    211   if (ASK_BROKER != eval_result) {
    212     *nt_status = STATUS_ACCESS_DENIED;
    213     return true;
    214   }
    215 
    216   UNICODE_STRING uni_name = {0};
    217   OBJECT_ATTRIBUTES obj_attributes = {0};
    218   InitObjectAttribs(key, attributes, root_directory, &obj_attributes,
    219                     &uni_name);
    220   *nt_status = NtOpenKeyInTarget(handle, desired_access, &obj_attributes,
    221                                 client_info.process);
    222   return true;
    223 }
    224 
    225 }  // namespace sandbox
    226