4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-28 03:27:46 +08:00

* cygheap.cc (init_cygheap::find_tls): Add comment.

* cygtls.cc (well_known_dlls): Rephrase comment.
	(bloda_detect): New function.
	(_cygtls::call2): Call init_thread and bloda_detect for non-pthread
	threads only.
	(_cygtls::remove): Move remove_tls and remove_wq calls up to run first.
	* miscfuncs.cc (struct pthread_wrapper_arg): Rename from struct
	thread_wrapper_arg.
	(pthread_wrapper): Rename from thread_wrapper and drop "static".  Fix
	comment.  Drop call to _cygtls::remove.  Call api_fatal rather than
	ExitThread.  Explain why.
	* miscfuncs.h (pthread_wrapper): Declare pthread_wrapper.
	* thread.cc (pthread::exit): Add a FIXME comment.  Call _cygtls::remove
	before calling ExitThread.
This commit is contained in:
Corinna Vinschen 2014-11-28 12:10:12 +00:00
parent b3281dd194
commit 9d2eff6684
6 changed files with 88 additions and 57 deletions

View File

@ -1,3 +1,20 @@
2014-11-28 Corinna Vinschen <corinna@vinschen.de>
* cygheap.cc (init_cygheap::find_tls): Add comment.
* cygtls.cc (well_known_dlls): Rephrase comment.
(bloda_detect): New function.
(_cygtls::call2): Call init_thread and bloda_detect for non-pthread
threads only.
(_cygtls::remove): Move remove_tls and remove_wq calls up to run first.
* miscfuncs.cc (struct pthread_wrapper_arg): Rename from struct
thread_wrapper_arg.
(pthread_wrapper): Rename from thread_wrapper and drop "static". Fix
comment. Drop call to _cygtls::remove. Call api_fatal rather than
ExitThread. Explain why.
* miscfuncs.h (pthread_wrapper): Declare pthread_wrapper.
* thread.cc (pthread::exit): Add a FIXME comment. Call _cygtls::remove
before calling ExitThread.
2014-11-27 Corinna Vinschen <corinna@vinschen.de> 2014-11-27 Corinna Vinschen <corinna@vinschen.de>
* mount.cc (mount_info::init): Take bool argument and allow to * mount.cc (mount_info::init): Take bool argument and allow to

View File

@ -673,6 +673,7 @@ init_cygheap::find_tls (int sig, bool& issig_wait)
{ {
__try __try
{ {
/* Only pthreads have tid set to non-0. */
if (!threadlist[ix]->tid) if (!threadlist[ix]->tid)
continue; continue;
else if (sigismember (&(threadlist[ix]->sigwait_mask), sig)) else if (sigismember (&(threadlist[ix]->sigwait_mask), sig))

View File

@ -1,7 +1,7 @@
/* cygtls.cc /* cygtls.cc
Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
2013 Red Hat, Inc. 2013, 2014 Red Hat, Inc.
This software is a copyrighted work licensed under the terms of the This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
@ -38,10 +38,9 @@ dll_cmp (const void *a, const void *b)
/* Keep sorted! /* Keep sorted!
This is a list of well-known core system DLLs which contain code This is a list of well-known core system DLLs which contain code
whiuch is started in its own thread by the system. Kernel32.dll, started in its own thread by the system. Kernel32.dll, for instance,
for instance, contains the thread called on every Ctrl-C keypress contains the thread called on every Ctrl-C keypress in a console window.
in a console window. The DLLs in this list are not recognized as The DLLs in this list are not recognized as BLODAs. */
BLODAs. */
const wchar_t *well_known_dlls[] = const wchar_t *well_known_dlls[] =
{ {
L"advapi32.dll", L"advapi32.dll",
@ -55,46 +54,58 @@ const wchar_t *well_known_dlls[] =
L"ws2_32.dll", L"ws2_32.dll",
}; };
/* Optional BLODA detection. The idea is that the function address is supposed
to be within Cygwin itself. This is also true for pthreads, since pthreads
are always calling pthread::thread_init_wrapper() in thread.cc. Therefore,
every function call to a function outside of the Cygwin DLL is potentially
a thread injected into the Cygwin process by some BLODA.
But that's too simple. Assuming the application itself calls CreateThread,
then this is a bad idea, but not really invalid. So we shouldn't print a
BLODA message if the address is within the loaded image of the application.
Also, ntdll.dll starts threads into the application which */
static void
bloda_detect (DWORD (*func) (void *, void *))
{
PIMAGE_DOS_HEADER img_start = (PIMAGE_DOS_HEADER)
GetModuleHandle (NULL);
PIMAGE_NT_HEADERS32 ntheader = (PIMAGE_NT_HEADERS32)
((PBYTE) img_start + img_start->e_lfanew);
void *img_end = (void *) ((PBYTE) img_start
+ ntheader->OptionalHeader.SizeOfImage);
if (((void *) func < (void *) cygwin_hmodule
|| (void *) func > (void *) cygheap)
&& ((void *) func < (void *) img_start || (void *) func >= img_end))
{
MEMORY_BASIC_INFORMATION mbi;
wchar_t modname[PATH_MAX];
VirtualQuery ((PVOID) func, &mbi, sizeof mbi);
GetModuleFileNameW ((HMODULE) mbi.AllocationBase, modname,
PATH_MAX);
/* Fetch basename and check against list of above system DLLs. */
const wchar_t *modbasename = wcsrchr (modname, L'\\') + 1;
if (!bsearch (modbasename, well_known_dlls,
sizeof well_known_dlls / sizeof well_known_dlls[0],
sizeof well_known_dlls[0], dll_cmp))
small_printf ("\n\nPotential BLODA detected! Thread function "
"called outside of Cygwin DLL:\n %W\n\n",
modname);
}
}
void void
_cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf) _cygtls::call2 (DWORD (*func) (void *, void *), void *arg, void *buf)
{ {
init_thread (buf, func); /* If func is pthread_wrapper, the final stack hasn't been set up yet.
This only happens in pthread_wrapper itself. Thus it doesn't make
/* Optional BLODA detection. The idea is that the function address is sense to call init_thread or perform BLODA detection. pthread_wrapper
supposed to be within Cygwin itself. This is also true for pthreads, eventually calls init_thread by itself. */
since pthreads are always calling thread_wrapper in miscfuncs.cc. if ((void *) func != (void *) pthread_wrapper)
Therefore, every function call to a function outside of the Cygwin DLL
is potentially a thread injected into the Cygwin process by some BLODA.
But that's a bit too simple. Assuming the application itself calls
CreateThread, then this is a bad idea, but not really invalid. So we
shouldn't print a BLODA message if the address is within the loaded
image of the application. Also, ntdll.dll starts threads into the
application which */
if (detect_bloda)
{ {
PIMAGE_DOS_HEADER img_start = (PIMAGE_DOS_HEADER) GetModuleHandle (NULL); init_thread (buf, func);
PIMAGE_NT_HEADERS32 ntheader = (PIMAGE_NT_HEADERS32) if (detect_bloda)
((PBYTE) img_start + img_start->e_lfanew); bloda_detect (func);
void *img_end = (void *) ((PBYTE) img_start
+ ntheader->OptionalHeader.SizeOfImage);
if (((void *) func < (void *) cygwin_hmodule
|| (void *) func > (void *) cygheap)
&& ((void *) func < (void *) img_start || (void *) func >= img_end))
{
MEMORY_BASIC_INFORMATION mbi;
wchar_t modname[PATH_MAX];
VirtualQuery ((PVOID) func, &mbi, sizeof mbi);
GetModuleFileNameW ((HMODULE) mbi.AllocationBase, modname, PATH_MAX);
/* Fetch basename and check against list of above system DLLs. */
const wchar_t *modbasename = wcsrchr (modname, L'\\') + 1;
if (!bsearch (modbasename, well_known_dlls,
sizeof well_known_dlls / sizeof well_known_dlls[0],
sizeof well_known_dlls[0], dll_cmp))
small_printf ("\n\nPotential BLODA detected! Thread function "
"called outside of Cygwin DLL:\n %W\n\n", modname);
}
} }
DWORD res = func (arg, buf); DWORD res = func (arg, buf);
@ -169,6 +180,9 @@ _cygtls::remove (DWORD wait)
debug_printf ("wait %u", wait); debug_printf ("wait %u", wait);
cygheap->remove_tls (this, INFINITE);
remove_wq (wait);
/* FIXME: Need some sort of atthreadexit function to allow things like /* FIXME: Need some sort of atthreadexit function to allow things like
select to control this themselves. */ select to control this themselves. */
@ -197,8 +211,6 @@ _cygtls::remove (DWORD wait)
/* Close timer handle. */ /* Close timer handle. */
if (locals.cw_timer) if (locals.cw_timer)
NtClose (locals.cw_timer); NtClose (locals.cw_timer);
cygheap->remove_tls (this, wait);
remove_wq (wait);
} }
#ifdef __x86_64__ #ifdef __x86_64__

View File

@ -540,7 +540,7 @@ __import_address (void *imp)
parameters we don't use and instead to add parameters we need to make parameters we don't use and instead to add parameters we need to make
the function pthreads compatible. */ the function pthreads compatible. */
struct thread_wrapper_arg struct pthread_wrapper_arg
{ {
LPTHREAD_START_ROUTINE func; LPTHREAD_START_ROUTINE func;
PVOID arg; PVOID arg;
@ -549,23 +549,20 @@ struct thread_wrapper_arg
PBYTE stacklimit; PBYTE stacklimit;
}; };
static DWORD WINAPI DWORD WINAPI
thread_wrapper (PVOID arg) pthread_wrapper (PVOID arg)
{ {
/* Just plain paranoia. */ /* Just plain paranoia. */
if (!arg) if (!arg)
return ERROR_INVALID_PARAMETER; return ERROR_INVALID_PARAMETER;
/* The process is now threaded. Note the fact for later usage. */ /* The process is now threaded. Note for later usage by arc4random. */
__isthreaded = 1; __isthreaded = 1;
/* Fetch thread wrapper info and free from cygheap. */ /* Fetch thread wrapper info and free from cygheap. */
thread_wrapper_arg wrapper_arg = *(thread_wrapper_arg *) arg; pthread_wrapper_arg wrapper_arg = *(pthread_wrapper_arg *) arg;
cfree (arg); cfree (arg);
/* Remove _cygtls from this stack since it won't be used anymore. */
_my_tls.remove (0);
/* Set stack values in TEB */ /* Set stack values in TEB */
PTEB teb = NtCurrentTeb (); PTEB teb = NtCurrentTeb ();
teb->Tib.StackBase = wrapper_arg.stackbase; teb->Tib.StackBase = wrapper_arg.stackbase;
@ -676,8 +673,9 @@ thread_wrapper (PVOID arg)
: : [WRAPPER_ARG] "r" (&wrapper_arg), : : [WRAPPER_ARG] "r" (&wrapper_arg),
[CYGTLS] "i" (CYGTLS_PADSIZE)); [CYGTLS] "i" (CYGTLS_PADSIZE));
#endif #endif
/* Never return from here. */ /* pthread::thread_init_wrapper calls pthread::exit, which
ExitThread (0); in turn calls ExitThread, so we should never arrive here. */
api_fatal ("Dumb thinko in pthread handling. Whip the developer.");
} }
#ifdef __x86_64__ #ifdef __x86_64__
@ -751,10 +749,10 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
PVOID real_stackaddr = NULL; PVOID real_stackaddr = NULL;
ULONG real_stacksize = 0; ULONG real_stacksize = 0;
ULONG real_guardsize = 0; ULONG real_guardsize = 0;
thread_wrapper_arg *wrapper_arg; pthread_wrapper_arg *wrapper_arg;
HANDLE thread = NULL; HANDLE thread = NULL;
wrapper_arg = (thread_wrapper_arg *) ccalloc (HEAP_STR, 1, wrapper_arg = (pthread_wrapper_arg *) ccalloc (HEAP_STR, 1,
sizeof *wrapper_arg); sizeof *wrapper_arg);
if (!wrapper_arg) if (!wrapper_arg)
{ {
@ -846,7 +844,7 @@ CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, PVOID thread_arg,
reserve a 256K stack, not 64K, otherwise the thread creation might reserve a 256K stack, not 64K, otherwise the thread creation might
crash the process due to a stack overflow. */ crash the process due to a stack overflow. */
thread = CreateThread (&sec_none_nih, 4 * PTHREAD_STACK_MIN, thread = CreateThread (&sec_none_nih, 4 * PTHREAD_STACK_MIN,
thread_wrapper, wrapper_arg, pthread_wrapper, wrapper_arg,
creation_flags | STACK_SIZE_PARAM_IS_A_RESERVATION, creation_flags | STACK_SIZE_PARAM_IS_A_RESERVATION,
thread_id); thread_id);

View File

@ -66,6 +66,7 @@ ssize_t __reg3 check_iovec (const struct iovec *, int, bool);
#define check_iovec_for_read(a, b) check_iovec ((a), (b), false) #define check_iovec_for_read(a, b) check_iovec ((a), (b), false)
#define check_iovec_for_write(a, b) check_iovec ((a), (b), true) #define check_iovec_for_write(a, b) check_iovec ((a), (b), true)
extern "C" DWORD WINAPI pthread_wrapper (PVOID arg);
extern "C" HANDLE WINAPI CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, extern "C" HANDLE WINAPI CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func,
PVOID thread_arg, PVOID stackaddr, PVOID thread_arg, PVOID stackaddr,
ULONG stacksize, ULONG guardsize, ULONG stacksize, ULONG guardsize,

View File

@ -543,11 +543,13 @@ pthread::exit (void *value_ptr)
{ {
if (is_main_tls) if (is_main_tls)
{ {
/* FIXME: Needs locking. */
_cygtls *dummy = (_cygtls *) malloc (sizeof (_cygtls)); _cygtls *dummy = (_cygtls *) malloc (sizeof (_cygtls));
*dummy = *_main_tls; *dummy = *_main_tls;
_main_tls = dummy; _main_tls = dummy;
_main_tls->initialized = false; _main_tls->initialized = 0;
} }
cygtls->remove (INFINITE);
ExitThread (0); ExitThread (0);
} }
} }