Skip to content

Commit 48c99fb

Browse files
Setting a SECURITY_DESCRIPTOR’s DACL to NULL
Closing the gap between Semmle & PreFAST This rule is equivalent to C6248
1 parent 6266d8b commit 48c99fb

File tree

7 files changed

+202
-0
lines changed

7 files changed

+202
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@
88
# qltest projects and artifacts
99
*/ql/test/**/*.testproj
1010
*/ql/test/**/*.actual
11+
/.vs/slnx.sqlite
12+
/.vs/ql3/v15/Browse.VC.opendb
13+
/.vs/ql3/v15/Browse.VC.db
14+
/.vs/ProjectSettings.json
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
SECURITY_DESCRIPTOR pSD;
2+
SECURITY_ATTRIBUTES SA;
3+
4+
if (!InitializeSecurityDescriptor(&pSD, SECURITY_DESCRIPTOR_REVISION))
5+
{
6+
// error handling
7+
}
8+
if (!SetSecurityDescriptorDacl(&pSD,
9+
TRUE, // bDaclPresent - this value indicates the presence of a DACL in the security descriptor
10+
NULL, // pDacl - the pDacl parameter does not point to a DACL. All access will be allowed
11+
FALSE))
12+
{
13+
// error handling
14+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>This query indicates that a call is setting the <code>SECURITY_DESCRIPTOR</code>'s DACL field to null.</p>
8+
<p>When using <code>SetSecurityDescriptorDacl</code> to set a discretionary access control (DACL), setting the <code>bDaclPresent</code> argument to <code>TRUE</code> indicates the prescence of a DACL in the security description in the argument <code>pDacl</code>.</p>
9+
<p>When the <code>pDacl</code> parameter does not point to a DACL (i.e. it is <code>NULL</code>) and the <code>bDaclPresent</code> flag is <code>TRUE</code>, a <code>NULL DACL</code> is specified.</p>
10+
<p>A <code>NULL DACL</code> grants full access to any user who requests it; normal security checking is not performed with respect to the object.</p>
11+
</overview>
12+
13+
<recommendation>
14+
<p>You should not use a <code>NULL DACL</code> with an object because any user can change the DACL and owner of the security descriptor.</p>
15+
</recommendation>
16+
17+
<example>
18+
<p>In the following example, the call to <code>SetSecurityDescriptorDacl</code> is setting an unsafe DACL (<code>NULL DACL</code>) to the security descriptor.</p>
19+
<sample src="UnsafeDaclSecurityDescriptor.cpp" />
20+
21+
<p>To fix this issue, <code>pDacl</code> argument should be a pointer to an <code>ACL</code> structure that specifies the DACL for the security descriptor.</p>
22+
</example>
23+
24+
<references>
25+
<li><a href="https://docs.microsoft.com/en-us/windows/desktop/api/securitybaseapi/nf-securitybaseapi-setsecuritydescriptordacl">SetSecurityDescriptorDacl function (Microsoft documentation).</a>
26+
</li>
27+
</references>
28+
29+
</qhelp>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* @name Setting a SECURITY_DESCRIPTOR’s DACL to NULL
3+
* @description Setting a SECURITY_DESCRIPTOR’s DACL to NULL will result in an unprotected object.
4+
* If the DACL that belongs to the security descriptor of an object is set to NULL, a null DACL is created.
5+
* A null DACL grants full access to any user who requests it;
6+
* normal security checking is not performed with respect to the object.
7+
* @id cpp/unsafe-dacl-security-descriptor
8+
* @kind problem
9+
* @problem.severity error
10+
* @precision high
11+
* @tags security
12+
* external/cwe/cwe-732
13+
* external/microsoft/C6248
14+
*/
15+
import cpp
16+
import semmle.code.cpp.dataflow.DataFlow
17+
18+
/**
19+
* A function call to SetSecurityDescriptorDacl to set the ACL, specified by (2nd argument) bDaclPresent = TRUE
20+
*/
21+
class SetSecurityDescriptorDaclFunctionCall extends FunctionCall {
22+
SetSecurityDescriptorDaclFunctionCall() {
23+
this.getTarget().hasGlobalName("SetSecurityDescriptorDacl")
24+
and this.getArgument(1).getValue().toInt() != 0
25+
}
26+
}
27+
28+
/**
29+
* Dataflow that detects a call to SetSecurityDescriptorDacl with a NULL DACL as the pDacl argument
30+
*/
31+
class SetSecurityDescriptorDaclFunctionConfiguration extends DataFlow::Configuration {
32+
SetSecurityDescriptorDaclFunctionConfiguration() {
33+
this = "SetSecurityDescriptorDaclFunctionConfiguration"
34+
}
35+
36+
override predicate isSource(DataFlow::Node source) {
37+
exists( NullValue nullExpr |
38+
source.asExpr() = nullExpr
39+
)
40+
}
41+
42+
override predicate isSink(DataFlow::Node sink) {
43+
exists( SetSecurityDescriptorDaclFunctionCall call, VariableAccess val |
44+
val = sink.asExpr() |
45+
val = call.getArgument(2)
46+
)
47+
}
48+
}
49+
50+
from SetSecurityDescriptorDaclFunctionCall call, string message
51+
where exists( NullValue nullExpr |
52+
message = "Setting a SECURITY_DESCRIPTOR’s DACL to NULL will result in an unprotected object." |
53+
call.getArgument(1).getValue().toInt() != 0
54+
and call.getArgument(2) = nullExpr
55+
) or exists( Expr constassign, VariableAccess var,
56+
SetSecurityDescriptorDaclFunctionConfiguration config |
57+
message = "Setting a SECURITY_DESCRIPTOR’s DACL using variable " + var + " that is set to NULL will result in an unprotected object." |
58+
var = call.getArgument(2)
59+
and config.hasFlow(DataFlow::exprNode(constassign), DataFlow::exprNode(var))
60+
)
61+
select call, message
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
typedef unsigned long DWORD;
2+
typedef unsigned long ULONG;
3+
typedef unsigned char BYTE;
4+
typedef unsigned short WORD;
5+
typedef int BOOL;
6+
typedef void *PVOID;
7+
#define TRUE 1
8+
#define FALSE 0
9+
#define ERROR_SUCCESS 0L
10+
#define NULL 0
11+
12+
typedef PVOID PSECURITY_DESCRIPTOR;
13+
14+
typedef struct _ACL {
15+
BYTE AclRevision;
16+
BYTE Sbz1;
17+
WORD AclSize;
18+
WORD AceCount;
19+
WORD Sbz2;
20+
} ACL;
21+
typedef ACL *PACL;
22+
23+
typedef enum _ACCESS_MODE
24+
{
25+
NOT_USED_ACCESS = 0,
26+
GRANT_ACCESS,
27+
SET_ACCESS,
28+
DENY_ACCESS,
29+
REVOKE_ACCESS,
30+
SET_AUDIT_SUCCESS,
31+
SET_AUDIT_FAILURE
32+
} ACCESS_MODE;
33+
34+
typedef int TRUSTEE_W;
35+
36+
typedef struct _EXPLICIT_ACCESS_W
37+
{
38+
DWORD grfAccessPermissions;
39+
ACCESS_MODE grfAccessMode;
40+
DWORD grfInheritance;
41+
TRUSTEE_W Trustee;
42+
} EXPLICIT_ACCESS_W, *PEXPLICIT_ACCESS_W, EXPLICIT_ACCESSW, *PEXPLICIT_ACCESSW;
43+
44+
BOOL
45+
SetSecurityDescriptorDacl(
46+
PSECURITY_DESCRIPTOR pSecurityDescriptor,
47+
BOOL bDaclPresent,
48+
PACL pDacl,
49+
BOOL bDaclDefaulted
50+
) {
51+
return TRUE;
52+
}
53+
54+
DWORD SetEntriesInAcl(
55+
ULONG cCountOfExplicitEntries,
56+
PEXPLICIT_ACCESS_W pListOfExplicitEntries,
57+
PACL OldAcl,
58+
PACL *NewAcl
59+
)
60+
{
61+
*NewAcl = (PACL)0xFFFFFF;
62+
return ERROR_SUCCESS;
63+
}
64+
65+
void Test()
66+
{
67+
PSECURITY_DESCRIPTOR pSecurityDescriptor;
68+
BOOL b;
69+
b = SetSecurityDescriptorDacl(pSecurityDescriptor,
70+
TRUE, // Dacl Present
71+
NULL, // NULL pointer to DACL == BUG
72+
FALSE);
73+
74+
PACL pDacl = NULL;
75+
b = SetSecurityDescriptorDacl(pSecurityDescriptor,
76+
TRUE, // Dacl Present
77+
pDacl, // NULL pointer to DACL == BUG
78+
FALSE);
79+
80+
SetEntriesInAcl(0, NULL, NULL, &pDacl);
81+
b = SetSecurityDescriptorDacl(pSecurityDescriptor,
82+
TRUE, // Dacl Present
83+
pDacl, // Should have been set by SetEntriesInAcl ==> should not be flagged
84+
FALSE);
85+
86+
b = SetSecurityDescriptorDacl(pSecurityDescriptor,
87+
FALSE, // Dacl is not Present
88+
NULL, // DACL is going to be removed from security descriptor. Default/inherited access ==> should not be flagged
89+
FALSE);
90+
91+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| UnsafeDaclSecurityDescriptor.cpp:69:6:69:30 | call to SetSecurityDescriptorDacl | Setting a SECURITY_DESCRIPTOR\u2019s DACL to NULL will result in an unprotected object. |
2+
| UnsafeDaclSecurityDescriptor.cpp:75:6:75:30 | call to SetSecurityDescriptorDacl | Setting a SECURITY_DESCRIPTOR\u2019s DACL using variable pDacl that is set to NULL will result in an unprotected object. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-732/UnsafeDaclSecurityDescriptor.ql

0 commit comments

Comments
 (0)