Skip to content

Commit 3a2b007

Browse files
committed
Merge remote-tracking branch 'upstream/main' into next
2 parents dfff976 + 6ee9202 commit 3a2b007

File tree

58 files changed

+1072
-318
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1072
-318
lines changed

c/cert/src/codeql-pack.lock.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
lockVersion: 1.0.0
33
dependencies:
44
codeql/cpp-all:
5-
version: 2.1.1
5+
version: 4.0.3
66
codeql/dataflow:
7-
version: 1.1.6
7+
version: 2.0.3
88
codeql/mad:
9-
version: 1.0.12
9+
version: 1.0.19
1010
codeql/rangeanalysis:
11-
version: 1.0.12
11+
version: 1.0.19
1212
codeql/ssa:
13-
version: 1.0.12
13+
version: 1.0.19
1414
codeql/tutorial:
15-
version: 1.0.12
15+
version: 1.0.19
1616
codeql/typeflow:
17-
version: 1.0.12
17+
version: 1.0.19
1818
codeql/typetracking:
19-
version: 1.0.12
19+
version: 2.0.3
2020
codeql/util:
21-
version: 1.0.12
21+
version: 2.0.6
2222
codeql/xml:
23-
version: 1.0.12
23+
version: 1.0.19
2424
compiled: false

c/cert/src/qlpack.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
name: codeql/cert-c-coding-standards
2-
version: 2.48.0-dev
2+
version: 2.49.0-dev
33
description: CERT C 2016
44
suites: codeql-suites
55
license: MIT
66
default-suite-file: codeql-suites/cert-c-default.qls
77
dependencies:
88
codeql/common-c-coding-standards: '*'
9-
codeql/cpp-all: 2.1.1
9+
codeql/cpp-all: 4.0.3

c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,32 @@ import codingstandards.c.cert
2424
import codingstandards.cpp.types.Compatible
2525
import ExternalIdentifiers
2626

27-
predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
27+
predicate interestedInFunctions(
28+
FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, ExternalIdentifiers d
29+
) {
2830
not f1 = f2 and
29-
f1.getDeclaration() = f2.getDeclaration() and
30-
f1.getName() = f2.getName()
31+
d = f1.getDeclaration() and
32+
d = f2.getDeclaration()
33+
}
34+
35+
predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) {
36+
interestedInFunctions(f1, f2, _)
3137
}
3238

39+
module FuncDeclEquiv =
40+
FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>;
41+
3342
from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2
3443
where
3544
not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and
3645
not isExcluded(f2, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and
37-
not f1 = f2 and
38-
f1.getDeclaration() = d and
39-
f2.getDeclaration() = d and
40-
f1.getName() = f2.getName() and
46+
interestedInFunctions(f1, f2, d) and
4147
(
4248
//return type check
43-
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>::equalReturnTypes(f1,
44-
f2)
49+
not FuncDeclEquiv::equalReturnTypes(f1, f2)
4550
or
4651
//parameter type check
47-
not FunctionDeclarationTypeEquivalence<TypesCompatibleConfig, interestedInFunctions/2>::equalParameterTypes(f1,
48-
f2)
52+
not FuncDeclEquiv::equalParameterTypes(f1, f2)
4953
) and
5054
// Apply ordering on start line, trying to avoid the optimiser applying this join too early
5155
// in the pipeline
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# EXP16-C: Do not compare function pointers to constant values
2+
3+
This query implements the CERT-C rule EXP16-C:
4+
5+
> Do not compare function pointers to constant values
6+
7+
8+
## Description
9+
10+
Comparing a function pointer to a value that is not a null function pointer of the same type will be diagnosed because it typically indicates programmer error and can result in [unexpected behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). Implicit comparisons will be diagnosed, as well.
11+
12+
## Noncompliant Code Example
13+
14+
In this noncompliant code example, the addresses of the POSIX functions `getuid` and `geteuid` are compared for equality to 0. Because no function address shall be null, the first subexpression will always evaluate to false (0), and the second subexpression always to true (nonzero). Consequently, the entire expression will always evaluate to true, leading to a potential security vulnerability.
15+
16+
```cpp
17+
/* First the options that are allowed only for root */
18+
if (getuid == 0 || geteuid != 0) {
19+
/* ... */
20+
}
21+
22+
```
23+
24+
## Noncompliant Code Example
25+
26+
In this noncompliant code example, the function pointers `getuid` and `geteuid` are compared to 0. This example is from an actual [vulnerability](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) ([VU\#837857](http://www.kb.cert.org/vuls/id/837857)) discovered in some versions of the X Window System server. The vulnerability exists because the programmer neglected to provide the open and close parentheses following the `geteuid()` function identifier. As a result, the `geteuid` token returns the address of the function, which is never equal to 0. Consequently, the `or` condition of this `if` statement is always true, and access is provided to the protected block for all users. Many compilers issue a warning noting such pointless expressions. Therefore, this coding error is normally detected by adherence to [MSC00-C. Compile cleanly at high warning levels](https://wiki.sei.cmu.edu/confluence/display/c/MSC00-C.+Compile+cleanly+at+high+warning+levels).
27+
28+
```cpp
29+
/* First the options that are allowed only for root */
30+
if (getuid() == 0 || geteuid != 0) {
31+
/* ... */
32+
}
33+
34+
```
35+
36+
## Compliant Solution
37+
38+
The solution is to provide the open and close parentheses following the `geteuid` token so that the function is properly invoked:
39+
40+
```cpp
41+
/* First the options that are allowed only for root */
42+
if (getuid() == 0 || geteuid() != 0) {
43+
/* ... */
44+
}
45+
46+
```
47+
48+
## Compliant Solution
49+
50+
A function pointer can be compared to a null function pointer of the same type:
51+
52+
```cpp
53+
/* First the options that are allowed only for root */
54+
if (getuid == (uid_t(*)(void))0 || geteuid != (uid_t(*)(void))0) {
55+
/* ... */
56+
}
57+
58+
```
59+
This code should not be diagnosed by an analyzer.
60+
61+
## Noncompliant Code Example
62+
63+
In this noncompliant code example, the function pointer `do_xyz` is implicitly compared unequal to 0:
64+
65+
```cpp
66+
int do_xyz(void);
67+
68+
int f(void) {
69+
/* ... */
70+
if (do_xyz) {
71+
return -1; /* Indicate failure */
72+
}
73+
/* ... */
74+
return 0;
75+
}
76+
77+
```
78+
79+
## Compliant Solution
80+
81+
In this compliant solution, the function `do_xyz()` is invoked and the return value is compared to 0:
82+
83+
```cpp
84+
int do_xyz(void);
85+
86+
int f(void) {
87+
/* ... */
88+
if (do_xyz()) {
89+
return -1; /* Indicate failure */
90+
}
91+
/* ... */
92+
return 0;
93+
}
94+
95+
```
96+
97+
## Risk Assessment
98+
99+
Errors of omission can result in unintended program flow.
100+
101+
<table> <tbody> <tr> <th> Recommendation </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> EXP16-C </td> <td> Low </td> <td> Likely </td> <td> Medium </td> <td> <strong>P6</strong> </td> <td> <strong>L2</strong> </td> </tr> </tbody> </table>
102+
103+
104+
## Automated Detection
105+
106+
<table> <tbody> <tr> <th> Tool </th> <th> Version </th> <th> Checker </th> <th> Description </th> </tr> <tr> <td> <a> Astrée </a> </td> <td> 24.04 </td> <td> <strong>function-name-constant-comparison</strong> </td> <td> Partially checked </td> </tr> <tr> <td> <a> Coverity </a> </td> <td> 2017.07 </td> <td> <strong>BAD_COMPARE</strong> </td> <td> Can detect the specific instance where the address of a function is compared against 0, such as in the case of <code>geteuid</code> versus <code>getuid()</code> in the implementation-specific details </td> </tr> <tr> <td> <a> GCC </a> </td> <td> 4.3.5 </td> <td> </td> <td> Can detect violations of this recommendation when the <code>-Wall</code> flag is used </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2024.4 </td> <td> <strong>C0428, C3004, C3344</strong> </td> <td> </td> </tr> <tr> <td> <a> Klocwork </a> </td> <td> 2024.4 </td> <td> <strong>CWARN.NULLCHECK.FUNCNAMECWARN.FUNCADDR</strong> </td> <td> </td> </tr> <tr> <td> <a> LDRA tool suite </a> </td> <td> 9.7.1 </td> <td> <strong>99 S</strong> </td> <td> Partially implemented </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2024.2 </td> <td> <strong>CERT_C-EXP16-a</strong> </td> <td> Function address should not be compared to zero </td> </tr> <tr> <td> <a> PC-lint Plus </a> </td> <td> 1.4 </td> <td> <strong>2440, 2441</strong> </td> <td> Partially supported: reports address of function, array, or variable directly or indirectly compared to null </td> </tr> <tr> <td> <a> PVS-Studio </a> </td> <td> 7.35 </td> <td> <strong><a>V516</a>, <a>V1058</a></strong> </td> <td> </td> </tr> <tr> <td> <a> RuleChecker </a> </td> <td> 24.04 </td> <td> <strong>function-name-constant-comparison</strong> </td> <td> Partially checked </td> </tr> </tbody> </table>
107+
108+
109+
## Related Vulnerabilities
110+
111+
Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+EXP16-C).
112+
113+
## Related Guidelines
114+
115+
<table> <tbody> <tr> <td> <a> SEI CERT C++ Coding Standard </a> </td> <td> <a> VOID EXP16-CPP. Avoid conversions using void pointers </a> </td> </tr> <tr> <td> <a> ISO/IEC TR 24772:2013 </a> </td> <td> Likely incorrect expressions \[KOA\] </td> </tr> <tr> <td> <a> ISO/IEC TS 17961 </a> </td> <td> Comparing function addresses to zero \[funcaddr\] </td> </tr> <tr> <td> <a> MITRE CWE </a> </td> <td> <a> CWE-480 </a> , Use of incorrect operator <a> CWE-482 </a> , Comparing instead of assigning </td> </tr> </tbody> </table>
116+
117+
118+
## Bibliography
119+
120+
<table> <tbody> <tr> <td> \[ <a> Hatton 1995 </a> \] </td> <td> Section 2.7.2, "Errors of Omission and Addition" </td> </tr> </tbody> </table>
121+
122+
123+
## Implementation notes
124+
125+
None
126+
127+
## References
128+
129+
* CERT-C: [EXP16-C: Do not compare function pointers to constant values](https://wiki.sei.cmu.edu/confluence/display/c)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* @id c/cert/do-not-compare-function-pointers-to-constant-values
3+
* @name EXP16-C: Do not compare function pointers to constant values
4+
* @description Comparing function pointers to a constant value is not reliable and likely indicates
5+
* a programmer error.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/cert/id/exp16-c
10+
* correctness
11+
* external/cert/severity/low
12+
* external/cert/likelihood/likely
13+
* external/cert/remediation-cost/medium
14+
* external/cert/priority/p6
15+
* external/cert/level/l2
16+
* external/cert/obligation/recommendation
17+
*/
18+
19+
import cpp
20+
import semmle.code.cpp.controlflow.IRGuards
21+
import codingstandards.c.cert
22+
import codingstandards.cpp.types.FunctionType
23+
import codingstandards.cpp.exprs.FunctionExprs
24+
import codingstandards.cpp.exprs.Guards
25+
26+
final class FinalElement = Element;
27+
28+
abstract class EffectivelyComparison extends FinalElement {
29+
abstract string getExplanation();
30+
31+
abstract FunctionExpr getFunctionExpr();
32+
}
33+
34+
final class FinalComparisonOperation = ComparisonOperation;
35+
36+
class ExplicitComparison extends EffectivelyComparison, FinalComparisonOperation {
37+
Expr constantExpr;
38+
FunctionExpr funcExpr;
39+
40+
ExplicitComparison() {
41+
funcExpr = getAnOperand() and
42+
constantExpr = getAnOperand() and
43+
exists(constantExpr.getValue()) and
44+
not funcExpr = constantExpr and
45+
not constantExpr.getExplicitlyConverted().getUnderlyingType() =
46+
funcExpr.getExplicitlyConverted().getUnderlyingType()
47+
}
48+
49+
override string getExplanation() { result = "$@ compared to constant value." }
50+
51+
override FunctionExpr getFunctionExpr() { result = funcExpr }
52+
}
53+
54+
class ImplicitComparison extends EffectivelyComparison, GuardCondition {
55+
ImplicitComparison() {
56+
this instanceof FunctionExpr and
57+
not getParent() instanceof ComparisonOperation
58+
}
59+
60+
override string getExplanation() { result = "$@ undergoes implicit constant comparison." }
61+
62+
override FunctionExpr getFunctionExpr() { result = this }
63+
}
64+
65+
from EffectivelyComparison comparison, FunctionExpr funcExpr, Element function, string funcName
66+
where
67+
not isExcluded(comparison,
68+
Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and
69+
funcExpr = comparison.getFunctionExpr() and
70+
not exists(NullFunctionCallGuard nullGuard | nullGuard.getFunctionExpr() = funcExpr) and
71+
function = funcExpr.getFunction() and
72+
funcName = funcExpr.describe()
73+
select comparison, comparison.getExplanation(), function, funcName

c/cert/test/codeql-pack.lock.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
lockVersion: 1.0.0
33
dependencies:
44
codeql/cpp-all:
5-
version: 2.1.1
5+
version: 4.0.3
66
codeql/dataflow:
7-
version: 1.1.6
7+
version: 2.0.3
88
codeql/mad:
9-
version: 1.0.12
9+
version: 1.0.19
1010
codeql/rangeanalysis:
11-
version: 1.0.12
11+
version: 1.0.19
1212
codeql/ssa:
13-
version: 1.0.12
13+
version: 1.0.19
1414
codeql/tutorial:
15-
version: 1.0.12
15+
version: 1.0.19
1616
codeql/typeflow:
17-
version: 1.0.12
17+
version: 1.0.19
1818
codeql/typetracking:
19-
version: 1.0.12
19+
version: 2.0.3
2020
codeql/util:
21-
version: 1.0.12
21+
version: 2.0.6
2222
codeql/xml:
23-
version: 1.0.12
23+
version: 1.0.19
2424
compiled: false

c/cert/test/qlpack.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: codeql/cert-c-coding-standards-tests
2-
version: 2.48.0-dev
2+
version: 2.49.0-dev
33
extractor: cpp
44
license: MIT
55
dependencies:
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
| test.c:17:7:17:13 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 |
2+
| test.c:20:7:20:12 | ... > ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 |
3+
| test.c:29:7:29:13 | ... == ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 |
4+
| test.c:32:7:32:16 | ... == ... | $@ compared to constant value. | test.c:5:7:5:8 | g2 | Function pointer variable g2 |
5+
| test.c:35:7:35:15 | ... != ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 |
6+
| test.c:38:7:38:8 | f1 | $@ undergoes implicit constant comparison. | test.c:3:5:3:6 | f1 | Address of function f1 |
7+
| test.c:41:7:41:8 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 |
8+
| test.c:68:7:68:27 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 |
9+
| test.c:71:7:71:18 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 |
10+
| test.c:74:7:76:14 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 |
11+
| test.c:83:3:83:9 | ... == ... | $@ compared to constant value. | test.c:82:10:82:11 | l1 | Function pointer variable l1 |
12+
| test.c:84:3:84:12 | ... == ... | $@ compared to constant value. | test.c:82:10:82:11 | l1 | Function pointer variable l1 |
13+
| test.c:91:3:91:4 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 |
14+
| test.c:96:7:96:18 | ... == ... | $@ compared to constant value. | test.c:9:9:9:10 | fp | Function pointer variable fp |
15+
| test.c:102:7:102:22 | ... == ... | $@ compared to constant value. | test.c:14:11:14:21 | get_handler | Address of function get_handler |
16+
| test.c:105:7:105:24 | ... == ... | $@ compared to constant value. | test.c:105:7:105:17 | call to get_handler | Expression with function pointer type |
17+
| test.c:121:7:121:13 | ... != ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 |
18+
| test.c:133:7:133:13 | ... != ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 |
19+
| test.c:139:7:139:13 | ... == ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 |
20+
| test.c:149:8:149:9 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql

0 commit comments

Comments
 (0)