Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
<qhelp>
<overview>
<p>
When using a DLL, it is frequently the case that any static construtors are called from DllMain. There are a number of constraints that apply to calling other functions from DllMain. In particular, it is possible to create memory leaks if the DLL is loaded and unloaded dynamically. SysAllocString is an example of a function that, in this case, could cause a memory leak.
</p>
</overview>
<recommendation>
<p>
The ideal DllMain would be just an empty stub. However, given the complexity of many applications, this is generally too restrictive. A good rule of thumb for DllMain is to postpone as much initialization as possible. Lazy initialization increases robustness of the application because this initialization is not performed while the loader lock is held. Also, lazy initialization enables you to safely use much more of the Windows API.
</p>
</recommendation>
<example>
<p>
DLLMain function
</p>
<sample language="c"> <![CDATA[
BOOL WINAPI DllMain(
HINSTANCE hinstDLL, // handle to DLL module
DWORD fdwReason, // reason for calling function
LPVOID lpvReserved ) // reserved
{
// Perform actions based on the reason for calling.
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
// Initialize once for each new process.
// Return FALSE to fail DLL load.
break;

case DLL_THREAD_ATTACH:
// Do thread-specific initialization.
break;

case DLL_THREAD_DETACH:
// Do thread-specific cleanup.
break;

case DLL_PROCESS_DETACH:

if (lpvReserved != nullptr)
{
break; // do not do cleanup if process termination scenario
}

// Perform any necessary cleanup.
break;
}
return TRUE; // Successful DLL_PROCESS_ATTACH.
}
}]]>

</example>
<semmleNotes>
<p>

</p>
</semmleNotes>
<references>
<li>
<a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28637-calling-function-in-a-global-initializer-is-unsafe">
C28637
</a>
</li>
</references>
</qhelp>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
/**
* @id cpp/drivers/unsafe-call-in-global-init
* @kind problem
* @name TODO
* @description When using a DLL, it is frequently the case that any
* static construtors are called from DllMain.
* There are a number of constraints that apply to calling
* other functions from DllMain. In particular, it is
* possible to create memory leaks if the DLL is loaded
* and unloaded dynamically.
* @platform Desktop
* @feature.area Multiple
* @impact Insecure Coding Practice
* @repro.text
* @owner.email: [email protected]
* @opaqueid CQLD-C28637
* @problem.severity warning
* @precision medium
* @tags correctness
* @scope domainspecific
* @query-version v1
*/

import cpp
import drivers.libraries.DriverIsolation

from Function f, string msg
where
f.getName().matches("DllMain") and
exists(FunctionCall fc |
fc.getEnclosingFunction() = f and
(
fc.getTarget()
.getName()
.matches([
"LoadLibrary", "LoadLibraryEx", "GetStringTypeA", "GetStringTypeEx", "GetStringTypeW",
"CoInitializeEx", "CreateProcess", "ExitThread", "CreateThread", "ShGetFolderPathW"
]) or
fc instanceof RegistryIsolationFunctionCall
) and
msg = "Unsafe call in DllMain."
)
or
exists(Initializer i |
f.getName().matches("DllMain") and
i.getExpr().getEnclosingFunction() = f and
not i.getDeclaration().isStatic() and
i.getExpr().toString().toLowerCase().matches("null") and
msg = "Potential unsafe initialization in DllMain."
)
select f, msg + " Review Dynamic-Link Library Best Practices."
Loading