summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/sandbox/win/src/target_interceptions.cc
blob: 1b467814c6cfb399fc9018b3ea79ee520783f0f9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "sandbox/win/src/target_interceptions.h"

#include "base/win/static_constants.h"
#include "sandbox/win/src/interception_agent.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "sandbox/win/src/sandbox_nt_util.h"

namespace sandbox {

SANDBOX_INTERCEPT NtExports g_nt;

const char KERNEL32_DLL_NAME[] = "kernel32.dll";

enum SectionLoadState {
  kBeforeKernel32,
  kAfterKernel32,
};

// Hooks NtMapViewOfSection to detect the load of DLLs. If hot patching is
// required for this dll, this functions patches it.
NTSTATUS WINAPI
TargetNtMapViewOfSection(NtMapViewOfSectionFunction orig_MapViewOfSection,
                         HANDLE section,
                         HANDLE process,
                         PVOID* base,
                         ULONG_PTR zero_bits,
                         SIZE_T commit_size,
                         PLARGE_INTEGER offset,
                         PSIZE_T view_size,
                         SECTION_INHERIT inherit,
                         ULONG allocation_type,
                         ULONG protect) {
  NTSTATUS ret = orig_MapViewOfSection(section, process, base, zero_bits,
                                       commit_size, offset, view_size, inherit,
                                       allocation_type, protect);
  static SectionLoadState s_state = kBeforeKernel32;

  do {
    if (!NT_SUCCESS(ret))
      break;

    if (!IsSameProcess(process))
      break;

    // Only check for verifier.dll or kernel32.dll loading if we haven't moved
    // past that state yet.
    if (s_state == kBeforeKernel32) {
      const char* ansi_module_name =
          GetAnsiImageInfoFromModule(reinterpret_cast<HMODULE>(*base));

      // _strnicmp below may hit read access violations for some sections. We
      // find what looks like a valid export directory for a PE module but the
      // pointer to the module name will be pointing to invalid memory.
      __try {
        // Don't initialize the heap if verifier.dll is being loaded. This
        // indicates Application Verifier is enabled and we should wait until
        // the next module is loaded.
        if (ansi_module_name &&
            (g_nt._strnicmp(
                 ansi_module_name, base::win::kApplicationVerifierDllName,
                 g_nt.strlen(base::win::kApplicationVerifierDllName) + 1) == 0))
          break;

        if (ansi_module_name &&
            (g_nt._strnicmp(ansi_module_name, KERNEL32_DLL_NAME,
                            sizeof(KERNEL32_DLL_NAME)) == 0)) {
          s_state = kAfterKernel32;
        }
      } __except (EXCEPTION_EXECUTE_HANDLER) {
      }
    }

    if (!InitHeap())
      break;

    if (!IsValidImageSection(section, base, offset, view_size))
      break;

    UINT image_flags;
    UNICODE_STRING* module_name =
        GetImageInfoFromModule(reinterpret_cast<HMODULE>(*base), &image_flags);
    UNICODE_STRING* file_name = GetBackingFilePath(*base);

    if ((!module_name) && (image_flags & MODULE_HAS_CODE)) {
      // If the module has no exports we retrieve the module name from the
      // full path of the mapped section.
      module_name = ExtractModuleName(file_name);
    }

    InterceptionAgent* agent = InterceptionAgent::GetInterceptionAgent();

    if (agent) {
      if (!agent->OnDllLoad(file_name, module_name, *base)) {
        // Interception agent is demanding to un-map the module.
        g_nt.UnmapViewOfSection(process, *base);
        *base = nullptr;
        ret = STATUS_UNSUCCESSFUL;
      }
    }

    if (module_name)
      operator delete(module_name, NT_ALLOC);

    if (file_name)
      operator delete(file_name, NT_ALLOC);

  } while (false);

  return ret;
}

NTSTATUS WINAPI
TargetNtUnmapViewOfSection(NtUnmapViewOfSectionFunction orig_UnmapViewOfSection,
                           HANDLE process,
                           PVOID base) {
  NTSTATUS ret = orig_UnmapViewOfSection(process, base);

  if (!NT_SUCCESS(ret))
    return ret;

  if (!IsSameProcess(process))
    return ret;

  InterceptionAgent* agent = InterceptionAgent::GetInterceptionAgent();

  if (agent)
    agent->OnDllUnload(base);

  return ret;
}

}  // namespace sandbox