security/sandbox/win/src/filesystem_policy.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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.
     5 #include <string>
     7 #include "sandbox/win/src/filesystem_policy.h"
     9 #include "base/logging.h"
    10 #include "base/win/scoped_handle.h"
    11 #include "sandbox/win/src/ipc_tags.h"
    12 #include "sandbox/win/src/policy_engine_opcodes.h"
    13 #include "sandbox/win/src/policy_params.h"
    14 #include "sandbox/win/src/sandbox_utils.h"
    15 #include "sandbox/win/src/sandbox_types.h"
    16 #include "sandbox/win/src/win_utils.h"
    18 namespace {
    20 NTSTATUS NtCreateFileInTarget(HANDLE* target_file_handle,
    21                               ACCESS_MASK desired_access,
    22                               OBJECT_ATTRIBUTES* obj_attributes,
    23                               IO_STATUS_BLOCK* io_status_block,
    24                               ULONG file_attributes,
    25                               ULONG share_access,
    26                               ULONG create_disposition,
    27                               ULONG create_options,
    28                               PVOID ea_buffer,
    29                               ULONG ea_lenght,
    30                               HANDLE target_process) {
    31   NtCreateFileFunction NtCreateFile = NULL;
    32   ResolveNTFunctionPtr("NtCreateFile", &NtCreateFile);
    34   HANDLE local_handle = INVALID_HANDLE_VALUE;
    35   NTSTATUS status = NtCreateFile(&local_handle, desired_access, obj_attributes,
    36                                  io_status_block, NULL, file_attributes,
    37                                  share_access, create_disposition,
    38                                  create_options, ea_buffer, ea_lenght);
    39   if (!NT_SUCCESS(status)) {
    40     return status;
    41   }
    43   if (!sandbox::SameObject(local_handle, obj_attributes->ObjectName->Buffer)) {
    44     // The handle points somewhere else. Fail the operation.
    45     ::CloseHandle(local_handle);
    46     return STATUS_ACCESS_DENIED;
    47   }
    49   if (!::DuplicateHandle(::GetCurrentProcess(), local_handle,
    50                          target_process, target_file_handle, 0, FALSE,
    51                          DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    52     return STATUS_ACCESS_DENIED;
    53   }
    54   return STATUS_SUCCESS;
    55 }
    57 }  // namespace.
    59 namespace sandbox {
    61 bool FileSystemPolicy::GenerateRules(const wchar_t* name,
    62                                      TargetPolicy::Semantics semantics,
    63                                      LowLevelPolicy* policy) {
    64   std::wstring mod_name(name);
    65   if (mod_name.empty()) {
    66     return false;
    67   }
    69   // Don't do any pre-processing if the name starts like the the native
    70   // object manager style.
    71   if (0 != _wcsnicmp(mod_name.c_str(), kNTObjManPrefix, kNTObjManPrefixLen)) {
    72     // TODO(cpu) bug 32224: This prefix add is a hack because we don't have the
    73     // infrastructure to normalize names. In any case we need to escape the
    74     // question marks.
    75     if (!PreProcessName(mod_name, &mod_name)) {
    76       // The path to be added might contain a reparse point.
    77       NOTREACHED();
    78       return false;
    79     }
    80     if (0 != mod_name.compare(0, kNTPrefixLen, kNTPrefix)) {
    81       // TODO(nsylvain): Find a better way to do name resolution. Right now we
    82       // take the name and we expand it.
    83       mod_name.insert(0, L"\\/?/?\\");
    84       name = mod_name.c_str();
    85     }
    86   }
    88   EvalResult result = ASK_BROKER;
    90   // List of supported calls for the filesystem.
    91   const unsigned kCallNtCreateFile = 0x1;
    92   const unsigned kCallNtOpenFile = 0x2;
    93   const unsigned kCallNtQueryAttributesFile = 0x4;
    94   const unsigned kCallNtQueryFullAttributesFile = 0x8;
    95   const unsigned kCallNtSetInfoRename = 0x10;
    97   DWORD  rule_to_add = kCallNtOpenFile | kCallNtCreateFile |
    98                        kCallNtQueryAttributesFile |
    99                        kCallNtQueryFullAttributesFile | kCallNtSetInfoRename;
   101   PolicyRule create(result);
   102   PolicyRule open(result);
   103   PolicyRule query(result);
   104   PolicyRule query_full(result);
   105   PolicyRule rename(result);
   107   switch (semantics) {
   108     case TargetPolicy::FILES_ALLOW_DIR_ANY: {
   109       open.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
   110       create.AddNumberMatch(IF, OpenFile::OPTIONS, FILE_DIRECTORY_FILE, AND);
   111       break;
   112     }
   113     case TargetPolicy::FILES_ALLOW_READONLY: {
   114       // We consider all flags that are not known to be readonly as potentially
   115       // used for write.
   116       DWORD allowed_flags = FILE_READ_DATA | FILE_READ_ATTRIBUTES |
   117                             FILE_READ_EA | SYNCHRONIZE | FILE_EXECUTE |
   118                             GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL;
   119       DWORD restricted_flags = ~allowed_flags;
   120       open.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
   121       create.AddNumberMatch(IF_NOT, OpenFile::ACCESS, restricted_flags, AND);
   123       // Read only access don't work for rename.
   124       rule_to_add &= ~kCallNtSetInfoRename;
   125       break;
   126     }
   127     case TargetPolicy::FILES_ALLOW_QUERY: {
   128       // Here we don't want to add policy for the open or the create.
   129       rule_to_add &= ~(kCallNtOpenFile | kCallNtCreateFile |
   130                        kCallNtSetInfoRename);
   131       break;
   132     }
   133     case TargetPolicy::FILES_ALLOW_ANY: {
   134       break;
   135     }
   136     default: {
   137       NOTREACHED();
   138       return false;
   139     }
   140   }
   142   if ((rule_to_add & kCallNtCreateFile) &&
   143       (!create.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
   144        !policy->AddRule(IPC_NTCREATEFILE_TAG, &create))) {
   145     return false;
   146   }
   148   if ((rule_to_add & kCallNtOpenFile) &&
   149       (!open.AddStringMatch(IF, OpenFile::NAME, name, CASE_INSENSITIVE) ||
   150        !policy->AddRule(IPC_NTOPENFILE_TAG, &open))) {
   151     return false;
   152   }
   154   if ((rule_to_add & kCallNtQueryAttributesFile) &&
   155       (!query.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
   156        !policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &query))) {
   157     return false;
   158   }
   160   if ((rule_to_add & kCallNtQueryFullAttributesFile) &&
   161       (!query_full.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE)
   162        || !policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
   163                            &query_full))) {
   164     return false;
   165   }
   167   if ((rule_to_add & kCallNtSetInfoRename) &&
   168       (!rename.AddStringMatch(IF, FileName::NAME, name, CASE_INSENSITIVE) ||
   169        !policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &rename))) {
   170     return false;
   171   }
   173   return true;
   174 }
   176 // Right now we insert two rules, to be evaluated before any user supplied rule:
   177 // - go to the broker if the path doesn't look like the paths that we push on
   178 //    the policy (namely \??\something).
   179 // - go to the broker if it looks like this is a short-name path.
   180 //
   181 // It is possible to add a rule to go to the broker in any case; it would look
   182 // something like:
   183 //    rule = new PolicyRule(ASK_BROKER);
   184 //    rule->AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
   185 //    policy->AddRule(service, rule);
   186 bool FileSystemPolicy::SetInitialRules(LowLevelPolicy* policy) {
   187   PolicyRule format(ASK_BROKER);
   188   PolicyRule short_name(ASK_BROKER);
   190   bool rv = format.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
   191   rv &= format.AddStringMatch(IF_NOT, FileName::NAME, L"\\/?/?\\*",
   192                               CASE_SENSITIVE);
   194   rv &= short_name.AddNumberMatch(IF_NOT, FileName::BROKER, TRUE, AND);
   195   rv &= short_name.AddStringMatch(IF, FileName::NAME, L"*~*", CASE_SENSITIVE);
   197   if (!rv || !policy->AddRule(IPC_NTCREATEFILE_TAG, &format))
   198     return false;
   200   if (!policy->AddRule(IPC_NTCREATEFILE_TAG, &short_name))
   201     return false;
   203   if (!policy->AddRule(IPC_NTOPENFILE_TAG, &format))
   204     return false;
   206   if (!policy->AddRule(IPC_NTOPENFILE_TAG, &short_name))
   207     return false;
   209   if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &format))
   210     return false;
   212   if (!policy->AddRule(IPC_NTQUERYATTRIBUTESFILE_TAG, &short_name))
   213     return false;
   215   if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &format))
   216     return false;
   218   if (!policy->AddRule(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, &short_name))
   219     return false;
   221   if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &format))
   222     return false;
   224   if (!policy->AddRule(IPC_NTSETINFO_RENAME_TAG, &short_name))
   225     return false;
   227   return true;
   228 }
   230 bool FileSystemPolicy::CreateFileAction(EvalResult eval_result,
   231                                         const ClientInfo& client_info,
   232                                         const std::wstring &file,
   233                                         uint32 attributes,
   234                                         uint32 desired_access,
   235                                         uint32 file_attributes,
   236                                         uint32 share_access,
   237                                         uint32 create_disposition,
   238                                         uint32 create_options,
   239                                         HANDLE *handle,
   240                                         NTSTATUS* nt_status,
   241                                         ULONG_PTR *io_information) {
   242   // The only action supported is ASK_BROKER which means create the requested
   243   // file as specified.
   244   if (ASK_BROKER != eval_result) {
   245     *nt_status = STATUS_ACCESS_DENIED;
   246     return false;
   247   }
   248   IO_STATUS_BLOCK io_block = {0};
   249   UNICODE_STRING uni_name = {0};
   250   OBJECT_ATTRIBUTES obj_attributes = {0};
   251   InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
   252   *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
   253                                     &io_block, file_attributes, share_access,
   254                                     create_disposition, create_options, NULL,
   255                                     0, client_info.process);
   257   *io_information = io_block.Information;
   258   return true;
   259 }
   261 bool FileSystemPolicy::OpenFileAction(EvalResult eval_result,
   262                                       const ClientInfo& client_info,
   263                                       const std::wstring &file,
   264                                       uint32 attributes,
   265                                       uint32 desired_access,
   266                                       uint32 share_access,
   267                                       uint32 open_options,
   268                                       HANDLE *handle,
   269                                       NTSTATUS* nt_status,
   270                                       ULONG_PTR *io_information) {
   271   // The only action supported is ASK_BROKER which means open the requested
   272   // file as specified.
   273   if (ASK_BROKER != eval_result) {
   274     *nt_status = STATUS_ACCESS_DENIED;
   275     return true;
   276   }
   277   // An NtOpen is equivalent to an NtCreate with FileAttributes = 0 and
   278   // CreateDisposition = FILE_OPEN.
   279   IO_STATUS_BLOCK io_block = {0};
   280   UNICODE_STRING uni_name = {0};
   281   OBJECT_ATTRIBUTES obj_attributes = {0};
   282   InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
   283   *nt_status = NtCreateFileInTarget(handle, desired_access, &obj_attributes,
   284                                     &io_block, 0, share_access, FILE_OPEN,
   285                                     open_options, NULL, 0,
   286                                     client_info.process);
   288   *io_information = io_block.Information;
   289   return true;
   290 }
   292 bool FileSystemPolicy::QueryAttributesFileAction(
   293     EvalResult eval_result,
   294     const ClientInfo& client_info,
   295     const std::wstring &file,
   296     uint32 attributes,
   297     FILE_BASIC_INFORMATION* file_info,
   298     NTSTATUS* nt_status) {
   299   // The only action supported is ASK_BROKER which means query the requested
   300   // file as specified.
   301   if (ASK_BROKER != eval_result) {
   302     *nt_status = STATUS_ACCESS_DENIED;
   303     return true;
   304   }
   306   NtQueryAttributesFileFunction NtQueryAttributesFile = NULL;
   307   ResolveNTFunctionPtr("NtQueryAttributesFile", &NtQueryAttributesFile);
   309   UNICODE_STRING uni_name = {0};
   310   OBJECT_ATTRIBUTES obj_attributes = {0};
   311   InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
   312   *nt_status = NtQueryAttributesFile(&obj_attributes, file_info);
   314   return true;
   315 }
   317 bool FileSystemPolicy::QueryFullAttributesFileAction(
   318     EvalResult eval_result,
   319     const ClientInfo& client_info,
   320     const std::wstring &file,
   321     uint32 attributes,
   322     FILE_NETWORK_OPEN_INFORMATION* file_info,
   323     NTSTATUS* nt_status) {
   324   // The only action supported is ASK_BROKER which means query the requested
   325   // file as specified.
   326   if (ASK_BROKER != eval_result) {
   327     *nt_status = STATUS_ACCESS_DENIED;
   328     return true;
   329   }
   331   NtQueryFullAttributesFileFunction NtQueryFullAttributesFile = NULL;
   332   ResolveNTFunctionPtr("NtQueryFullAttributesFile", &NtQueryFullAttributesFile);
   334   UNICODE_STRING uni_name = {0};
   335   OBJECT_ATTRIBUTES obj_attributes = {0};
   336   InitObjectAttribs(file, attributes, NULL, &obj_attributes, &uni_name);
   337   *nt_status = NtQueryFullAttributesFile(&obj_attributes, file_info);
   339   return true;
   340 }
   342 bool FileSystemPolicy::SetInformationFileAction(
   343     EvalResult eval_result, const ClientInfo& client_info,
   344     HANDLE target_file_handle, void* file_info, uint32 length,
   345     uint32 info_class, IO_STATUS_BLOCK* io_block,
   346     NTSTATUS* nt_status) {
   347   // The only action supported is ASK_BROKER which means open the requested
   348   // file as specified.
   349   if (ASK_BROKER != eval_result) {
   350     *nt_status = STATUS_ACCESS_DENIED;
   351     return true;
   352   }
   354   NtSetInformationFileFunction NtSetInformationFile = NULL;
   355   ResolveNTFunctionPtr("NtSetInformationFile", &NtSetInformationFile);
   357   HANDLE local_handle = NULL;
   358   if (!::DuplicateHandle(client_info.process, target_file_handle,
   359                          ::GetCurrentProcess(), &local_handle, 0, FALSE,
   360                          DUPLICATE_SAME_ACCESS)) {
   361     *nt_status = STATUS_ACCESS_DENIED;
   362     return true;
   363   }
   365   base::win::ScopedHandle handle(local_handle);
   367   FILE_INFORMATION_CLASS file_info_class =
   368       static_cast<FILE_INFORMATION_CLASS>(info_class);
   369   *nt_status = NtSetInformationFile(local_handle, io_block, file_info, length,
   370                                     file_info_class);
   372   return true;
   373 }
   375 bool PreProcessName(const std::wstring& path, std::wstring* new_path) {
   376   ConvertToLongPath(path, new_path);
   378   bool reparsed = false;
   379   if (ERROR_SUCCESS != IsReparsePoint(*new_path, &reparsed))
   380     return false;
   382   // We can't process reparsed file.
   383   return !reparsed;
   384 }
   386 }  // namespace sandbox

mercurial