mirror of
https://github.com/github/codeql.git
synced 2025-12-20 18:56:32 +01:00
Modifications to the query to address false positives.
This commit is contained in:
@@ -13,23 +13,87 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
class WideCharPointerType extends PointerType {
|
||||
WideCharPointerType() { this.getBaseType() instanceof WideCharType }
|
||||
}
|
||||
|
||||
/**
|
||||
* Recurse through types to find any intermediate type or final type
|
||||
* that suggests the type is unlikely to be a string.
|
||||
* Specifically looking for any unsigned character, or datatype with name containing "byte"
|
||||
* or datatype uint8_t.
|
||||
*/
|
||||
predicate hasIntermediateType(Type cur, Type targ) {
|
||||
cur = targ
|
||||
or
|
||||
hasIntermediateType(cur.(DerivedType).getBaseType(), targ)
|
||||
or
|
||||
hasIntermediateType(cur.(TypedefType).getBaseType(), targ)
|
||||
}
|
||||
|
||||
/**
|
||||
* A type that may also be `CharPointerType`, but that are likely used as arbitrary buffers.
|
||||
*/
|
||||
class UnlikelyToBeAStringType extends Type {
|
||||
UnlikelyToBeAStringType() {
|
||||
this.(PointerType).getBaseType().(CharType).isUnsigned() or
|
||||
this.(PointerType).getBaseType().getName().toLowerCase().matches("%byte") or
|
||||
this.getName().toLowerCase().matches("%byte") or
|
||||
this.(PointerType).getBaseType().hasName("uint8_t")
|
||||
exists(Type targ |
|
||||
targ.(CharType).isUnsigned() or
|
||||
targ.getName().toLowerCase().matches(["uint8_t", "%byte%"])
|
||||
|
|
||||
hasIntermediateType(this, targ)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Types that can be wide depending on the UNICODE macro
|
||||
// see https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
class UnicodeMacroDependentWidthType extends Type {
|
||||
UnicodeMacroDependentWidthType() {
|
||||
exists(Type targ |
|
||||
targ.getName() in [
|
||||
"LPCTSTR",
|
||||
"LPTSTR",
|
||||
"PCTSTR",
|
||||
"PTSTR",
|
||||
"TBYTE",
|
||||
"TCHAR"
|
||||
]
|
||||
|
|
||||
hasIntermediateType(this, targ)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class UnicodeMacro extends Macro {
|
||||
UnicodeMacro() { this.getName().toLowerCase().matches("%unicode%") }
|
||||
}
|
||||
|
||||
class UnicodeMacroInvocation extends MacroInvocation {
|
||||
UnicodeMacroInvocation() { this.getMacro() instanceof UnicodeMacro }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds when a expression whose type is UnicodeMacroDependentWidthType and
|
||||
* is observed to be guarded by a check involving a bitwise-and operation
|
||||
* with a UnicodeMacroInvocation.
|
||||
* Such expressions are assumed to be checked dynamically, i.e.,
|
||||
* the flag would indicate if UNICODE typing is set correctly to allow
|
||||
* or disallow a widening cast.
|
||||
*/
|
||||
predicate isLikelyDynamicChecked(Expr e, GuardCondition gc) {
|
||||
e.getType() instanceof UnicodeMacroDependentWidthType and
|
||||
exists(BitwiseAndExpr bai, UnicodeMacroInvocation umi | bai.getAnOperand() = umi.getExpr() |
|
||||
// bai == 0 is false when reaching `e.getBasicBlock()`.
|
||||
// That is, bai != 0 when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, 0, e.getBasicBlock(), false)
|
||||
or
|
||||
// bai == k and k != 0 is true when reaching `e.getBasicBlock()`.
|
||||
gc.ensuresEq(bai, any(int k | k != 0), e.getBasicBlock(), true)
|
||||
)
|
||||
}
|
||||
|
||||
from Expr e1, Cast e2
|
||||
where
|
||||
e2 = e1.getConversion() and
|
||||
@@ -42,7 +106,11 @@ where
|
||||
not e1.getType() instanceof UnlikelyToBeAStringType and
|
||||
// Avoid castings from 'new' expressions as typically these will be safe
|
||||
// Example: `__Type* ret = reinterpret_cast<__Type*>(New(m_pmo) char[num * sizeof(__Type)]);`
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1)
|
||||
not exists(NewOrNewArrayExpr newExpr | newExpr.getAChild*() = e1) and
|
||||
// Avoid cases where the cast is guarded by a check to determine if
|
||||
// unicode encoding is enabled in such a way to disallow the dangerous cast
|
||||
// at runtime.
|
||||
not isLikelyDynamicChecked(e1, _)
|
||||
select e1,
|
||||
"Conversion from " + e1.getType().toString() + " to " + e2.getType().toString() +
|
||||
". Use of invalid string can lead to undefined behavior."
|
||||
|
||||
Reference in New Issue
Block a user