* Copyright (c) 2015-2020 Google, Inc. All rights reserved.
* Copyright (c) 2006-2010 VMware, Inc. All rights reserved.
* **********************************************************/
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include "tools.h"
#define VERBOSE 0
* the NUDGE_ defines already here.
*/
byte *
get_nudge_target()
{
* just hardcode the offsets for now
*/
static const uint DR_NUDGE_FUNC_OFFSET = IF_X64_ELSE(0x28, 0x20);
return get_drmarker_field(DR_NUDGE_FUNC_OFFSET);
}
typedef unsigned int(__stdcall *threadfunc_t)(void *);
static bool test_tls = false;
#define TLS_SLOTS 64
static bool tls_own[TLS_SLOTS];
byte *
get_own_teb()
{
return (byte *)IF_X64_ELSE(__readgsqword, __readfsdword)(IF_X64_ELSE(0x30, 0x18));
}
int WINAPI
thread_func(void *arg)
{
int i;
while (!test_tls)
;
for (i = 0; i < TLS_SLOTS; i++) {
if (tls_own[i]) {
if (TlsGetValue(i) != 0) {
print("TLS slot %d is " PFX " when it should be 0!\n", i, TlsGetValue(i));
}
}
}
print("Done testing tls slots\n");
return 0;
}
int
main()
{
int tid;
HANDLE detach_thread;
HANDLE my_thread;
byte *nudge_target;
int i;
INIT();
my_thread = (HANDLE)_beginthreadex(NULL, 0, thread_func, NULL, 0, &tid);
nudge_target = get_nudge_target();
if (nudge_target == NULL) {
print("Cannot find DRmarker -- are you running natively?\n");
} else {
* hole in DR by creating a thread that directly targets the DR
* detach routine. Hopefully this will motivate us to close
* the hole (case 552) :)
* Update: rather than use raw system calls, which are complex across
* Windows versions and duplicate code with core/, we use a high-level
* thread creation API. DR does detect and stop this, but we have a
* relaxation for this test in DEBUG.
* The alternative is to create a new runall type that detaches from
* the outside and then waits a while, but would be hard to time.
*/
nudge_arg_t *arg = (nudge_arg_t *)VirtualAlloc(NULL, sizeof(nudge_arg_t),
MEM_COMMIT, PAGE_READWRITE);
arg->version = NUDGE_ARG_CURRENT_VERSION;
arg->nudge_action_mask = NUDGE_GENERIC(detach);
arg->flags = 0;
arg->client_arg = 0;
print("About to detach using underhanded methods\n");
detach_thread =
(HANDLE)_beginthreadex(NULL, 0, (threadfunc_t)nudge_target, arg, 0, &tid);
assert(detach_thread != NULL);
WaitForSingleObject(detach_thread, INFINITE);
assert(get_nudge_target() == NULL);
print("Running natively now\n");
}
for (i = 0; i < TLS_SLOTS; i++) {
* a value for already-existing threads. The "official" method
* is to directly TlsGetValue() and if not NULL assume that dll
* has already set that value. Our detach needs to clear values
* to ensure this. We have the simplest test possible here, of course.
* We do need another thread as TlsAlloc seems to clear the slot for
* the current thread.
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/using_thread_local_storage_in_a_dynamic_link_library.asp
*/
unsigned long tlshandle = 0UL;
tlshandle = TlsAlloc();
if (tlshandle == TLS_OUT_OF_INDEXES) {
break;
}
#if VERBOSE
print("handle %d is %d\n", i, tlshandle);
#endif
assert(tlshandle >= 0);
if (tlshandle >= TLS_SLOTS)
break;
tls_own[tlshandle] = true;
}
test_tls = true;
WaitForSingleObject(my_thread, INFINITE);
return 0;
}