Fix deadlock when loading libtorrent Dll

Definition of `bool file::has_manage_volume_privs` involves a call to
`get_manage_volume_privs()`, causing restricted tasks to be performed
from within `DllMain` function. They introduce possibility that client
application deadlocks or crashes.

You should never perform the following tasks from within DllMain:

* Call `LoadLibrary` or `LoadLibraryEx` (either directly or indirectly).
  This can cause a deadlock or a crash.

* Call the registry functions. These functions are implemented in
  'Advapi32.dll'. If not initialized before your DLL, it can access
  uninitialized memory and cause the process to crash.
This commit is contained in:
d_komarov 2018-07-06 15:14:38 +03:00 committed by Arvid Norberg
parent 3249b70cbd
commit 1c86e94de6
2 changed files with 20 additions and 33 deletions

View File

@ -341,10 +341,6 @@ namespace libtorrent
#endif #endif
int m_open_mode; int m_open_mode;
#if defined TORRENT_WINDOWS
static bool has_manage_volume_privs;
#endif
#ifdef TORRENT_DEBUG_FILE_LEAKS #ifdef TORRENT_DEBUG_FILE_LEAKS
std::string m_file_path; std::string m_file_path;
#endif #endif

View File

@ -79,6 +79,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdio.h> #include <stdio.h>
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include <boost/scope_exit.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/static_assert.hpp> #include <boost/static_assert.hpp>
@ -1314,9 +1315,6 @@ namespace libtorrent
#ifdef TORRENT_WINDOWS #ifdef TORRENT_WINDOWS
bool get_manage_volume_privs(); bool get_manage_volume_privs();
// this needs to be run before CreateFile
bool file::has_manage_volume_privs = get_manage_volume_privs();
#endif #endif
file::file() file::file()
@ -1956,10 +1954,15 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
static LookupPrivilegeValue_t pLookupPrivilegeValue = NULL; static LookupPrivilegeValue_t pLookupPrivilegeValue = NULL;
static AdjustTokenPrivileges_t pAdjustTokenPrivileges = NULL; static AdjustTokenPrivileges_t pAdjustTokenPrivileges = NULL;
static bool failed_advapi = false; static bool failed_advapi = false;
HMODULE advapi = NULL;
BOOST_SCOPE_EXIT(&advapi) {
if (advapi) FreeLibrary(advapi);
} BOOST_SCOPE_EXIT_END
if (pOpenProcessToken == NULL && !failed_advapi) if (pOpenProcessToken == NULL && !failed_advapi)
{ {
HMODULE advapi = LoadLibraryA("advapi32"); advapi = LoadLibraryA("advapi32");
if (advapi == NULL) if (advapi == NULL)
{ {
failed_advapi = true; failed_advapi = true;
@ -1977,16 +1980,19 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
} }
} }
HANDLE token; HANDLE token = NULL;
if (!pOpenProcessToken(GetCurrentProcess() if (!pOpenProcessToken(GetCurrentProcess()
, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) , TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
return false; return false;
BOOST_SCOPE_EXIT(&token) {
CloseHandle(token);
} BOOST_SCOPE_EXIT_END
TOKEN_PRIVILEGES privs; TOKEN_PRIVILEGES privs;
if (!pLookupPrivilegeValue(NULL, "SeManageVolumePrivilege" if (!pLookupPrivilegeValue(NULL, "SeManageVolumePrivilege"
, &privs.Privileges[0].Luid)) , &privs.Privileges[0].Luid))
{ {
CloseHandle(token);
return false; return false;
} }
@ -1996,38 +2002,23 @@ typedef struct _FILE_ALLOCATED_RANGE_BUFFER {
bool ret = pAdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, NULL) bool ret = pAdjustTokenPrivileges(token, FALSE, &privs, 0, NULL, NULL)
&& GetLastError() == ERROR_SUCCESS; && GetLastError() == ERROR_SUCCESS;
CloseHandle(token);
return ret; return ret;
} }
void set_file_valid_data(HANDLE f, boost::int64_t size) void set_file_valid_data(HANDLE f, boost::int64_t size)
{ {
typedef BOOL (WINAPI *SetFileValidData_t)(HANDLE, LONGLONG); typedef BOOL (WINAPI *SetFileValidData_t)(HANDLE, LONGLONG);
static SetFileValidData_t pSetFileValidData = NULL; static SetFileValidData_t const pSetFileValidData = (SetFileValidData_t)
static bool failed_kernel32 = false; GetProcAddress(GetModuleHandleA("kernel32"), "SetFileValidData");
if (pSetFileValidData == NULL && !failed_kernel32) if (pSetFileValidData == NULL) return;
static bool const has_manage_volume_privs = get_manage_volume_privs();
if (has_manage_volume_privs)
{ {
HMODULE k32 = LoadLibraryA("kernel32"); pSetFileValidData(f, size);
if (k32 == NULL)
{
failed_kernel32 = true;
return;
}
pSetFileValidData = (SetFileValidData_t)GetProcAddress(k32, "SetFileValidData");
if (pSetFileValidData == NULL)
{
failed_kernel32 = true;
return;
}
} }
TORRENT_ASSERT(pSetFileValidData);
// we don't necessarily expect to have enough
// privilege to do this, so ignore errors.
pSetFileValidData(f, size);
} }
#endif #endif