security/sandbox/win/src/process_thread_interception.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) 2006-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 "sandbox/win/src/process_thread_interception.h"
     7 #include "sandbox/win/src/crosscall_client.h"
     8 #include "sandbox/win/src/ipc_tags.h"
     9 #include "sandbox/win/src/policy_params.h"
    10 #include "sandbox/win/src/policy_target.h"
    11 #include "sandbox/win/src/sandbox_factory.h"
    12 #include "sandbox/win/src/sandbox_nt_util.h"
    13 #include "sandbox/win/src/sharedmem_ipc_client.h"
    14 #include "sandbox/win/src/target_services.h"
    16 namespace sandbox {
    18 SANDBOX_INTERCEPT NtExports g_nt;
    20 // Hooks NtOpenThread and proxy the call to the broker if it's trying to
    21 // open a thread in the same process.
    22 NTSTATUS WINAPI TargetNtOpenThread(NtOpenThreadFunction orig_OpenThread,
    23                                    PHANDLE thread, ACCESS_MASK desired_access,
    24                                    POBJECT_ATTRIBUTES object_attributes,
    25                                    PCLIENT_ID client_id) {
    26   NTSTATUS status = orig_OpenThread(thread, desired_access, object_attributes,
    27                                     client_id);
    28   if (NT_SUCCESS(status))
    29     return status;
    31   do {
    32     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
    33       break;
    34     if (!client_id)
    35       break;
    37     uint32 thread_id = 0;
    38     bool should_break = false;
    39     __try {
    40       // We support only the calls for the current process
    41       if (NULL != client_id->UniqueProcess)
    42         should_break = true;
    44       // Object attributes should be NULL or empty.
    45       if (!should_break && NULL != object_attributes) {
    46         if (0 != object_attributes->Attributes ||
    47             NULL != object_attributes->ObjectName ||
    48             NULL != object_attributes->RootDirectory ||
    49             NULL != object_attributes->SecurityDescriptor ||
    50             NULL != object_attributes->SecurityQualityOfService) {
    51           should_break = true;
    52         }
    53       }
    55       thread_id = static_cast<uint32>(
    56                       reinterpret_cast<ULONG_PTR>(client_id->UniqueThread));
    57     } __except(EXCEPTION_EXECUTE_HANDLER) {
    58       break;
    59     }
    61     if (should_break)
    62       break;
    64     if (!ValidParameter(thread, sizeof(HANDLE), WRITE))
    65       break;
    67     void* memory = GetGlobalIPCMemory();
    68     if (NULL == memory)
    69       break;
    71     SharedMemIPCClient ipc(memory);
    72     CrossCallReturn answer = {0};
    73     ResultCode code = CrossCall(ipc, IPC_NTOPENTHREAD_TAG, desired_access,
    74                                 thread_id, &answer);
    75     if (SBOX_ALL_OK != code)
    76       break;
    78     if (!NT_SUCCESS(answer.nt_status))
    79       // The nt_status here is most likely STATUS_INVALID_CID because
    80       // in the broker we set the process id in the CID (client ID) param
    81       // to be the current process. If you try to open a thread from another
    82       // process you will get this INVALID_CID error. On the other hand, if you
    83       // try to open a thread in your own process, it should return success.
    84       // We don't want to return STATUS_INVALID_CID here, so we return the
    85       // return of the original open thread status, which is most likely
    86       // STATUS_ACCESS_DENIED.
    87       break;
    89     __try {
    90       // Write the output parameters.
    91       *thread = answer.handle;
    92     } __except(EXCEPTION_EXECUTE_HANDLER) {
    93       break;
    94     }
    96     return answer.nt_status;
    97   } while (false);
    99   return status;
   100 }
   102 // Hooks NtOpenProcess and proxy the call to the broker if it's trying to
   103 // open the current process.
   104 NTSTATUS WINAPI TargetNtOpenProcess(NtOpenProcessFunction orig_OpenProcess,
   105                                    PHANDLE process, ACCESS_MASK desired_access,
   106                                    POBJECT_ATTRIBUTES object_attributes,
   107                                    PCLIENT_ID client_id) {
   108   NTSTATUS status = orig_OpenProcess(process, desired_access, object_attributes,
   109                                      client_id);
   110   if (NT_SUCCESS(status))
   111     return status;
   113   do {
   114     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
   115       break;
   116     if (!client_id)
   117       break;
   119     uint32 process_id = 0;
   120     bool should_break = false;
   121     __try {
   122       // Object attributes should be NULL or empty.
   123       if (!should_break && NULL != object_attributes) {
   124         if (0 != object_attributes->Attributes ||
   125             NULL != object_attributes->ObjectName ||
   126             NULL != object_attributes->RootDirectory ||
   127             NULL != object_attributes->SecurityDescriptor ||
   128             NULL != object_attributes->SecurityQualityOfService) {
   129           should_break = true;
   130         }
   131       }
   133       process_id = static_cast<uint32>(
   134                       reinterpret_cast<ULONG_PTR>(client_id->UniqueProcess));
   135     } __except(EXCEPTION_EXECUTE_HANDLER) {
   136       break;
   137     }
   139     if (should_break)
   140       break;
   142     if (!ValidParameter(process, sizeof(HANDLE), WRITE))
   143       break;
   145     void* memory = GetGlobalIPCMemory();
   146     if (NULL == memory)
   147       break;
   149     SharedMemIPCClient ipc(memory);
   150     CrossCallReturn answer = {0};
   151     ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESS_TAG, desired_access,
   152                                 process_id, &answer);
   153     if (SBOX_ALL_OK != code)
   154       break;
   156     if (!NT_SUCCESS(answer.nt_status))
   157       return answer.nt_status;
   159     __try {
   160       // Write the output parameters.
   161       *process = answer.handle;
   162     } __except(EXCEPTION_EXECUTE_HANDLER) {
   163       break;
   164     }
   166     return answer.nt_status;
   167   } while (false);
   169   return status;
   170 }
   173 NTSTATUS WINAPI TargetNtOpenProcessToken(
   174     NtOpenProcessTokenFunction orig_OpenProcessToken, HANDLE process,
   175     ACCESS_MASK desired_access, PHANDLE token) {
   176   NTSTATUS status = orig_OpenProcessToken(process, desired_access, token);
   177   if (NT_SUCCESS(status))
   178     return status;
   180   do {
   181     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
   182       break;
   184     if (CURRENT_PROCESS != process)
   185       break;
   187     if (!ValidParameter(token, sizeof(HANDLE), WRITE))
   188       break;
   190     void* memory = GetGlobalIPCMemory();
   191     if (NULL == memory)
   192       break;
   194     SharedMemIPCClient ipc(memory);
   195     CrossCallReturn answer = {0};
   196     ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESSTOKEN_TAG, process,
   197                                 desired_access, &answer);
   198     if (SBOX_ALL_OK != code)
   199       break;
   201     if (!NT_SUCCESS(answer.nt_status))
   202       return answer.nt_status;
   204     __try {
   205       // Write the output parameters.
   206       *token = answer.handle;
   207     } __except(EXCEPTION_EXECUTE_HANDLER) {
   208       break;
   209     }
   211     return answer.nt_status;
   212   } while (false);
   214   return status;
   215 }
   217 NTSTATUS WINAPI TargetNtOpenProcessTokenEx(
   218     NtOpenProcessTokenExFunction orig_OpenProcessTokenEx, HANDLE process,
   219     ACCESS_MASK desired_access, ULONG handle_attributes, PHANDLE token) {
   220   NTSTATUS status = orig_OpenProcessTokenEx(process, desired_access,
   221                                             handle_attributes, token);
   222   if (NT_SUCCESS(status))
   223     return status;
   225   do {
   226     if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
   227       break;
   229     if (CURRENT_PROCESS != process)
   230       break;
   232     if (!ValidParameter(token, sizeof(HANDLE), WRITE))
   233       break;
   235     void* memory = GetGlobalIPCMemory();
   236     if (NULL == memory)
   237       break;
   239     SharedMemIPCClient ipc(memory);
   240     CrossCallReturn answer = {0};
   241     ResultCode code = CrossCall(ipc, IPC_NTOPENPROCESSTOKENEX_TAG, process,
   242                                 desired_access, handle_attributes, &answer);
   243     if (SBOX_ALL_OK != code)
   244       break;
   246     if (!NT_SUCCESS(answer.nt_status))
   247       return answer.nt_status;
   249     __try {
   250       // Write the output parameters.
   251       *token = answer.handle;
   252     } __except(EXCEPTION_EXECUTE_HANDLER) {
   253       break;
   254     }
   256     return answer.nt_status;
   257   } while (false);
   259   return status;
   260 }
   262 BOOL WINAPI TargetCreateProcessW(CreateProcessWFunction orig_CreateProcessW,
   263                                  LPCWSTR application_name, LPWSTR command_line,
   264                                  LPSECURITY_ATTRIBUTES process_attributes,
   265                                  LPSECURITY_ATTRIBUTES thread_attributes,
   266                                  BOOL inherit_handles, DWORD flags,
   267                                  LPVOID environment, LPCWSTR current_directory,
   268                                  LPSTARTUPINFOW startup_info,
   269                                  LPPROCESS_INFORMATION process_information) {
   270   if (orig_CreateProcessW(application_name, command_line, process_attributes,
   271                           thread_attributes, inherit_handles, flags,
   272                           environment, current_directory, startup_info,
   273                           process_information)) {
   274     return TRUE;
   275   }
   276   DWORD original_error = ::GetLastError();
   278   // We don't trust that the IPC can work this early.
   279   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
   280     return FALSE;
   282   do {
   283     if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
   284                         WRITE))
   285       break;
   287     void* memory = GetGlobalIPCMemory();
   288     if (NULL == memory)
   289       break;
   291     const wchar_t* cur_dir = NULL;
   293     wchar_t current_directory[MAX_PATH];
   294     DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
   295     if (0 != result && result < MAX_PATH)
   296       cur_dir = current_directory;
   298     SharedMemIPCClient ipc(memory);
   299     CrossCallReturn answer = {0};
   301     InOutCountedBuffer proc_info(process_information,
   302                                  sizeof(PROCESS_INFORMATION));
   304     ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, application_name,
   305                                 command_line, cur_dir, proc_info, &answer);
   306     if (SBOX_ALL_OK != code)
   307       break;
   309     ::SetLastError(answer.win32_result);
   310     if (ERROR_SUCCESS != answer.win32_result)
   311       return FALSE;
   313     return TRUE;
   314   } while (false);
   316   ::SetLastError(original_error);
   317   return FALSE;
   318 }
   320 BOOL WINAPI TargetCreateProcessA(CreateProcessAFunction orig_CreateProcessA,
   321                                  LPCSTR application_name, LPSTR command_line,
   322                                  LPSECURITY_ATTRIBUTES process_attributes,
   323                                  LPSECURITY_ATTRIBUTES thread_attributes,
   324                                  BOOL inherit_handles, DWORD flags,
   325                                  LPVOID environment, LPCSTR current_directory,
   326                                  LPSTARTUPINFOA startup_info,
   327                                  LPPROCESS_INFORMATION process_information) {
   328   if (orig_CreateProcessA(application_name, command_line, process_attributes,
   329                           thread_attributes, inherit_handles, flags,
   330                           environment, current_directory, startup_info,
   331                           process_information)) {
   332     return TRUE;
   333   }
   334   DWORD original_error = ::GetLastError();
   336   // We don't trust that the IPC can work this early.
   337   if (!SandboxFactory::GetTargetServices()->GetState()->InitCalled())
   338     return FALSE;
   340   do {
   341     if (!ValidParameter(process_information, sizeof(PROCESS_INFORMATION),
   342                         WRITE))
   343       break;
   345     void* memory = GetGlobalIPCMemory();
   346     if (NULL == memory)
   347       break;
   349     // Convert the input params to unicode.
   350     UNICODE_STRING *cmd_unicode = NULL;
   351     UNICODE_STRING *app_unicode = NULL;
   352     if (command_line) {
   353       cmd_unicode = AnsiToUnicode(command_line);
   354       if (!cmd_unicode)
   355         break;
   356     }
   358     if (application_name) {
   359       app_unicode = AnsiToUnicode(application_name);
   360       if (!app_unicode) {
   361         operator delete(cmd_unicode, NT_ALLOC);
   362         break;
   363       }
   364     }
   366     const wchar_t* cmd_line = cmd_unicode ? cmd_unicode->Buffer : NULL;
   367     const wchar_t* app_name = app_unicode ? app_unicode->Buffer : NULL;
   368     const wchar_t* cur_dir = NULL;
   370     wchar_t current_directory[MAX_PATH];
   371     DWORD result = ::GetCurrentDirectory(MAX_PATH, current_directory);
   372     if (0 != result && result < MAX_PATH)
   373       cur_dir = current_directory;
   375     SharedMemIPCClient ipc(memory);
   376     CrossCallReturn answer = {0};
   378     InOutCountedBuffer proc_info(process_information,
   379                                  sizeof(PROCESS_INFORMATION));
   381     ResultCode code = CrossCall(ipc, IPC_CREATEPROCESSW_TAG, app_name,
   382                                 cmd_line, cur_dir, proc_info, &answer);
   384     operator delete(cmd_unicode, NT_ALLOC);
   385     operator delete(app_unicode, NT_ALLOC);
   387     if (SBOX_ALL_OK != code)
   388       break;
   390     ::SetLastError(answer.win32_result);
   391     if (ERROR_SUCCESS != answer.win32_result)
   392       return FALSE;
   394     return TRUE;
   395   } while (false);
   397   ::SetLastError(original_error);
   398   return FALSE;
   399 }
   401 // Creates a thread without registering with CSRSS. This is required if we
   402 // closed the CSRSS ALPC port after lockdown.
   403 HANDLE WINAPI TargetCreateThread(CreateThreadFunction orig_CreateThread,
   404                                  LPSECURITY_ATTRIBUTES thread_attributes,
   405                                  SIZE_T stack_size,
   406                                  LPTHREAD_START_ROUTINE start_address,
   407                                  PVOID parameter,
   408                                  DWORD creation_flags,
   409                                  LPDWORD thread_id) {
   410 // Try the normal CreateThread; switch to RtlCreateUserThread if needed.
   411   static bool use_create_thread = true;
   412   HANDLE thread;
   413   if (use_create_thread) {
   414     thread = orig_CreateThread(thread_attributes, stack_size, start_address,
   415                                parameter, creation_flags, thread_id);
   416     if (thread)
   417       return thread;
   418   }
   420   PSECURITY_DESCRIPTOR sd =
   421       thread_attributes ? thread_attributes->lpSecurityDescriptor : NULL;
   422   CLIENT_ID client_id;
   424   NTSTATUS result = g_nt.RtlCreateUserThread(NtCurrentProcess, sd,
   425                                              creation_flags & CREATE_SUSPENDED,
   426                                              0, stack_size, 0, start_address,
   427                                              parameter, &thread, &client_id);
   428   if (!NT_SUCCESS(result))
   429     return 0;
   431   // CSRSS is closed if we got here, so use RtlCreateUserThread from here on.
   432   use_create_thread = false;
   433   if (thread_id)
   434     *thread_id = HandleToUlong(client_id.UniqueThread);
   435   return thread;
   436 }
   438 // Cache the default LCID to avoid pinging CSRSS after lockdown.
   439 // TODO(jschuh): This approach will miss a default locale changes after
   440 // lockdown. In the future we may want to have the broker check instead.
   441 LCID WINAPI TargetGetUserDefaultLCID(
   442     GetUserDefaultLCIDFunction orig_GetUserDefaultLCID) {
   443   static LCID default_lcid = orig_GetUserDefaultLCID();
   444   return default_lcid;
   445 }
   447 }  // namespace sandbox

mercurial