1 // Copyright (c) 2006-2010 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 // For information about interceptions as a whole see
6 // http://dev.chromium.org/developers/design-documents/sandbox .
8 #include "sandbox/win/src/interception_agent.h"
10 #include "sandbox/win/src/interception_internal.h"
11 #include "sandbox/win/src/interceptors.h"
12 #include "sandbox/win/src/eat_resolver.h"
13 #include "sandbox/win/src/sidestep_resolver.h"
14 #include "sandbox/win/src/sandbox_nt_util.h"
18 // Returns true if target lies between base and base + range.
19 bool IsWithinRange(const void* base
, size_t range
, const void* target
) {
20 const char* end
= reinterpret_cast<const char*>(base
) + range
;
21 return reinterpret_cast<const char*>(target
) < end
;
28 // This is the list of all imported symbols from ntdll.dll.
29 SANDBOX_INTERCEPT NtExports g_nt
;
31 // The list of intercepted functions back-pointers.
32 SANDBOX_INTERCEPT OriginalFunctions g_originals
;
34 // Memory buffer mapped from the parent, with the list of interceptions.
35 SANDBOX_INTERCEPT SharedMemory
* g_interceptions
= NULL
;
37 InterceptionAgent
* InterceptionAgent::GetInterceptionAgent() {
38 static InterceptionAgent
* s_singleton
= NULL
;
43 size_t array_bytes
= g_interceptions
->num_intercepted_dlls
* sizeof(void*);
44 s_singleton
= reinterpret_cast<InterceptionAgent
*>(
45 new(NT_ALLOC
) char[array_bytes
+ sizeof(InterceptionAgent
)]);
47 bool success
= s_singleton
->Init(g_interceptions
);
49 operator delete(s_singleton
, NT_ALLOC
);
56 bool InterceptionAgent::Init(SharedMemory
* shared_memory
) {
57 interceptions_
= shared_memory
;
58 for (int i
= 0 ; i
< shared_memory
->num_intercepted_dlls
; i
++)
63 bool InterceptionAgent::DllMatch(const UNICODE_STRING
* full_path
,
64 const UNICODE_STRING
* name
,
65 const DllPatchInfo
* dll_info
) {
66 UNICODE_STRING current_name
;
67 current_name
.Length
= static_cast<USHORT
>(g_nt
.wcslen(dll_info
->dll_name
) *
69 current_name
.MaximumLength
= current_name
.Length
;
70 current_name
.Buffer
= const_cast<wchar_t*>(dll_info
->dll_name
);
72 BOOLEAN case_insensitive
= TRUE
;
74 !g_nt
.RtlCompareUnicodeString(¤t_name
, full_path
, case_insensitive
))
78 !g_nt
.RtlCompareUnicodeString(¤t_name
, name
, case_insensitive
))
84 bool InterceptionAgent::OnDllLoad(const UNICODE_STRING
* full_path
,
85 const UNICODE_STRING
* name
,
87 DllPatchInfo
* dll_info
= interceptions_
->dll_list
;
89 for (; i
< interceptions_
->num_intercepted_dlls
; i
++) {
90 if (DllMatch(full_path
, name
, dll_info
))
93 dll_info
= reinterpret_cast<DllPatchInfo
*>(
94 reinterpret_cast<char*>(dll_info
) + dll_info
->record_bytes
);
97 // Return now if the dll is not in our list of interest.
98 if (i
== interceptions_
->num_intercepted_dlls
)
101 // The dll must be unloaded.
102 if (dll_info
->unload_module
)
105 // Purify causes this condition to trigger.
109 size_t buffer_bytes
= offsetof(DllInterceptionData
, thunks
) +
110 dll_info
->num_functions
* sizeof(ThunkData
);
111 dlls_
[i
] = reinterpret_cast<DllInterceptionData
*>(
112 new(NT_PAGE
, base_address
) char[buffer_bytes
]);
118 dlls_
[i
]->data_bytes
= buffer_bytes
;
119 dlls_
[i
]->num_thunks
= 0;
120 dlls_
[i
]->base
= base_address
;
121 dlls_
[i
]->used_bytes
= offsetof(DllInterceptionData
, thunks
);
123 VERIFY(PatchDll(dll_info
, dlls_
[i
]));
126 SIZE_T real_size
= buffer_bytes
;
127 void* to_protect
= dlls_
[i
];
128 VERIFY_SUCCESS(g_nt
.ProtectVirtualMemory(NtCurrentProcess
, &to_protect
,
129 &real_size
, PAGE_EXECUTE_READ
,
134 void InterceptionAgent::OnDllUnload(void* base_address
) {
135 for (int i
= 0; i
< interceptions_
->num_intercepted_dlls
; i
++) {
136 if (dlls_
[i
] && dlls_
[i
]->base
== base_address
) {
137 operator delete(dlls_
[i
], NT_PAGE
);
144 // TODO(rvargas): We have to deal with prebinded dlls. I see two options: change
145 // the timestamp of the patched dll, or modify the info on the prebinded dll.
146 // the first approach messes matching of debug symbols, the second one is more
148 bool InterceptionAgent::PatchDll(const DllPatchInfo
* dll_info
,
149 DllInterceptionData
* thunks
) {
150 DCHECK_NT(NULL
!= thunks
);
151 DCHECK_NT(NULL
!= dll_info
);
153 const FunctionInfo
* function
= reinterpret_cast<const FunctionInfo
*>(
154 reinterpret_cast<const char*>(dll_info
) + dll_info
->offset_to_functions
);
156 for (int i
= 0; i
< dll_info
->num_functions
; i
++) {
157 if (!IsWithinRange(dll_info
, dll_info
->record_bytes
, function
->function
)) {
162 ResolverThunk
* resolver
= GetResolver(function
->type
);
166 const char* interceptor
= function
->function
+
167 g_nt
.strlen(function
->function
) + 1;
169 if (!IsWithinRange(function
, function
->record_bytes
, interceptor
) ||
170 !IsWithinRange(dll_info
, dll_info
->record_bytes
, interceptor
)) {
175 NTSTATUS ret
= resolver
->Setup(thunks
->base
,
176 interceptions_
->interceptor_base
,
179 function
->interceptor_address
,
183 if (!NT_SUCCESS(ret
)) {
188 DCHECK_NT(!g_originals
[function
->id
]);
189 g_originals
[function
->id
] = &thunks
->thunks
[i
];
191 thunks
->num_thunks
++;
192 thunks
->used_bytes
+= sizeof(ThunkData
);
194 function
= reinterpret_cast<const FunctionInfo
*>(
195 reinterpret_cast<const char*>(function
) + function
->record_bytes
);
201 // This method is called from within the loader lock
202 ResolverThunk
* InterceptionAgent::GetResolver(InterceptionType type
) {
203 static EatResolverThunk
* eat_resolver
= NULL
;
204 static SidestepResolverThunk
* sidestep_resolver
= NULL
;
205 static SmartSidestepResolverThunk
* smart_sidestep_resolver
= NULL
;
208 eat_resolver
= new(NT_ALLOC
) EatResolverThunk
;
211 // Sidestep is not supported for x64.
212 if (!sidestep_resolver
)
213 sidestep_resolver
= new(NT_ALLOC
) SidestepResolverThunk
;
215 if (!smart_sidestep_resolver
)
216 smart_sidestep_resolver
= new(NT_ALLOC
) SmartSidestepResolverThunk
;
220 case INTERCEPTION_EAT
:
222 case INTERCEPTION_SIDESTEP
:
223 return sidestep_resolver
;
224 case INTERCEPTION_SMART_SIDESTEP
:
225 return smart_sidestep_resolver
;
233 } // namespace sandbox