mirror of
https://github.com/github/codeql.git
synced 2026-05-20 14:17:11 +02:00
Compare commits
79 Commits
codeql-cli
...
calumgrant
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60076dc8a8 | ||
|
|
d3e469f989 | ||
|
|
5bfd22e60a | ||
|
|
7fa9167ef9 | ||
|
|
f845ac1dd8 | ||
|
|
f183bc9a65 | ||
|
|
28dd2ca83c | ||
|
|
442dad4ff9 | ||
|
|
91f6498e16 | ||
|
|
b4c8390991 | ||
|
|
ac18e7494f | ||
|
|
32ff8dc0f6 | ||
|
|
e0acf262d5 | ||
|
|
9fd95381dc | ||
|
|
a0ef2888c7 | ||
|
|
531e637009 | ||
|
|
ebe9088458 | ||
|
|
9fa1ad9d8d | ||
|
|
f21784db9d | ||
|
|
fb140404b6 | ||
|
|
0f96e79264 | ||
|
|
0b9187d76c | ||
|
|
a9d21e70c2 | ||
|
|
dd55460d7f | ||
|
|
784d07c95b | ||
|
|
f3b52adde6 | ||
|
|
43bc3e5d99 | ||
|
|
93562950bb | ||
|
|
0932a0edb5 | ||
|
|
00de19ce13 | ||
|
|
ab9ab0e22f | ||
|
|
7b071ba91e | ||
|
|
2b74061167 | ||
|
|
19df33fb43 | ||
|
|
35462a4d09 | ||
|
|
fc841023c6 | ||
|
|
6fa18be0cc | ||
|
|
fbb7f0a0c6 | ||
|
|
cf9d773de0 | ||
|
|
a0512a50f2 | ||
|
|
3e5707154a | ||
|
|
6b5974a372 | ||
|
|
d248fbfe57 | ||
|
|
4e59ac4819 | ||
|
|
66777e6282 | ||
|
|
3846be450d | ||
|
|
411f3cd2f5 | ||
|
|
7edb397de1 | ||
|
|
cec503eecd | ||
|
|
4e798b3db4 | ||
|
|
ff328d6c04 | ||
|
|
121f0584e4 | ||
|
|
04ee557b31 | ||
|
|
217bc74278 | ||
|
|
e1c601dc52 | ||
|
|
64f33955b5 | ||
|
|
344dd2dab5 | ||
|
|
2aea356756 | ||
|
|
6a6585e415 | ||
|
|
9504f3611f | ||
|
|
016bda04a5 | ||
|
|
24eb774921 | ||
|
|
bf34860ad0 | ||
|
|
3573ff10c7 | ||
|
|
9c409f1280 | ||
|
|
5548662a74 | ||
|
|
ae34a9c80e | ||
|
|
460de3f7d5 | ||
|
|
4e36008ed9 | ||
|
|
642f9dcbea | ||
|
|
7688f46650 | ||
|
|
9cc614ac2d | ||
|
|
de1b374e0e | ||
|
|
4b95ea0987 | ||
|
|
8277c602ac | ||
|
|
d7e2fbc11d | ||
|
|
9958ad904c | ||
|
|
28288e0d23 | ||
|
|
3b78477406 |
@@ -218,6 +218,7 @@ use_repo(
|
||||
"kotlin-compiler-2.0.0-RC1",
|
||||
"kotlin-compiler-2.0.20-Beta2",
|
||||
"kotlin-compiler-2.1.0-Beta1",
|
||||
"kotlin-compiler-2.1.20-Beta1",
|
||||
"kotlin-compiler-embeddable-1.5.0",
|
||||
"kotlin-compiler-embeddable-1.5.10",
|
||||
"kotlin-compiler-embeddable-1.5.20",
|
||||
@@ -232,6 +233,7 @@ use_repo(
|
||||
"kotlin-compiler-embeddable-2.0.0-RC1",
|
||||
"kotlin-compiler-embeddable-2.0.20-Beta2",
|
||||
"kotlin-compiler-embeddable-2.1.0-Beta1",
|
||||
"kotlin-compiler-embeddable-2.1.20-Beta1",
|
||||
"kotlin-stdlib-1.5.0",
|
||||
"kotlin-stdlib-1.5.10",
|
||||
"kotlin-stdlib-1.5.20",
|
||||
@@ -246,6 +248,7 @@ use_repo(
|
||||
"kotlin-stdlib-2.0.0-RC1",
|
||||
"kotlin-stdlib-2.0.20-Beta2",
|
||||
"kotlin-stdlib-2.1.0-Beta1",
|
||||
"kotlin-stdlib-2.1.20-Beta1",
|
||||
)
|
||||
|
||||
go_sdk = use_extension("@rules_go//go:extensions.bzl", "go_sdk")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-all
|
||||
version: 0.4.1
|
||||
version: 0.4.2-dev
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/actions-queries
|
||||
version: 0.4.1
|
||||
version: 0.4.2-dev
|
||||
library: false
|
||||
warnOnImplicitThis: true
|
||||
groups: [actions, queries]
|
||||
|
||||
2432
cpp/downgrades/59cb96ca699929b63941e81905f9b8de7eed59a6/old.dbscheme
Normal file
2432
cpp/downgrades/59cb96ca699929b63941e81905f9b8de7eed59a6/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
class PreprocessorDirective extends @preprocdirect {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_default {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
bindingset[kind]
|
||||
int getKind(int kind) {
|
||||
if kind = 14
|
||||
then result = 6 // Represent MSFT #import as #include
|
||||
else
|
||||
if kind = 15 or kind = 6
|
||||
then result = 3 // Represent #elifdef and #elifndef as #elif
|
||||
else result = kind
|
||||
}
|
||||
|
||||
from PreprocessorDirective ppd, int kind, Location l
|
||||
where preprocdirects(ppd, kind, l)
|
||||
select ppd, getKind(kind), l
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Support #elifdef, #elifndef and #import
|
||||
compatibility: full
|
||||
preprocdirects.rel: run preprocdirects.qlo
|
||||
5
cpp/ql/lib/change-notes/2024-01-20-elifdef.md
Normal file
5
cpp/ql/lib/change-notes/2024-01-20-elifdef.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* New classes `PreprocessorElifdef` and `PreprocessorElifndef` were introduced, which represents the C23/C++23 `#elifdef` and `#elifndef` preprocessor directives.
|
||||
* A new class `TypeLibraryImport` was introduced, which represents the `#import` preprocessor directive as used by the Microsoft Visual C++ for importing type libraries.
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 3.2.0
|
||||
version: 3.2.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -57,9 +57,9 @@ class IncludeNext extends Include, @ppd_include_next {
|
||||
}
|
||||
|
||||
/**
|
||||
* A `#import` preprocessor directive (used heavily in Objective C, and
|
||||
* supported by GCC as an extension in C). For example the following code
|
||||
* contains one `Import` directive:
|
||||
* An Objective C `#import` preprocessor directive (supported by GCC as
|
||||
* an extension in C). For example the following code contains one `Import`
|
||||
* directive:
|
||||
* ```
|
||||
* #import <header3.h>
|
||||
* ```
|
||||
@@ -67,3 +67,14 @@ class IncludeNext extends Include, @ppd_include_next {
|
||||
class Import extends Include, @ppd_objc_import {
|
||||
override string toString() { result = "#import " + this.getIncludeText() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A Microsoft `#import` preprocessor directive for importing a type library.
|
||||
* For example the following code contains one `TypeLibraryImport` directive:
|
||||
* ```
|
||||
* #import "library.tlb"
|
||||
* ```
|
||||
*/
|
||||
class TypeLibraryImport extends Include, @ppd_ms_import {
|
||||
override string toString() { result = "#import " + this.getIncludeText() }
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ private class TPreprocessorBranchDirective = @ppd_branch or @ppd_else or @ppd_en
|
||||
|
||||
/**
|
||||
* A C/C++ preprocessor branch related directive: `#if`, `#ifdef`,
|
||||
* `#ifndef`, `#elif`, `#else` or `#endif`.
|
||||
* `#ifndef`, `#elif`, `#elifdef`, `#elifndef`, `#else` or `#endif`.
|
||||
*/
|
||||
class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBranchDirective {
|
||||
/**
|
||||
@@ -74,8 +74,8 @@ class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBr
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the next `#elif`, `#else` or `#endif` matching this branching
|
||||
* directive.
|
||||
* Gets the next `#elif`, `#elifdef`, `#elifndef`, `#else` or `#endif` matching
|
||||
* this branching directive.
|
||||
*
|
||||
* For example `somePreprocessorBranchDirective.getIf().getNext()` gets
|
||||
* the second directive in the same construct as
|
||||
@@ -88,8 +88,8 @@ class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBr
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of this branching directive within the matching #if,
|
||||
* #ifdef or #ifndef.
|
||||
* Gets the index of this branching directive within the matching `#if`,
|
||||
* `#ifdef` or `#ifndef`.
|
||||
*/
|
||||
private int getIndexInBranch(PreprocessorBranch branch) {
|
||||
this =
|
||||
@@ -102,8 +102,8 @@ class PreprocessorBranchDirective extends PreprocessorDirective, TPreprocessorBr
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ preprocessor branching directive: `#if`, `#ifdef`, `#ifndef`, or
|
||||
* `#elif`.
|
||||
* A C/C++ preprocessor branching directive: `#if`, `#ifdef`, `#ifndef`,
|
||||
* `#elif`, `#elifdef`, or `#elifndef`.
|
||||
*
|
||||
* A branching directive has a condition and that condition may be evaluated
|
||||
* at compile-time. As a result, the preprocessor will either take the
|
||||
@@ -151,8 +151,8 @@ class PreprocessorBranch extends PreprocessorBranchDirective, @ppd_branch {
|
||||
* #endif
|
||||
* ```
|
||||
* For the related notion of a directive which causes branching (which
|
||||
* includes `#if`, plus also `#ifdef`, `#ifndef`, and `#elif`), see
|
||||
* `PreprocessorBranch`.
|
||||
* includes `#if`, plus also `#ifdef`, `#ifndef`, `#elif`, `#elifdef`,
|
||||
* and `#elifndef`), see `PreprocessorBranch`.
|
||||
*/
|
||||
class PreprocessorIf extends PreprocessorBranch, @ppd_if {
|
||||
override string toString() { result = "#if " + this.getHead() }
|
||||
@@ -222,6 +222,40 @@ class PreprocessorElif extends PreprocessorBranch, @ppd_elif {
|
||||
override string toString() { result = "#elif " + this.getHead() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ preprocessor `#elifdef` directive. For example there is a
|
||||
* `PreprocessorElifdef` on the third line of the following code:
|
||||
* ```
|
||||
* #ifdef MYDEFINE1
|
||||
* // ...
|
||||
* #elifdef MYDEFINE2
|
||||
* // ...
|
||||
* #else
|
||||
* // ...
|
||||
* #endif
|
||||
* ```
|
||||
*/
|
||||
class PreprocessorElifdef extends PreprocessorBranch, @ppd_elifdef {
|
||||
override string toString() { result = "#elifdef " + this.getHead() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ preprocessor `#elifndef` directive. For example there is a
|
||||
* `PreprocessorElifndef` on the third line of the following code:
|
||||
* ```
|
||||
* #ifdef MYDEFINE1
|
||||
* // ...
|
||||
* #elifndef MYDEFINE2
|
||||
* // ...
|
||||
* #else
|
||||
* // ...
|
||||
* #endif
|
||||
* ```
|
||||
*/
|
||||
class PreprocessorElifndef extends PreprocessorBranch, @ppd_elifndef {
|
||||
override string toString() { result = "#elifndef " + this.getHead() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A C/C++ preprocessor `#endif` directive. For example there is a
|
||||
* `PreprocessorEndif` on the third line of the following code:
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/**
|
||||
* This library offers a view of preprocessor branches (`#if`, `#ifdef`,
|
||||
* `#ifndef`, `#elif` and `#else`) as blocks of code between the opening and
|
||||
* closing directives, with navigable parent-child relationships to other
|
||||
* blocks. The main class is `PreprocessorBlock`.
|
||||
* `#ifndef`, `#elif`, `#elifdef`, `#elifndef`, and `#else`) as blocks of
|
||||
* code between the opening and closing directives, with navigable
|
||||
* parent-child relationships to other blocks. The main class is
|
||||
* `PreprocessorBlock`.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
@@ -32,10 +33,10 @@ private int getPreprocIndex(PreprocessorBranchDirective directive) {
|
||||
|
||||
/**
|
||||
* A chunk of code from one preprocessor branch (`#if`, `#ifdef`,
|
||||
* `#ifndef`, `#elif` or `#else`) to the directive that closes it
|
||||
* (`#elif`, `#else` or `#endif`). The `getParent()` method
|
||||
* allows these blocks to be navigated as a tree, with the root
|
||||
* being the entire file.
|
||||
* `#ifndef`, `#elif`, `#elifdef`, `#elifndef`, or `#else`) to the
|
||||
* directive that closes it (`#elif`, `#elifdef`, `#elifndef`, `#else`,
|
||||
* or `#endif`). The `getParent()` method allows these blocks to be
|
||||
* navigated as a tree, with the root being the entire file.
|
||||
*/
|
||||
class PreprocessorBlock extends @element {
|
||||
PreprocessorBlock() {
|
||||
|
||||
@@ -2318,12 +2318,15 @@ case @preprocdirect.kind of
|
||||
| 11 = @ppd_pragma
|
||||
| 12 = @ppd_objc_import
|
||||
| 13 = @ppd_include_next
|
||||
| 14 = @ppd_ms_import
|
||||
| 15 = @ppd_elifdef
|
||||
| 16 = @ppd_elifndef
|
||||
| 18 = @ppd_warning
|
||||
;
|
||||
|
||||
@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next;
|
||||
@ppd_include = @ppd_plain_include | @ppd_objc_import | @ppd_include_next | @ppd_ms_import;
|
||||
|
||||
@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif;
|
||||
@ppd_branch = @ppd_if | @ppd_ifdef | @ppd_ifndef | @ppd_elif | @ppd_elifdef | @ppd_elifndef;
|
||||
|
||||
preprocpair(
|
||||
int begin : @ppd_branch ref,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support #elifdef, #elifndef and #import
|
||||
compatibility: partial
|
||||
@@ -177,6 +177,12 @@ predicate overflows(MulExpr me, Type t) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate buildModeNoneIntLongConversion(IntType argType, LongType resultType) {
|
||||
exists(argType) and
|
||||
exists(resultType) and
|
||||
exists(Compilation c | c.buildModeNone())
|
||||
}
|
||||
|
||||
from MulExpr me, Type t1, Type t2
|
||||
where
|
||||
t1 = me.getType().getUnderlyingType() and
|
||||
@@ -218,7 +224,10 @@ where
|
||||
// only report if we cannot prove that the result of the
|
||||
// multiplication will be less (resp. greater) than the
|
||||
// maximum (resp. minimum) number we can compute.
|
||||
overflows(me, t1)
|
||||
overflows(me, t1) and
|
||||
// In build mode none, many conversions from integer to long are caused by incorrect types,
|
||||
// so exclude those results
|
||||
not buildModeNoneIntLongConversion(t1, t2)
|
||||
select me,
|
||||
"Multiplication result may overflow '" + me.getType().toString() + "' before it is converted to '"
|
||||
+ me.getFullyConverted().getType().toString() + "'."
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 1.3.2
|
||||
version: 1.3.3-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
| #elif defined GREEN | preprocblock.cpp:10:0:11:0 | #ifndef BLUE |
|
||||
| #elif defined GREEN | preprocblock.cpp:14:0:15:0 | #if 0 |
|
||||
| #elif defined GREEN | preprocblock.cpp:16:0:17:0 | #else |
|
||||
| #elifdef GREEN | preprocblock23.cpp:11:0:12:0 | #if 0 |
|
||||
| #elifdef GREEN | preprocblock23.cpp:13:0:14:0 | #elifndef BLUE |
|
||||
| (no parent) | file://:0:0:0:0 | |
|
||||
| (no parent) | header.h:0:0:8:0 | header.h |
|
||||
| (no parent) | preprocblock23.cpp:0:0:22:0 | preprocblock23.cpp |
|
||||
| (no parent) | preprocblock.cpp:0:0:25:0 | preprocblock.cpp |
|
||||
| header.h | header.h:3:0:7:0 | #ifndef HEADER_H |
|
||||
| preprocblock23.cpp | preprocblock23.cpp:7:0:7:0 | #ifdef RED |
|
||||
| preprocblock23.cpp | preprocblock23.cpp:8:0:17:0 | #elifdef GREEN |
|
||||
| preprocblock23.cpp | preprocblock23.cpp:18:0:21:0 | #else |
|
||||
| preprocblock.cpp | preprocblock.cpp:6:0:6:0 | #ifdef RED |
|
||||
| preprocblock.cpp | preprocblock.cpp:7:0:20:0 | #elif defined GREEN |
|
||||
| preprocblock.cpp | preprocblock.cpp:21:0:24:0 | #else |
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// preprocblock23.cpp
|
||||
// semmle-extractor-options: -std=c++23
|
||||
|
||||
#include "header.h"
|
||||
#define GREEN
|
||||
|
||||
#ifdef RED
|
||||
#elifdef GREEN
|
||||
#include "header.h"
|
||||
|
||||
#if 0
|
||||
#include "header.h" // not reached
|
||||
#elifndef BLUE
|
||||
#include "header.h"
|
||||
#endif
|
||||
|
||||
#include "header.h"
|
||||
#else
|
||||
|
||||
// ...
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,7 @@
|
||||
| preprocblock23.cpp:4:1:4:19 | #include "header.h" | preprocblock23.cpp:0:0:22:0 | preprocblock23.cpp |
|
||||
| preprocblock23.cpp:9:2:9:20 | #include "header.h" | preprocblock23.cpp:8:0:17:0 | #elifdef GREEN |
|
||||
| preprocblock23.cpp:14:3:14:21 | #include "header.h" | preprocblock23.cpp:13:0:14:0 | #elifndef BLUE |
|
||||
| preprocblock23.cpp:17:2:17:20 | #include "header.h" | preprocblock23.cpp:8:0:17:0 | #elifdef GREEN |
|
||||
| preprocblock.cpp:3:1:3:19 | #include "header.h" | preprocblock.cpp:0:0:25:0 | preprocblock.cpp |
|
||||
| preprocblock.cpp:8:2:8:20 | #include "header.h" | preprocblock.cpp:7:0:20:0 | #elif defined GREEN |
|
||||
| preprocblock.cpp:11:3:11:21 | #include "header.h" | preprocblock.cpp:10:0:11:0 | #ifndef BLUE |
|
||||
|
||||
15
cpp/ql/test/library-tests/preprocessor/preprocessor/pp23.cpp
Normal file
15
cpp/ql/test/library-tests/preprocessor/preprocessor/pp23.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// semmle-extractor-options: -std=c++23
|
||||
|
||||
#define BAR
|
||||
|
||||
#ifdef FOO
|
||||
#warning C++23 1
|
||||
#elifdef BAR
|
||||
#warning C++23 2
|
||||
#endif
|
||||
|
||||
#ifdef FOO
|
||||
#warning C++23 3
|
||||
#elifndef FOO
|
||||
#warning C++23 3
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
// semmle-extractor-options: --microsoft
|
||||
|
||||
#import "test.tlb"
|
||||
@@ -1,4 +1,13 @@
|
||||
| a.h:0:0:0:0 | a.h | 1 | 1 | 1 | 19 | IncludeNext | "a.h" | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 3 | 1 | 3 | 11 | Macro | BAR | |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 5 | 1 | 5 | 10 | PreprocessorIfdef | FOO | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 7 | 1 | 7 | 12 | PreprocessorElifdef | BAR | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 8 | 1 | 8 | 16 | PreprocessorWarning | C++23 2 | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 9 | 1 | 9 | 6 | PreprocessorEndif | N/A | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 11 | 1 | 11 | 10 | PreprocessorIfdef | FOO | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 13 | 1 | 13 | 13 | PreprocessorElifndef | FOO | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 14 | 1 | 14 | 16 | PreprocessorWarning | C++23 3 | N/A |
|
||||
| pp23.cpp:0:0:0:0 | pp23.cpp | 15 | 1 | 15 | 6 | PreprocessorEndif | N/A | N/A |
|
||||
| pp.cpp:0:0:0:0 | pp.cpp | 1 | 1 | 1 | 16 | PreprocessorIf | defined(FOO) | N/A |
|
||||
| pp.cpp:0:0:0:0 | pp.cpp | 3 | 1 | 3 | 19 | PreprocessorElif | !defined(BAR) | N/A |
|
||||
| pp.cpp:0:0:0:0 | pp.cpp | 4 | 1 | 4 | 11 | Macro | BAR | |
|
||||
@@ -40,3 +49,6 @@
|
||||
| pp.h:0:0:0:0 | pp.h | 7 | 1 | 11 | 8 | Macro | MULTILINE | world a long |
|
||||
| pp.h:0:0:0:0 | pp.h | 13 | 1 | 14 | 11 | PreprocessorUndef | MULTILINE | N/A |
|
||||
| pp.h:0:0:0:0 | pp.h | 16 | 1 | 17 | 8 | Include | "pp.h" | N/A |
|
||||
| ppms.cpp:0:0:0:0 | ppms.cpp | 3 | 1 | 3 | 18 | TypeLibraryImport | "test.tlb" | N/A |
|
||||
| test.tlh:0:0:0:0 | test.tlh | 1 | 1 | 1 | 12 | PreprocessorPragma | once | N/A |
|
||||
| test.tlh:0:0:0:0 | test.tlh | 3 | 1 | 3 | 21 | PreprocessorWarning | type library | N/A |
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#warning type library
|
||||
@@ -0,0 +1,10 @@
|
||||
// semmle-extractor-options: --build-mode none
|
||||
|
||||
int f();
|
||||
|
||||
void test() {
|
||||
int i = f();
|
||||
unsigned u = i;
|
||||
long j = i * i; // GOOD: build mode none
|
||||
unsigned long k = u * u; // GOOD: build mode none
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Arithmetic/IntMultToLong.ql
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-all
|
||||
version: 1.7.32
|
||||
version: 1.7.33-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-solorigate-queries
|
||||
version: 1.7.32
|
||||
version: 1.7.33-dev
|
||||
groups:
|
||||
- csharp
|
||||
- solorigate
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-all
|
||||
version: 4.0.2
|
||||
version: 4.0.3-dev
|
||||
groups: csharp
|
||||
dbscheme: semmlecode.csharp.dbscheme
|
||||
extractor: csharp
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* All *experimental* queries have been deprecated. The queries are instead available as part of the *default* query suite in [CodeQL-Community-Packs](https://github.com/GitHubSecurityLab/CodeQL-Community-Packs).
|
||||
@@ -15,10 +15,16 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import TaintedWebClientLib
|
||||
import TaintedWebClient::PathGraph
|
||||
deprecated import TaintedWebClientLib
|
||||
deprecated import TaintedWebClient::PathGraph
|
||||
|
||||
from TaintedWebClient::PathNode source, TaintedWebClient::PathNode sink
|
||||
where TaintedWebClient::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "A method of WebClient depepends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
deprecated query predicate problems(
|
||||
DataFlow::Node sinkNode, TaintedWebClient::PathNode source, TaintedWebClient::PathNode sink,
|
||||
string message1, DataFlow::Node sourceNode, string message2
|
||||
) {
|
||||
TaintedWebClient::flowPath(source, sink) and
|
||||
sinkNode = sink.getNode() and
|
||||
message1 = "A method of WebClient depepends on a $@." and
|
||||
sourceNode = source.getNode() and
|
||||
message2 = "user-provided value"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
deprecated module;
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.frameworks.system.Net
|
||||
import semmle.code.csharp.frameworks.System
|
||||
|
||||
@@ -11,10 +11,16 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import RequestForgery::RequestForgery
|
||||
import RequestForgeryFlow::PathGraph
|
||||
deprecated import RequestForgery::RequestForgery
|
||||
deprecated import RequestForgeryFlow::PathGraph
|
||||
|
||||
from RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink
|
||||
where RequestForgeryFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "The URL of this request depends on a $@.", source.getNode(),
|
||||
"user-provided value"
|
||||
deprecated query predicate problems(
|
||||
DataFlow::Node sinkNode, RequestForgeryFlow::PathNode source, RequestForgeryFlow::PathNode sink,
|
||||
string message1, DataFlow::Node sourceNode, string message2
|
||||
) {
|
||||
RequestForgeryFlow::flowPath(source, sink) and
|
||||
sinkNode = sink.getNode() and
|
||||
message1 = "The URL of this request depends on a $@." and
|
||||
sourceNode = source.getNode() and
|
||||
message2 = "user-provided value"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
deprecated module;
|
||||
|
||||
import csharp
|
||||
|
||||
module RequestForgery {
|
||||
|
||||
@@ -17,89 +17,91 @@ import csharp
|
||||
import semmle.code.asp.WebConfig
|
||||
import semmle.code.csharp.frameworks.system.Web
|
||||
import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
||||
import experimental.dataflow.flowsources.AuthCookie
|
||||
deprecated import experimental.dataflow.flowsources.AuthCookie
|
||||
|
||||
from Expr httpOnlySink
|
||||
where
|
||||
exists(Assignment a, Expr val |
|
||||
httpOnlySink = a.getRValue() and
|
||||
val.getValue() = "false" and
|
||||
(
|
||||
exists(ObjectCreation oc |
|
||||
getAValueForProp(oc, a, "HttpOnly") = val and
|
||||
(
|
||||
deprecated query predicate problems(Expr httpOnlySink, string message) {
|
||||
(
|
||||
exists(Assignment a, Expr val |
|
||||
httpOnlySink = a.getRValue() and
|
||||
val.getValue() = "false" and
|
||||
(
|
||||
exists(ObjectCreation oc |
|
||||
getAValueForProp(oc, a, "HttpOnly") = val and
|
||||
(
|
||||
oc.getType() instanceof SystemWebHttpCookie and
|
||||
isCookieWithSensitiveName(oc.getArgument(0))
|
||||
or
|
||||
exists(MethodCall mc, MicrosoftAspNetCoreHttpResponseCookies iResponse |
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
iResponse.getAppendMethod() = mc.getTarget() and
|
||||
isCookieWithSensitiveName(mc.getArgument(0)) and
|
||||
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
||||
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
|
||||
// Passed as third argument to `IResponseCookies.Append`
|
||||
exists(DataFlow::Node creation, DataFlow::Node append |
|
||||
CookieOptionsTracking::flow(creation, append) and
|
||||
creation.asExpr() = oc and
|
||||
append.asExpr() = mc.getArgument(2)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(PropertyWrite pw |
|
||||
(
|
||||
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or
|
||||
pw.getProperty().getDeclaringType() instanceof
|
||||
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
|
||||
) and
|
||||
pw.getProperty().getName() = "HttpOnly" and
|
||||
a.getLValue() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRValue())
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Call c |
|
||||
httpOnlySink = c and
|
||||
(
|
||||
exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc |
|
||||
// default is not configured or is not set to `Always`
|
||||
not getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" and
|
||||
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
||||
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
|
||||
iResponse.getAppendMethod() = mc.getTarget() and
|
||||
isCookieWithSensitiveName(mc.getArgument(0)) and
|
||||
(
|
||||
// `HttpOnly` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
not isPropertySet(oc, "HttpOnly") and
|
||||
exists(DataFlow::Node creation |
|
||||
CookieOptionsTracking::flow(creation, _) and
|
||||
creation.asExpr() = oc
|
||||
)
|
||||
)
|
||||
or
|
||||
// IResponseCookies.Append(String, String) was called, `HttpOnly` is set to `false` by default
|
||||
mc = c and
|
||||
mc.getNumberOfArguments() < 3
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof SystemWebHttpCookie and
|
||||
isCookieWithSensitiveName(oc.getArgument(0))
|
||||
or
|
||||
exists(MethodCall mc, MicrosoftAspNetCoreHttpResponseCookies iResponse |
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
iResponse.getAppendMethod() = mc.getTarget() and
|
||||
isCookieWithSensitiveName(mc.getArgument(0)) and
|
||||
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
||||
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
|
||||
// Passed as third argument to `IResponseCookies.Append`
|
||||
exists(DataFlow::Node creation, DataFlow::Node append |
|
||||
CookieOptionsTracking::flow(creation, append) and
|
||||
creation.asExpr() = oc and
|
||||
append.asExpr() = mc.getArgument(2)
|
||||
)
|
||||
isCookieWithSensitiveName(oc.getArgument(0)) and
|
||||
// the property wasn't explicitly set, so a default value from config is used
|
||||
not isPropertySet(oc, "HttpOnly") and
|
||||
// the default in config is not set to `true`
|
||||
not exists(XmlElement element |
|
||||
element instanceof HttpCookiesElement and
|
||||
element.(HttpCookiesElement).isHttpOnlyCookies()
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(PropertyWrite pw |
|
||||
(
|
||||
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or
|
||||
pw.getProperty().getDeclaringType() instanceof
|
||||
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
|
||||
) and
|
||||
pw.getProperty().getName() = "HttpOnly" and
|
||||
a.getLValue() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRValue())
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Call c |
|
||||
httpOnlySink = c and
|
||||
(
|
||||
exists(MicrosoftAspNetCoreHttpResponseCookies iResponse, MethodCall mc |
|
||||
// default is not configured or is not set to `Always`
|
||||
not getAValueForCookiePolicyProp("HttpOnly").getValue() = "1" and
|
||||
// there is no callback `OnAppendCookie` that sets `HttpOnly` to true
|
||||
not OnAppendCookieHttpOnlyTracking::flowTo(_) and
|
||||
iResponse.getAppendMethod() = mc.getTarget() and
|
||||
isCookieWithSensitiveName(mc.getArgument(0)) and
|
||||
(
|
||||
// `HttpOnly` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
not isPropertySet(oc, "HttpOnly") and
|
||||
exists(DataFlow::Node creation |
|
||||
CookieOptionsTracking::flow(creation, _) and
|
||||
creation.asExpr() = oc
|
||||
)
|
||||
)
|
||||
or
|
||||
// IResponseCookies.Append(String, String) was called, `HttpOnly` is set to `false` by default
|
||||
mc = c and
|
||||
mc.getNumberOfArguments() < 3
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof SystemWebHttpCookie and
|
||||
isCookieWithSensitiveName(oc.getArgument(0)) and
|
||||
// the property wasn't explicitly set, so a default value from config is used
|
||||
not isPropertySet(oc, "HttpOnly") and
|
||||
// the default in config is not set to `true`
|
||||
not exists(XmlElement element |
|
||||
element instanceof HttpCookiesElement and
|
||||
element.(HttpCookiesElement).isHttpOnlyCookies()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
select httpOnlySink, "Cookie attribute 'HttpOnly' is not set to true."
|
||||
) and
|
||||
message = "Cookie attribute 'HttpOnly' is not set to true."
|
||||
}
|
||||
|
||||
@@ -68,15 +68,14 @@ predicate isExprAnAccessToSafeClientSideEncryptionVersionValue(Expr e) {
|
||||
)
|
||||
}
|
||||
|
||||
from Expr e, Class c, Assembly asm
|
||||
where
|
||||
asm = c.getLocation() and
|
||||
(
|
||||
deprecated query predicate problems(Expr e, string message) {
|
||||
exists(Class c, Assembly asm | asm = c.getLocation() |
|
||||
exists(Expr e2 |
|
||||
isCreatingAzureClientSideEncryptionObject(e, c, e2) and
|
||||
not isObjectCreationArgumentSafeAndUsingSafeVersionOfAssembly(e2, asm)
|
||||
)
|
||||
or
|
||||
isCreatingOutdatedAzureClientSideEncryptionObject(e, c)
|
||||
)
|
||||
select e, "Unsafe usage of v1 version of Azure Storage client-side encryption."
|
||||
) and
|
||||
message = "Unsafe usage of v1 version of Azure Storage client-side encryption."
|
||||
}
|
||||
|
||||
@@ -17,89 +17,91 @@ import csharp
|
||||
import semmle.code.asp.WebConfig
|
||||
import semmle.code.csharp.frameworks.system.Web
|
||||
import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
||||
import experimental.dataflow.flowsources.AuthCookie
|
||||
deprecated import experimental.dataflow.flowsources.AuthCookie
|
||||
|
||||
from Expr secureSink
|
||||
where
|
||||
exists(Call c |
|
||||
secureSink = c and
|
||||
(
|
||||
// default is not configured or is not set to `Always` or `SameAsRequest`
|
||||
not (
|
||||
getAValueForCookiePolicyProp("Secure").getValue() = "0" or
|
||||
getAValueForCookiePolicyProp("Secure").getValue() = "1"
|
||||
) and
|
||||
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
||||
not OnAppendCookieSecureTracking::flowTo(_) and
|
||||
deprecated query predicate problems(Expr secureSink, string message) {
|
||||
(
|
||||
exists(Call c |
|
||||
secureSink = c and
|
||||
(
|
||||
// `Secure` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
not isPropertySet(oc, "Secure") and
|
||||
exists(DataFlow::Node creation |
|
||||
CookieOptionsTracking::flow(creation, _) and
|
||||
creation.asExpr() = oc
|
||||
// default is not configured or is not set to `Always` or `SameAsRequest`
|
||||
not (
|
||||
getAValueForCookiePolicyProp("Secure").getValue() = "0" or
|
||||
getAValueForCookiePolicyProp("Secure").getValue() = "1"
|
||||
) and
|
||||
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
||||
not OnAppendCookieSecureTracking::flowTo(_) and
|
||||
(
|
||||
// `Secure` property in `CookieOptions` passed to IResponseCookies.Append(...) wasn't set
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
not isPropertySet(oc, "Secure") and
|
||||
exists(DataFlow::Node creation |
|
||||
CookieOptionsTracking::flow(creation, _) and
|
||||
creation.asExpr() = oc
|
||||
)
|
||||
)
|
||||
or
|
||||
// IResponseCookies.Append(String, String) was called, `Secure` is set to `false` by default
|
||||
exists(MethodCall mc, MicrosoftAspNetCoreHttpResponseCookies iResponse |
|
||||
mc = c and
|
||||
iResponse.getAppendMethod() = mc.getTarget() and
|
||||
mc.getNumberOfArguments() < 3
|
||||
)
|
||||
)
|
||||
or
|
||||
// IResponseCookies.Append(String, String) was called, `Secure` is set to `false` by default
|
||||
exists(MethodCall mc, MicrosoftAspNetCoreHttpResponseCookies iResponse |
|
||||
mc = c and
|
||||
iResponse.getAppendMethod() = mc.getTarget() and
|
||||
mc.getNumberOfArguments() < 3
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof SystemWebHttpCookie and
|
||||
// the property wasn't explicitly set, so a default value from config is used
|
||||
not isPropertySet(oc, "Secure") and
|
||||
// the default in config is not set to `true`
|
||||
// the `exists` below covers the `cs/web/requiressl-not-set`
|
||||
not exists(XmlElement element |
|
||||
element instanceof FormsElement and
|
||||
element.(FormsElement).isRequireSsl()
|
||||
or
|
||||
element instanceof HttpCookiesElement and
|
||||
element.(HttpCookiesElement).isRequireSsl()
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Assignment a, Expr val |
|
||||
secureSink = a.getRValue() and
|
||||
(
|
||||
exists(ObjectCreation oc |
|
||||
getAValueForProp(oc, a, "Secure") = val and
|
||||
val.getValue() = "false" and
|
||||
(
|
||||
oc.getType() instanceof SystemWebHttpCookie
|
||||
or
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
||||
not OnAppendCookieSecureTracking::flowTo(_) and
|
||||
// the cookie option is passed to `Append`
|
||||
exists(DataFlow::Node creation |
|
||||
CookieOptionsTracking::flow(creation, _) and
|
||||
creation.asExpr() = oc
|
||||
exists(ObjectCreation oc |
|
||||
oc = c and
|
||||
oc.getType() instanceof SystemWebHttpCookie and
|
||||
// the property wasn't explicitly set, so a default value from config is used
|
||||
not isPropertySet(oc, "Secure") and
|
||||
// the default in config is not set to `true`
|
||||
// the `exists` below covers the `cs/web/requiressl-not-set`
|
||||
not exists(XmlElement element |
|
||||
element instanceof FormsElement and
|
||||
element.(FormsElement).isRequireSsl()
|
||||
or
|
||||
element instanceof HttpCookiesElement and
|
||||
element.(HttpCookiesElement).isRequireSsl()
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(PropertyWrite pw |
|
||||
(
|
||||
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or
|
||||
pw.getProperty().getDeclaringType() instanceof
|
||||
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
|
||||
) and
|
||||
pw.getProperty().getName() = "SecurePolicy" and
|
||||
a.getLValue() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRValue()) and
|
||||
val.getValue() = "2" // None
|
||||
)
|
||||
or
|
||||
exists(Assignment a, Expr val |
|
||||
secureSink = a.getRValue() and
|
||||
(
|
||||
exists(ObjectCreation oc |
|
||||
getAValueForProp(oc, a, "Secure") = val and
|
||||
val.getValue() = "false" and
|
||||
(
|
||||
oc.getType() instanceof SystemWebHttpCookie
|
||||
or
|
||||
oc.getType() instanceof MicrosoftAspNetCoreHttpCookieOptions and
|
||||
// there is no callback `OnAppendCookie` that sets `Secure` to true
|
||||
not OnAppendCookieSecureTracking::flowTo(_) and
|
||||
// the cookie option is passed to `Append`
|
||||
exists(DataFlow::Node creation |
|
||||
CookieOptionsTracking::flow(creation, _) and
|
||||
creation.asExpr() = oc
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(PropertyWrite pw |
|
||||
(
|
||||
pw.getProperty().getDeclaringType() instanceof MicrosoftAspNetCoreHttpCookieBuilder or
|
||||
pw.getProperty().getDeclaringType() instanceof
|
||||
MicrosoftAspNetCoreAuthenticationCookiesCookieAuthenticationOptions
|
||||
) and
|
||||
pw.getProperty().getName() = "SecurePolicy" and
|
||||
a.getLValue() = pw and
|
||||
DataFlow::localExprFlow(val, a.getRValue()) and
|
||||
val.getValue() = "2" // None
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
select secureSink, "Cookie attribute 'Secure' is not set to true."
|
||||
) and
|
||||
message = "Cookie attribute 'Secure' is not set to true."
|
||||
}
|
||||
|
||||
@@ -192,7 +192,13 @@ module HashWithoutSaltConfig implements DataFlow::ConfigSig {
|
||||
|
||||
module HashWithoutSalt = TaintTracking::Global<HashWithoutSaltConfig>;
|
||||
|
||||
from HashWithoutSalt::PathNode source, HashWithoutSalt::PathNode sink
|
||||
where HashWithoutSalt::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "$@ is hashed without a salt.", source.getNode(),
|
||||
"The password"
|
||||
deprecated query predicate problems(
|
||||
DataFlow::Node sinkNode, HashWithoutSalt::PathNode source, HashWithoutSalt::PathNode sink,
|
||||
string message, DataFlow::Node sourceNode, string password
|
||||
) {
|
||||
sinkNode = sink.getNode() and
|
||||
sourceNode = source.getNode() and
|
||||
HashWithoutSalt::flowPath(source, sink) and
|
||||
message = "$@ is hashed without a salt." and
|
||||
password = "The password"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
deprecated module;
|
||||
|
||||
import csharp
|
||||
import DataFlow
|
||||
|
||||
|
||||
@@ -14,11 +14,17 @@
|
||||
|
||||
import csharp
|
||||
import DataFlow
|
||||
import JsonWebTokenHandlerLib
|
||||
deprecated import JsonWebTokenHandlerLib
|
||||
import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
from TokenValidationParametersProperty p, CallableAlwaysReturnsTrue e, string qualifier, string name
|
||||
where e = p.getAnAssignedValue() and p.hasFullyQualifiedName(qualifier, name)
|
||||
select e,
|
||||
"JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns \"true\".",
|
||||
p, getQualifiedName(qualifier, name)
|
||||
deprecated query predicate problems(
|
||||
CallableAlwaysReturnsTrue e, string message, TokenValidationParametersProperty p,
|
||||
string fullyQualifiedName
|
||||
) {
|
||||
exists(string qualifier, string name | p.hasFullyQualifiedName(qualifier, name) |
|
||||
fullyQualifiedName = getQualifiedName(qualifier, name)
|
||||
) and
|
||||
e = p.getAnAssignedValue() and
|
||||
message =
|
||||
"JsonWebTokenHandler security-sensitive property $@ is being delegated to this callable that always returns \"true\"."
|
||||
}
|
||||
|
||||
@@ -12,15 +12,18 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import JsonWebTokenHandlerLib
|
||||
deprecated import JsonWebTokenHandlerLib
|
||||
import semmle.code.csharp.commons.QualifiedName
|
||||
|
||||
from
|
||||
DataFlow::Node source, DataFlow::Node sink,
|
||||
TokenValidationParametersPropertySensitiveValidation pw, string qualifier, string name
|
||||
where
|
||||
deprecated query predicate problems(
|
||||
DataFlow::Node sink, string message, TokenValidationParametersPropertySensitiveValidation pw,
|
||||
string fullyQualifiedName, DataFlow::Node source, string value
|
||||
) {
|
||||
FalseValueFlowsToTokenValidationParametersPropertyWriteToBypassValidation::flow(source, sink) and
|
||||
sink.asExpr() = pw.getAnAssignedValue() and
|
||||
pw.hasFullyQualifiedName(qualifier, name)
|
||||
select sink, "The security sensitive property $@ is being disabled by the following value: $@.", pw,
|
||||
getQualifiedName(qualifier, name), source, "false"
|
||||
exists(string qualifier, string name | pw.hasFullyQualifiedName(qualifier, name) |
|
||||
fullyQualifiedName = getQualifiedName(qualifier, name)
|
||||
) and
|
||||
message = "The security sensitive property $@ is being disabled by the following value: $@." and
|
||||
value = "false"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.
|
||||
*/
|
||||
deprecated module;
|
||||
|
||||
import csharp
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
deprecated import DataSetSerialization
|
||||
|
||||
from DataSetOrTableRelatedClass dstc
|
||||
where dstc.fromSource()
|
||||
select dstc,
|
||||
"Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
|
||||
deprecated query predicate problems(DataSetOrTableRelatedClass dstc, string message) {
|
||||
dstc.fromSource() and
|
||||
message =
|
||||
"Defining a class that inherits or has a property derived from the obsolete DataSet or DataTable types. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
|
||||
}
|
||||
|
||||
@@ -10,12 +10,17 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
deprecated import DataSetSerialization
|
||||
|
||||
from UnsafeXmlSerializerImplementation c, Member m
|
||||
where
|
||||
deprecated query predicate problems(
|
||||
Member m, string message, UnsafeXmlSerializerImplementation c, string classMessage, Member member,
|
||||
string memberMessage
|
||||
) {
|
||||
c.fromSource() and
|
||||
isClassUnsafeXmlSerializerImplementation(c, m)
|
||||
select m,
|
||||
"Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details.",
|
||||
c, c.toString(), m, m.toString()
|
||||
isClassUnsafeXmlSerializerImplementation(c, m) and
|
||||
message =
|
||||
"Defining an serializable class $@ that has member $@ of a type that is derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." and
|
||||
classMessage = c.toString() and
|
||||
member = m and
|
||||
memberMessage = m.toString()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
deprecated import DataSetSerialization
|
||||
|
||||
predicate xmlSerializerConstructorArgument(Expr e) {
|
||||
exists(ObjectCreation oc, Constructor c | e = oc.getArgument(0) |
|
||||
@@ -21,7 +21,7 @@ predicate xmlSerializerConstructorArgument(Expr e) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate unsafeDataContractTypeCreation(Expr e) {
|
||||
deprecated predicate unsafeDataContractTypeCreation(Expr e) {
|
||||
exists(MethodCall gt |
|
||||
gt.getTarget().getName() = "GetType" and
|
||||
e = gt and
|
||||
@@ -31,16 +31,20 @@ predicate unsafeDataContractTypeCreation(Expr e) {
|
||||
e.(TypeofExpr).getTypeAccess().getTarget() instanceof DataSetOrTableRelatedClass
|
||||
}
|
||||
|
||||
module FlowToDataSerializerConstructorConfig implements DataFlow::ConfigSig {
|
||||
deprecated module FlowToDataSerializerConstructorConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node node) { unsafeDataContractTypeCreation(node.asExpr()) }
|
||||
|
||||
predicate isSink(DataFlow::Node node) { xmlSerializerConstructorArgument(node.asExpr()) }
|
||||
}
|
||||
|
||||
module FlowToDataSerializerConstructor = DataFlow::Global<FlowToDataSerializerConstructorConfig>;
|
||||
deprecated module FlowToDataSerializerConstructor =
|
||||
DataFlow::Global<FlowToDataSerializerConstructorConfig>;
|
||||
|
||||
from DataFlow::Node source, DataFlow::Node sink
|
||||
where FlowToDataSerializerConstructor::flow(source, sink)
|
||||
select sink,
|
||||
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source.",
|
||||
source, source.toString()
|
||||
deprecated query predicate problems(
|
||||
DataFlow::Node sink, string message, DataFlow::Node source, string sourceMessage
|
||||
) {
|
||||
FlowToDataSerializerConstructor::flow(source, sink) and
|
||||
message =
|
||||
"Unsafe type is used in data contract serializer. Make sure $@ comes from the trusted source." and
|
||||
sourceMessage = source.toString()
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import DataSetSerialization
|
||||
deprecated import DataSetSerialization
|
||||
|
||||
from UnsafeXmlReadMethodCall mc
|
||||
select mc,
|
||||
"Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details."
|
||||
deprecated query predicate problems(UnsafeXmlReadMethodCall mc, string message) {
|
||||
message =
|
||||
"Making an XML deserialization call with a type derived from DataSet or DataTable types and may lead to a security problem. Please visit https://go.microsoft.com/fwlink/?linkid=2132227 for details." and
|
||||
exists(mc)
|
||||
}
|
||||
|
||||
@@ -48,8 +48,8 @@ predicate isExternMethod(Method externMethod) {
|
||||
SystemRuntimeInteropServicesComImportAttributeClass
|
||||
}
|
||||
|
||||
from MethodCall mc
|
||||
where
|
||||
deprecated query predicate problems(MethodCall mc, string message) {
|
||||
isExternMethod(mc.getTarget()) and
|
||||
isDangerousMethod(mc.getTarget())
|
||||
select mc, "Call to an external method '" + mc.getTarget().getName() + "'."
|
||||
isDangerousMethod(mc.getTarget()) and
|
||||
message = "Call to an external method '" + mc.getTarget().getName() + "'."
|
||||
}
|
||||
|
||||
@@ -174,13 +174,16 @@ predicate isPotentialTimeBomb(
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
Flow::PathNode source, Flow::PathNode sink, Call getLastWriteTimeMethodCall,
|
||||
Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement
|
||||
where
|
||||
deprecated query predicate problems(
|
||||
SelectionStmt selStatement, Flow::PathNode source, Flow::PathNode sink, string message,
|
||||
Call timeComparisonCall, string timeComparisonCallString, Call timeArithmeticCall, string offset,
|
||||
Call getLastWriteTimeMethodCall, string lastWriteTimeMethodCallMessage
|
||||
) {
|
||||
isPotentialTimeBomb(source, sink, getLastWriteTimeMethodCall, timeArithmeticCall,
|
||||
timeComparisonCall, selStatement)
|
||||
select selStatement, source, sink,
|
||||
"Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger.",
|
||||
timeComparisonCall, timeComparisonCall.toString(), timeArithmeticCall, "offset",
|
||||
getLastWriteTimeMethodCall, "last modification time of a file"
|
||||
timeComparisonCall, selStatement) and
|
||||
message =
|
||||
"Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger." and
|
||||
timeComparisonCallString = timeComparisonCall.toString() and
|
||||
offset = "offset" and
|
||||
lastWriteTimeMethodCallMessage = "last modification time of a file"
|
||||
}
|
||||
|
||||
@@ -42,8 +42,15 @@ predicate isSuspiciousPropertyName(PropertyRead pr) {
|
||||
pr.getTarget().hasFullyQualifiedName("System.Diagnostics", "Process", "ProcessName")
|
||||
}
|
||||
|
||||
from DataFlowFromMethodToHash::PathNode src, DataFlowFromMethodToHash::PathNode sink
|
||||
where DataFlowFromMethodToHash::flow(src.getNode(), sink.getNode())
|
||||
select src.getNode(), src, sink,
|
||||
"The hash is calculated on $@, may be related to a backdoor. Please review the code for possible malicious intent.",
|
||||
sink.getNode(), "this process name"
|
||||
deprecated query predicate problems(
|
||||
DataFlow::Node srcNode, DataFlowFromMethodToHash::PathNode src,
|
||||
DataFlowFromMethodToHash::PathNode sink, string message, DataFlow::Node sinkNode,
|
||||
string sinkMessage
|
||||
) {
|
||||
srcNode = src.getNode() and
|
||||
sinkNode = sink.getNode() and
|
||||
DataFlowFromMethodToHash::flow(srcNode, sinkNode) and
|
||||
message =
|
||||
"The hash is calculated on $@, may be related to a backdoor. Please review the code for possible malicious intent." and
|
||||
sinkMessage = "this process name"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Provides classes and predicates for detecting insecure cookies.
|
||||
*/
|
||||
deprecated module;
|
||||
|
||||
import csharp
|
||||
import semmle.code.csharp.frameworks.microsoft.AspNetCore
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/csharp-queries
|
||||
version: 1.0.15
|
||||
version: 1.0.16-dev
|
||||
groups:
|
||||
- csharp
|
||||
- queries
|
||||
|
||||
@@ -4,5 +4,5 @@ nodes
|
||||
| RequestForgery.cs:12:52:12:54 | url : String | semmle.label | url : String |
|
||||
| RequestForgery.cs:14:66:14:68 | access to parameter url | semmle.label | access to parameter url |
|
||||
subpaths
|
||||
#select
|
||||
problems
|
||||
| RequestForgery.cs:14:66:14:68 | access to parameter url | RequestForgery.cs:12:52:12:54 | url : String | RequestForgery.cs:14:66:14:68 | access to parameter url | The URL of this request depends on a $@. | RequestForgery.cs:12:52:12:54 | url | user-provided value |
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
#select
|
||||
| HashWithoutSalt.cs:20:49:20:56 | access to local variable passBuff | HashWithoutSalt.cs:18:70:18:77 | access to parameter password : String | HashWithoutSalt.cs:20:49:20:56 | access to local variable passBuff | $@ is hashed without a salt. | HashWithoutSalt.cs:18:70:18:77 | access to parameter password | The password |
|
||||
| HashWithoutSalt.cs:39:51:39:59 | access to local variable passBytes | HashWithoutSalt.cs:38:64:38:71 | access to parameter password : String | HashWithoutSalt.cs:39:51:39:59 | access to local variable passBytes | $@ is hashed without a salt. | HashWithoutSalt.cs:38:64:38:71 | access to parameter password | The password |
|
||||
| HashWithoutSalt.cs:71:48:71:56 | access to local variable passBytes | HashWithoutSalt.cs:70:64:70:71 | access to parameter password : String | HashWithoutSalt.cs:71:48:71:56 | access to local variable passBytes | $@ is hashed without a salt. | HashWithoutSalt.cs:70:64:70:71 | access to parameter password | The password |
|
||||
edges
|
||||
| HashWithoutSalt.cs:18:17:18:24 | access to local variable passBuff : IBuffer | HashWithoutSalt.cs:20:49:20:56 | access to local variable passBuff | provenance | |
|
||||
| HashWithoutSalt.cs:18:28:18:105 | call to method ConvertStringToBinary : IBuffer | HashWithoutSalt.cs:18:17:18:24 | access to local variable passBuff : IBuffer | provenance | |
|
||||
@@ -27,4 +23,8 @@ nodes
|
||||
| HashWithoutSalt.cs:70:28:70:72 | call to method GetBytes : Byte[] | semmle.label | call to method GetBytes : Byte[] |
|
||||
| HashWithoutSalt.cs:70:64:70:71 | access to parameter password : String | semmle.label | access to parameter password : String |
|
||||
| HashWithoutSalt.cs:71:48:71:56 | access to local variable passBytes | semmle.label | access to local variable passBytes |
|
||||
problems
|
||||
| HashWithoutSalt.cs:20:49:20:56 | access to local variable passBuff | HashWithoutSalt.cs:18:70:18:77 | access to parameter password : String | HashWithoutSalt.cs:20:49:20:56 | access to local variable passBuff | $@ is hashed without a salt. | HashWithoutSalt.cs:18:70:18:77 | access to parameter password | The password |
|
||||
| HashWithoutSalt.cs:39:51:39:59 | access to local variable passBytes | HashWithoutSalt.cs:38:64:38:71 | access to parameter password : String | HashWithoutSalt.cs:39:51:39:59 | access to local variable passBytes | $@ is hashed without a salt. | HashWithoutSalt.cs:38:64:38:71 | access to parameter password | The password |
|
||||
| HashWithoutSalt.cs:71:48:71:56 | access to local variable passBytes | HashWithoutSalt.cs:70:64:70:71 | access to parameter password : String | HashWithoutSalt.cs:71:48:71:56 | access to local variable passBytes | $@ is hashed without a salt. | HashWithoutSalt.cs:70:64:70:71 | access to parameter password | The password |
|
||||
subpaths
|
||||
|
||||
@@ -17,7 +17,7 @@ edges
|
||||
| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo | provenance | |
|
||||
| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo : Int32 | provenance | |
|
||||
| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:36:71:70 | call to method AddHours | provenance | |
|
||||
#select
|
||||
problems
|
||||
| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
|
||||
| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo : Int32 | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
|
||||
| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:76 | ... >= ... | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
edges
|
||||
nodes
|
||||
subpaths
|
||||
#select
|
||||
problems
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
Java,"Java 7 to 22 [5]_","javac (OpenJDK and Oracle JDK),
|
||||
|
||||
Eclipse compiler for Java (ECJ) [6]_",``.java``
|
||||
Kotlin,"Kotlin 1.5.0 to 2.1.0\ *x*","kotlinc",``.kt``
|
||||
Kotlin,"Kotlin 1.5.0 to 2.1.2\ *x*","kotlinc",``.kt``
|
||||
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [7]_"
|
||||
Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
|
||||
Ruby [9]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
|
||||
Swift [10]_,"Swift 5.4-5.10","Swift compiler","``.swift``"
|
||||
TypeScript [11]_,"2.6-5.6",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
|
||||
TypeScript [11]_,"2.6-5.7",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
|
||||
|
||||
.. container:: footnote-group
|
||||
|
||||
|
||||
@@ -138,5 +138,5 @@ sync,,,34,,,,,,,,,,,,,,,,,,,,,,,34,
|
||||
syscall,5,2,8,5,,,,,,,,,,,,,,,,,,2,,,,8,
|
||||
text/scanner,,,3,,,,,,,,,,,,,,,,,,,,,,,3,
|
||||
text/tabwriter,,,1,,,,,,,,,,,,,,,,,,,,,,,1,
|
||||
text/template,,,6,,,,,,,,,,,,,,,,,,,,,,,6,
|
||||
text/template,,,4,,,,,,,,,,,,,,,,,,,,,,,4,
|
||||
xorm.io/xorm,34,,,,,,,,,,,,,,34,,,,,,,,,,,,
|
||||
|
||||
|
@@ -26,7 +26,7 @@ Go framework & library support
|
||||
`Macaron <https://gopkg.in/macaron.v1>`_,``gopkg.in/macaron*``,12,1,1
|
||||
`Revel <http://revel.github.io/>`_,"``github.com/revel/revel*``, ``github.com/robfig/revel*``",46,20,4
|
||||
`SendGrid <https://github.com/sendgrid/sendgrid-go>`_,``github.com/sendgrid/sendgrid-go*``,,1,
|
||||
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",52,605,104
|
||||
`Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",52,603,104
|
||||
`XPath <https://github.com/antchfx/xpath>`_,``github.com/antchfx/xpath*``,,,4
|
||||
`appleboy/gin-jwt <https://github.com/appleboy/gin-jwt>`_,``github.com/appleboy/gin-jwt*``,,,1
|
||||
`beego <https://beego.me/>`_,"``github.com/astaxie/beego*``, ``github.com/beego/beego*``",102,63,213
|
||||
@@ -61,5 +61,5 @@ Go framework & library support
|
||||
`yaml <https://gopkg.in/yaml.v3>`_,``gopkg.in/yaml*``,,9,
|
||||
`zap <https://go.uber.org/zap>`_,``go.uber.org/zap*``,,11,33
|
||||
Others,"``github.com/Masterminds/squirrel``, ``github.com/caarlos0/env``, ``github.com/go-gorm/gorm``, ``github.com/go-xorm/xorm``, ``github.com/gobuffalo/envy``, ``github.com/gogf/gf/database/gdb``, ``github.com/hashicorp/go-envparse``, ``github.com/jinzhu/gorm``, ``github.com/jmoiron/sqlx``, ``github.com/joho/godotenv``, ``github.com/kelseyhightower/envconfig``, ``github.com/lann/squirrel``, ``github.com/raindog308/gorqlite``, ``github.com/rqlite/gorqlite``, ``github.com/uptrace/bun``, ``go.mongodb.org/mongo-driver/mongo``, ``gopkg.in/Masterminds/squirrel``, ``gorm.io/gorm``, ``xorm.io/xorm``",117,16,391
|
||||
Totals,,459,943,1532
|
||||
Totals,,459,941,1532
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql-go-consistency-queries
|
||||
version: 1.0.15
|
||||
version: 1.0.16-dev
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Added the [rs cors](https://github.com/rs/cors) library to the CorsMisconfiguration.ql query
|
||||
5
go/ql/lib/change-notes/2024-12-16-any-content-readers.md
Normal file
5
go/ql/lib/change-notes/2024-12-16-any-content-readers.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* By implementing `ImplicitFieldReadNode` it is now possible to declare a dataflow node that reads any content (fields, array members, map keys and values). For example, this is appropriate for modelling a serialization method that flattens a potentially deep data structure into a string or byte array.
|
||||
* The `Template.Execute[Template]` methods of the `text/template` package now correctly convey taint from any nested fields to their result. This may produce more results from any taint-tracking query when the `text/template` package is in use.
|
||||
@@ -7,5 +7,5 @@ extensions:
|
||||
- ["text/template", "", False, "HTMLEscapeString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["text/template", "", False, "JSEscape", "", "", "Argument[1]", "Argument[0]", "taint", "manual"]
|
||||
- ["text/template", "", False, "JSEscapeString", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["text/template", "Template", True, "Execute", "", "", "Argument[1]", "Argument[0]", "taint", "manual"]
|
||||
- ["text/template", "Template", True, "ExecuteTemplate", "", "", "Argument[2]", "Argument[0]", "taint", "manual"]
|
||||
# - ["text/template", "Template", True, "Execute", "", "", "Argument[1]", "Argument[0]", "taint", "manual"] # Implemented in QL to provide an arbitrary content read from the input.
|
||||
# - ["text/template", "Template", True, "ExecuteTemplate", "", "", "Argument[2]", "Argument[0]", "taint", "manual"] # Implemented in QL to provide an arbitrary content read from the input.
|
||||
|
||||
@@ -32,6 +32,7 @@ import semmle.go.frameworks.Afero
|
||||
import semmle.go.frameworks.AwsLambda
|
||||
import semmle.go.frameworks.Beego
|
||||
import semmle.go.frameworks.BeegoOrm
|
||||
import semmle.go.frameworks.RsCors
|
||||
import semmle.go.frameworks.Couchbase
|
||||
import semmle.go.frameworks.Echo
|
||||
import semmle.go.frameworks.ElazarlGoproxy
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-all
|
||||
version: 3.0.2
|
||||
version: 3.0.3-dev
|
||||
groups: go
|
||||
dbscheme: go.dbscheme
|
||||
extractor: go
|
||||
|
||||
@@ -143,26 +143,28 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
* Thus, `node2` references an object with a content `x` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
// a write `(*p).f = rhs` is modeled as two store steps: `rhs` is flows into field `f` of `(*p)`,
|
||||
// which in turn flows into the pointer content of `p`
|
||||
exists(Write w, Field f, DataFlow::Node base, DataFlow::Node rhs | w.writesField(base, f, rhs) |
|
||||
node1 = rhs and
|
||||
node2.(PostUpdateNode).getPreUpdateNode() = base and
|
||||
c = any(DataFlow::FieldContent fc | fc.getField() = f)
|
||||
predicate storeStep(Node node1, ContentSet cs, Node node2) {
|
||||
exists(Content c | cs.asOneContent() = c |
|
||||
// a write `(*p).f = rhs` is modeled as two store steps: `rhs` is flows into field `f` of `(*p)`,
|
||||
// which in turn flows into the pointer content of `p`
|
||||
exists(Write w, Field f, DataFlow::Node base, DataFlow::Node rhs | w.writesField(base, f, rhs) |
|
||||
node1 = rhs and
|
||||
node2.(PostUpdateNode).getPreUpdateNode() = base and
|
||||
c = any(DataFlow::FieldContent fc | fc.getField() = f)
|
||||
or
|
||||
node1 = base and
|
||||
node2.(PostUpdateNode).getPreUpdateNode() = node1.(PointerDereferenceNode).getOperand() and
|
||||
c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType())
|
||||
)
|
||||
or
|
||||
node1 = base and
|
||||
node2.(PostUpdateNode).getPreUpdateNode() = node1.(PointerDereferenceNode).getOperand() and
|
||||
node1 = node2.(AddressOperationNode).getOperand() and
|
||||
c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType())
|
||||
or
|
||||
containerStoreStep(node1, node2, c)
|
||||
)
|
||||
or
|
||||
node1 = node2.(AddressOperationNode).getOperand() and
|
||||
c = any(DataFlow::PointerContent pc | pc.getPointerType() = node2.getType())
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), cs,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
or
|
||||
containerStoreStep(node1, node2, c)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,20 +172,26 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
|
||||
* Thus, `node1` references an object with a content `c` whose value ends up in
|
||||
* `node2`.
|
||||
*/
|
||||
predicate readStep(Node node1, ContentSet c, Node node2) {
|
||||
node1 = node2.(PointerDereferenceNode).getOperand() and
|
||||
c = any(DataFlow::PointerContent pc | pc.getPointerType() = node1.getType())
|
||||
or
|
||||
exists(FieldReadNode read |
|
||||
node2 = read and
|
||||
node1 = read.getBase() and
|
||||
c = any(DataFlow::FieldContent fc | fc.getField() = read.getField())
|
||||
predicate readStep(Node node1, ContentSet cs, Node node2) {
|
||||
exists(Content c | cs.asOneContent() = c |
|
||||
node1 = node2.(PointerDereferenceNode).getOperand() and
|
||||
c = any(DataFlow::PointerContent pc | pc.getPointerType() = node1.getType())
|
||||
or
|
||||
exists(FieldReadNode read |
|
||||
node2 = read and
|
||||
node1 = read.getBase() and
|
||||
c = any(DataFlow::FieldContent fc | fc.getField() = read.getField())
|
||||
)
|
||||
or
|
||||
containerReadStep(node1, node2, c)
|
||||
)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
|
||||
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), cs,
|
||||
node2.(FlowSummaryNode).getSummaryNode())
|
||||
or
|
||||
containerReadStep(node1, node2, c)
|
||||
any(ImplicitFieldReadNode ifrn).shouldImplicitlyReadAllFields(node1) and
|
||||
cs.isUniversalContent() and
|
||||
node1 = node2
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ private import semmle.go.dataflow.FunctionInputsAndOutputs
|
||||
private import semmle.go.dataflow.ExternalFlow
|
||||
private import DataFlowPrivate
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import codeql.util.Unit
|
||||
import DataFlowNodes::Public
|
||||
|
||||
/**
|
||||
@@ -50,6 +51,18 @@ abstract class FunctionModel extends Function {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A unit class for adding nodes that should implicitly read from all nested content.
|
||||
*
|
||||
* For example, this might be appropriate for the argument to a method that serializes a struct.
|
||||
*/
|
||||
class ImplicitFieldReadNode extends Unit {
|
||||
/**
|
||||
* Holds if the node `n` should implicitly read from all nested content in a taint-tracking context.
|
||||
*/
|
||||
abstract predicate shouldImplicitlyReadAllFields(DataFlow::Node n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `Node` corresponding to `insn`.
|
||||
*/
|
||||
@@ -169,6 +182,11 @@ class Content extends TContent {
|
||||
) {
|
||||
filepath = "" and startline = 0 and startcolumn = 0 and endline = 0 and endcolumn = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `ContentSet` contaning only this content.
|
||||
*/
|
||||
ContentSet asContentSet() { result.asOneContent() = this }
|
||||
}
|
||||
|
||||
/** A reference through a field. */
|
||||
@@ -236,21 +254,33 @@ class SyntheticFieldContent extends Content, TSyntheticFieldContent {
|
||||
override string toString() { result = s.toString() }
|
||||
}
|
||||
|
||||
private newtype TContentSet =
|
||||
TOneContent(Content c) or
|
||||
TAllContent()
|
||||
|
||||
/**
|
||||
* An entity that represents a set of `Content`s.
|
||||
*
|
||||
* The set may be interpreted differently depending on whether it is
|
||||
* stored into (`getAStoreContent`) or read from (`getAReadContent`).
|
||||
*/
|
||||
class ContentSet instanceof Content {
|
||||
class ContentSet instanceof TContentSet {
|
||||
/** Gets a content that may be stored into when storing into this set. */
|
||||
Content getAStoreContent() { result = this }
|
||||
Content getAStoreContent() { this = TOneContent(result) }
|
||||
|
||||
/** Gets a content that may be read from when reading from this set. */
|
||||
Content getAReadContent() { result = this }
|
||||
Content getAReadContent() {
|
||||
this = TOneContent(result)
|
||||
or
|
||||
this = TAllContent() and exists(result)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this content set. */
|
||||
string toString() { result = super.toString() }
|
||||
string toString() {
|
||||
exists(Content c | this = TOneContent(c) | result = c.toString())
|
||||
or
|
||||
this = TAllContent() and result = "all content"
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
@@ -262,8 +292,27 @@ class ContentSet instanceof Content {
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
super.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
exists(Content c | this = TOneContent(c) |
|
||||
c.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
)
|
||||
or
|
||||
this = TAllContent() and
|
||||
filepath = "" and
|
||||
startline = 0 and
|
||||
startcolumn = 0 and
|
||||
endline = 0 and
|
||||
endcolumn = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is a singleton content set, returns the content.
|
||||
*/
|
||||
Content asOneContent() { this = TOneContent(result) }
|
||||
|
||||
/**
|
||||
* Holds if this is a universal content set.
|
||||
*/
|
||||
predicate isUniversalContent() { this = TAllContent() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,26 +61,28 @@ module Input implements InputSig<Location, DataFlowImplSpecific::GoDataFlow> {
|
||||
}
|
||||
|
||||
string encodeContent(ContentSet cs, string arg) {
|
||||
exists(Field f, string package, string className, string fieldName |
|
||||
f = cs.(FieldContent).getField() and
|
||||
f.hasQualifiedName(package, className, fieldName) and
|
||||
result = "Field" and
|
||||
arg = package + "." + className + "." + fieldName
|
||||
exists(Content c | cs.asOneContent() = c |
|
||||
exists(Field f, string package, string className, string fieldName |
|
||||
f = c.(FieldContent).getField() and
|
||||
f.hasQualifiedName(package, className, fieldName) and
|
||||
result = "Field" and
|
||||
arg = package + "." + className + "." + fieldName
|
||||
)
|
||||
or
|
||||
exists(SyntheticField f |
|
||||
f = c.(SyntheticFieldContent).getField() and result = "SyntheticField" and arg = f
|
||||
)
|
||||
or
|
||||
c instanceof ArrayContent and result = "ArrayElement" and arg = ""
|
||||
or
|
||||
c instanceof CollectionContent and result = "Element" and arg = ""
|
||||
or
|
||||
c instanceof MapKeyContent and result = "MapKey" and arg = ""
|
||||
or
|
||||
c instanceof MapValueContent and result = "MapValue" and arg = ""
|
||||
or
|
||||
c instanceof PointerContent and result = "Dereference" and arg = ""
|
||||
)
|
||||
or
|
||||
exists(SyntheticField f |
|
||||
f = cs.(SyntheticFieldContent).getField() and result = "SyntheticField" and arg = f
|
||||
)
|
||||
or
|
||||
cs instanceof ArrayContent and result = "ArrayElement" and arg = ""
|
||||
or
|
||||
cs instanceof CollectionContent and result = "Element" and arg = ""
|
||||
or
|
||||
cs instanceof MapKeyContent and result = "MapKey" and arg = ""
|
||||
or
|
||||
cs instanceof MapValueContent and result = "MapValue" and arg = ""
|
||||
or
|
||||
cs instanceof PointerContent and result = "Dereference" and arg = ""
|
||||
}
|
||||
|
||||
bindingset[token]
|
||||
@@ -523,7 +525,9 @@ module Private {
|
||||
SummaryComponent qualifier() { result = argument(-1) }
|
||||
|
||||
/** Gets a summary component for field `f`. */
|
||||
SummaryComponent field(Field f) { result = content(any(FieldContent c | c.getField() = f)) }
|
||||
SummaryComponent field(Field f) {
|
||||
result = content(any(FieldContent c | c.getField() = f).asContentSet())
|
||||
}
|
||||
|
||||
/** Gets a summary component that represents the return value of a call. */
|
||||
SummaryComponent return() { result = SC::return(_) }
|
||||
|
||||
@@ -47,10 +47,11 @@ private Type getElementType(Type containerType) {
|
||||
* of `c` at sinks and inputs to additional taint steps.
|
||||
*/
|
||||
bindingset[node]
|
||||
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c) {
|
||||
exists(Type containerType |
|
||||
predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet cs) {
|
||||
exists(Type containerType, DataFlow::Content c |
|
||||
node instanceof DataFlow::ArgumentNode and
|
||||
getElementType*(node.getType()) = containerType
|
||||
getElementType*(node.getType()) = containerType and
|
||||
cs.asOneContent() = c
|
||||
|
|
||||
containerType instanceof ArrayType and
|
||||
c instanceof DataFlow::ArrayContent
|
||||
@@ -142,7 +143,7 @@ predicate elementWriteStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
any(DataFlow::Write w).writesElement(succ.(DataFlow::PostUpdateNode).getPreUpdateNode(), _, pred)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryStoreStep(pred.(DataFlowPrivate::FlowSummaryNode)
|
||||
.getSummaryNode(), any(DataFlow::Content c | c instanceof DataFlow::ArrayContent),
|
||||
.getSummaryNode(), any(DataFlow::ArrayContent ac).asContentSet(),
|
||||
succ.(DataFlowPrivate::FlowSummaryNode).getSummaryNode())
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ module GinCors {
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Credentials header
|
||||
*/
|
||||
class AllowCredentialsWrite extends DataFlow::ExprNode {
|
||||
class AllowCredentialsWrite extends UniversalAllowCredentialsWrite {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowCredentialsWrite() {
|
||||
@@ -35,12 +35,12 @@ module GinCors {
|
||||
/**
|
||||
* Get config struct holding header values
|
||||
*/
|
||||
DataFlow::Node getBase() { result = base }
|
||||
override DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
GinConfig getConfig() {
|
||||
override GinConfig getConfig() {
|
||||
exists(GinConfig gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
@@ -55,7 +55,7 @@ module GinCors {
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Origins header
|
||||
*/
|
||||
class AllowOriginsWrite extends DataFlow::ExprNode {
|
||||
class AllowOriginsWrite extends UniversalOriginWrite {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowOriginsWrite() {
|
||||
@@ -69,12 +69,12 @@ module GinCors {
|
||||
/**
|
||||
* Get config struct holding header values
|
||||
*/
|
||||
DataFlow::Node getBase() { result = base }
|
||||
override DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
GinConfig getConfig() {
|
||||
override GinConfig getConfig() {
|
||||
exists(GinConfig gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
@@ -89,7 +89,7 @@ module GinCors {
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Origins of value "*", overriding AllowOrigins
|
||||
*/
|
||||
class AllowAllOriginsWrite extends DataFlow::ExprNode {
|
||||
class AllowAllOriginsWrite extends UniversalAllowAllOriginsWrite {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowAllOriginsWrite() {
|
||||
@@ -103,12 +103,12 @@ module GinCors {
|
||||
/**
|
||||
* Get config struct holding header values
|
||||
*/
|
||||
DataFlow::Node getBase() { result = base }
|
||||
override DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
GinConfig getConfig() {
|
||||
override GinConfig getConfig() {
|
||||
exists(GinConfig gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
|
||||
184
go/ql/lib/semmle/go/frameworks/RsCors.qll
Normal file
184
go/ql/lib/semmle/go/frameworks/RsCors.qll
Normal file
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* Provides classes for modeling the `github.com/rs/cors` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/**
|
||||
* An abstract class for modeling the Go CORS handler model origin write.
|
||||
*/
|
||||
abstract class UniversalOriginWrite extends DataFlow::ExprNode {
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
abstract DataFlow::Node getBase();
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
abstract Variable getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract class for modeling the Go CORS handler model allow all origins write.
|
||||
*/
|
||||
abstract class UniversalAllowAllOriginsWrite extends DataFlow::ExprNode {
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
abstract DataFlow::Node getBase();
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
abstract Variable getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* An abstract class for modeling the Go CORS handler model allow credentials write.
|
||||
*/
|
||||
abstract class UniversalAllowCredentialsWrite extends DataFlow::ExprNode {
|
||||
/**
|
||||
* Get config struct holding header values
|
||||
*/
|
||||
abstract DataFlow::Node getBase();
|
||||
|
||||
/**
|
||||
* Get config variable holding header values
|
||||
*/
|
||||
abstract Variable getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes for modeling the `github.com/rs/cors` package.
|
||||
*/
|
||||
module RsCors {
|
||||
/** Gets the package name `github.com/gin-gonic/gin`. */
|
||||
string packagePath() { result = package("github.com/rs/cors", "") }
|
||||
|
||||
/**
|
||||
* A new function create a new rs Handler
|
||||
*/
|
||||
class New extends Function {
|
||||
New() { exists(Function f | f.hasQualifiedName(packagePath(), "New") | this = f) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Credentials header
|
||||
*/
|
||||
class AllowCredentialsWrite extends UniversalAllowCredentialsWrite {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowCredentialsWrite() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName(packagePath(), "Options", "AllowCredentials") and
|
||||
w.writesField(base, f, this) and
|
||||
this.getType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options struct holding header values
|
||||
*/
|
||||
override DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get options variable holding header values
|
||||
*/
|
||||
override RsOptions getConfig() {
|
||||
exists(RsOptions gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
base.asInstruction() or
|
||||
gc.getV().getAUse() = base
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Origins header
|
||||
*/
|
||||
class AllowOriginsWrite extends UniversalOriginWrite {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowOriginsWrite() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName(packagePath(), "Options", "AllowedOrigins") and
|
||||
w.writesField(base, f, this) and
|
||||
this.asExpr() instanceof SliceLit
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options struct holding header values
|
||||
*/
|
||||
override DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get options variable holding header values
|
||||
*/
|
||||
override RsOptions getConfig() {
|
||||
exists(RsOptions gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
base.asInstruction() or
|
||||
gc.getV().getAUse() = base
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A write to the value of Access-Control-Allow-Origins of value "*", overriding AllowOrigins
|
||||
*/
|
||||
class AllowAllOriginsWrite extends UniversalAllowAllOriginsWrite {
|
||||
DataFlow::Node base;
|
||||
|
||||
AllowAllOriginsWrite() {
|
||||
exists(Field f, Write w |
|
||||
f.hasQualifiedName(packagePath(), "Options", "AllowAllOrigins") and
|
||||
w.writesField(base, f, this) and
|
||||
this.getType() instanceof BoolType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get options struct holding header values
|
||||
*/
|
||||
override DataFlow::Node getBase() { result = base }
|
||||
|
||||
/**
|
||||
* Get options variable holding header values
|
||||
*/
|
||||
override RsOptions getConfig() {
|
||||
exists(RsOptions gc |
|
||||
(
|
||||
gc.getV().getBaseVariable().getDefinition().(SsaExplicitDefinition).getRhs() =
|
||||
base.asInstruction() or
|
||||
gc.getV().getAUse() = base
|
||||
) and
|
||||
result = gc
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable of type Options that holds the headers to be set.
|
||||
*/
|
||||
class RsOptions extends Variable {
|
||||
SsaWithFields v;
|
||||
|
||||
RsOptions() {
|
||||
this = v.getBaseVariable().getSourceVariable() and
|
||||
exists(Type t | t.hasQualifiedName(packagePath(), "Options") | v.getType() = t)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variable declaration of Options
|
||||
*/
|
||||
SsaWithFields getV() { result = v }
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ module NetHttp {
|
||||
|
|
||||
lastParamIndex = call.getCall().getCalleeType().getNumParameter() - 1 and
|
||||
varArgsSliceArgument = SummaryComponentStack::argument(lastParamIndex) and
|
||||
arrayContentSC = SummaryComponent::content(arrayContent) and
|
||||
arrayContentSC = SummaryComponent::content(arrayContent.asContentSet()) and
|
||||
stack = SummaryComponentStack::push(arrayContentSC, varArgsSliceArgument)
|
||||
)
|
||||
else stack = SummaryComponentStack::argument(n)
|
||||
|
||||
@@ -67,4 +67,45 @@ module TextTemplate {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
|
||||
private class ExecuteTemplateMethod extends Method {
|
||||
int inputArg;
|
||||
|
||||
ExecuteTemplateMethod() {
|
||||
exists(string name |
|
||||
this.hasQualifiedName("text/template", "Template", name) and
|
||||
(
|
||||
name = "Execute" and inputArg = 1
|
||||
or
|
||||
name = "ExecuteTemplate" and inputArg = 2
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
int getInputArgIdx() { result = inputArg }
|
||||
}
|
||||
|
||||
private class ExecuteTemplateFieldReader extends DataFlow::ImplicitFieldReadNode {
|
||||
override predicate shouldImplicitlyReadAllFields(DataFlow::Node n) {
|
||||
exists(ExecuteTemplateMethod m, DataFlow::MethodCallNode cn |
|
||||
cn.getTarget() = m and
|
||||
n = cn.getArgument(m.getInputArgIdx())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class ExecuteTemplateFunctionModels extends TaintTracking::FunctionModel,
|
||||
ExecuteTemplateMethod
|
||||
{
|
||||
FunctionInput inp;
|
||||
FunctionOutput outp;
|
||||
|
||||
ExecuteTemplateFunctionModels() {
|
||||
inp.isParameter(this.getInputArgIdx()) and outp.isParameter(0)
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ module UntrustedToAllowOriginHeaderConfig implements DataFlow::ConfigSig {
|
||||
module UntrustedToAllowOriginConfigConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof ActiveThreatModelSource }
|
||||
|
||||
additional predicate isSinkWrite(DataFlow::Node sink, GinCors::AllowOriginsWrite w) { sink = w }
|
||||
additional predicate isSinkWrite(DataFlow::Node sink, UniversalOriginWrite w) { sink = w }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSinkWrite(sink, _) }
|
||||
}
|
||||
@@ -102,17 +102,17 @@ predicate allowCredentialsIsSetToTrue(DataFlow::ExprNode allowOriginHW) {
|
||||
allowCredentialsHW.getResponseWriter()
|
||||
)
|
||||
or
|
||||
exists(GinCors::AllowCredentialsWrite allowCredentialsGin |
|
||||
exists(UniversalAllowCredentialsWrite allowCredentialsGin |
|
||||
allowCredentialsGin.getExpr().getBoolValue() = true
|
||||
|
|
||||
allowCredentialsGin.getConfig() = allowOriginHW.(GinCors::AllowOriginsWrite).getConfig() and
|
||||
not exists(GinCors::AllowAllOriginsWrite allowAllOrigins |
|
||||
allowCredentialsGin.getConfig() = allowOriginHW.(UniversalOriginWrite).getConfig() and
|
||||
not exists(UniversalAllowAllOriginsWrite allowAllOrigins |
|
||||
allowAllOrigins.getExpr().getBoolValue() = true and
|
||||
allowCredentialsGin.getConfig() = allowAllOrigins.getConfig()
|
||||
)
|
||||
or
|
||||
allowCredentialsGin.getBase() = allowOriginHW.(GinCors::AllowOriginsWrite).getBase() and
|
||||
not exists(GinCors::AllowAllOriginsWrite allowAllOrigins |
|
||||
allowCredentialsGin.getBase() = allowOriginHW.(UniversalOriginWrite).getBase() and
|
||||
not exists(UniversalAllowAllOriginsWrite allowAllOrigins |
|
||||
allowAllOrigins.getExpr().getBoolValue() = true and
|
||||
allowCredentialsGin.getBase() = allowAllOrigins.getBase()
|
||||
)
|
||||
@@ -150,7 +150,7 @@ predicate allowOriginIsNull(DataFlow::ExprNode allowOriginHW, string message) {
|
||||
+ " is set to `true`"
|
||||
or
|
||||
allowOriginHW
|
||||
.(GinCors::AllowOriginsWrite)
|
||||
.(UniversalOriginWrite)
|
||||
.asExpr()
|
||||
.(SliceLit)
|
||||
.getAnElement()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/go-queries
|
||||
version: 1.1.6
|
||||
version: 1.1.7-dev
|
||||
groups:
|
||||
- go
|
||||
- queries
|
||||
|
||||
@@ -5,3 +5,4 @@
|
||||
| CorsMisconfiguration.go:53:4:53:44 | call to Set | access-control-allow-origin header is set to a user-defined value, and access-control-allow-credentials is set to `true` |
|
||||
| CorsMisconfiguration.go:60:4:60:56 | call to Set | access-control-allow-origin header is set to a user-defined value, and access-control-allow-credentials is set to `true` |
|
||||
| CorsMisconfiguration.go:67:5:67:57 | call to Set | access-control-allow-origin header is set to a user-defined value, and access-control-allow-credentials is set to `true` |
|
||||
| RsCors.go:11:21:11:59 | slice literal | access-control-allow-origin header is set to `null`, and access-control-allow-credentials is set to `true` |
|
||||
|
||||
39
go/ql/test/experimental/CWE-942/RsCors.go
Normal file
39
go/ql/test/experimental/CWE-942/RsCors.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/rs/cors"
|
||||
)
|
||||
|
||||
func rs_vulnerable() {
|
||||
c := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"null", "http://foo.com:8080"},
|
||||
AllowCredentials: true,
|
||||
// Enable Debugging for testing, consider disabling in production
|
||||
Debug: true,
|
||||
})
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte("{\"hello\": \"world\"}"))
|
||||
})
|
||||
|
||||
http.ListenAndServe(":8080", c.Handler(handler))
|
||||
}
|
||||
|
||||
func rs_safe() {
|
||||
c := cors.New(cors.Options{
|
||||
AllowedOrigins: []string{"http://foo.com:8080"},
|
||||
AllowCredentials: true,
|
||||
// Enable Debugging for testing, consider disabling in production
|
||||
Debug: true,
|
||||
})
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write([]byte("{\"hello\": \"world\"}"))
|
||||
})
|
||||
|
||||
http.ListenAndServe(":8080", c.Handler(handler))
|
||||
}
|
||||
@@ -5,6 +5,7 @@ go 1.21
|
||||
require (
|
||||
github.com/gin-contrib/cors v1.4.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/rs/cors v1.10.1
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
53
go/ql/test/experimental/CWE-942/vendor/github.com/rs/cors/stub.go
generated
vendored
Normal file
53
go/ql/test/experimental/CWE-942/vendor/github.com/rs/cors/stub.go
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for github.com/rs/cors, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: github.com/rs/cors (exports: Options; functions: New)
|
||||
|
||||
// Package cors is a stub of github.com/rs/cors, generated by depstubber.
|
||||
package cors
|
||||
|
||||
import (
|
||||
http "net/http"
|
||||
)
|
||||
|
||||
type Cors struct {
|
||||
Log Logger
|
||||
}
|
||||
|
||||
func (_ *Cors) Handler(_ http.Handler) http.Handler {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ *Cors) HandlerFunc(_ http.ResponseWriter, _ *http.Request) {}
|
||||
|
||||
func (_ *Cors) OriginAllowed(_ *http.Request) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ *Cors) ServeHTTP(_ http.ResponseWriter, _ *http.Request, _ http.HandlerFunc) {}
|
||||
|
||||
type Logger interface {
|
||||
Printf(_ string, _ ...interface{})
|
||||
}
|
||||
|
||||
func New(_ Options) *Cors {
|
||||
return nil
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
AllowedOrigins []string
|
||||
AllowOriginFunc func(string) bool
|
||||
AllowOriginRequestFunc func(*http.Request, string) bool
|
||||
AllowOriginVaryRequestFunc func(*http.Request, string) (bool, []string)
|
||||
AllowedMethods []string
|
||||
AllowedHeaders []string
|
||||
ExposedHeaders []string
|
||||
MaxAge int
|
||||
AllowCredentials bool
|
||||
AllowPrivateNetwork bool
|
||||
OptionsPassthrough bool
|
||||
OptionsSuccessStatus int
|
||||
Debug bool
|
||||
Logger Logger
|
||||
}
|
||||
@@ -4,6 +4,9 @@ github.com/gin-contrib/cors
|
||||
# github.com/gin-gonic/gin v1.9.1
|
||||
## explicit
|
||||
github.com/gin-gonic/gin
|
||||
# github.com/rs/cors v1.10.1
|
||||
## explicit
|
||||
github.com/rs/cors
|
||||
# github.com/bytedance/sonic v1.9.1
|
||||
## explicit
|
||||
github.com/bytedance/sonic
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import go
|
||||
import utils.test.InlineFlowTest
|
||||
|
||||
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
|
||||
exists(sink) and
|
||||
result = src.(DataFlow::CallNode).getArgument(0).getExactValue()
|
||||
}
|
||||
|
||||
import TaintFlowTestArgString<DefaultFlowConfig, getArgString/2>
|
||||
@@ -0,0 +1,60 @@
|
||||
package xyz
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
type Inner1 struct {
|
||||
Data string
|
||||
}
|
||||
|
||||
type Inner2 struct {
|
||||
Data string
|
||||
}
|
||||
|
||||
type Inner3 struct {
|
||||
Data string
|
||||
}
|
||||
|
||||
type HasInner3Slice struct {
|
||||
Slice []Inner3
|
||||
}
|
||||
|
||||
type Outer struct {
|
||||
SliceField []Inner1
|
||||
PtrField *Inner2
|
||||
MapField map[string]Inner3
|
||||
DeepField HasInner3Slice
|
||||
}
|
||||
|
||||
func source(n int) string { return "dummy" }
|
||||
func sink(arg any) {}
|
||||
|
||||
func test() {
|
||||
|
||||
source1 := source(1)
|
||||
source2 := source(2)
|
||||
source3 := source(3)
|
||||
source4 := source(4)
|
||||
|
||||
toSerialize := Outer{[]Inner1{{source1}}, &Inner2{source2}, map[string]Inner3{"key": {source3}},
|
||||
HasInner3Slice{[]Inner3{{source4}}}}
|
||||
buff1 := new(bytes.Buffer)
|
||||
buff2 := new(bytes.Buffer)
|
||||
bytes1 := make([]byte, 10)
|
||||
bytes2 := make([]byte, 10)
|
||||
|
||||
tmpl, _ := template.New("test").Parse("Template text goes here (irrelevant for test)")
|
||||
tmpl.ExecuteTemplate(buff1, "test", toSerialize)
|
||||
buff1.Read(bytes1)
|
||||
sink(bytes1) // $ hasTaintFlow=1 hasTaintFlow=2 hasTaintFlow=3 hasTaintFlow=4
|
||||
|
||||
// Read `buff2` via an `any`-typed variable, to ensure the static type of the argument to tmpl.Execute makes no difference to the result
|
||||
var toSerializeAsAny any
|
||||
toSerializeAsAny = toSerialize
|
||||
tmpl.Execute(buff2, toSerializeAsAny)
|
||||
buff2.Read(bytes2)
|
||||
sink(bytes2) // $ hasTaintFlow=1 hasTaintFlow=2 hasTaintFlow=3 hasTaintFlow=4
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Add databaseMetadata relation
|
||||
compatibility: full
|
||||
databaseMetadata.rel: delete
|
||||
BIN
java/kotlin-extractor/deps/kotlin-compiler-2.1.20-Beta1.jar
(Stored with Git LFS)
Normal file
BIN
java/kotlin-extractor/deps/kotlin-compiler-2.1.20-Beta1.jar
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.1.20-Beta1.jar
(Stored with Git LFS)
Normal file
BIN
java/kotlin-extractor/deps/kotlin-compiler-embeddable-2.1.20-Beta1.jar
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
java/kotlin-extractor/deps/kotlin-stdlib-2.1.20-Beta1.jar
(Stored with Git LFS)
Normal file
BIN
java/kotlin-extractor/deps/kotlin-stdlib-2.1.20-Beta1.jar
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -25,7 +25,19 @@ import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.classFqName
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.types.typeWithArguments
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrStarProjection
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeArgument
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
@@ -2293,7 +2305,7 @@ open class KotlinFileExtractor(
|
||||
// synthesised and inherit the annotation from the delegate (which given it has
|
||||
// @NotNull, is likely written in Java)
|
||||
JvmAnnotationNames.JETBRAINS_NOT_NULL_ANNOTATION.takeUnless {
|
||||
t.isNullable() ||
|
||||
t.isNullableCodeQL() ||
|
||||
primitiveTypeMapping.getPrimitiveInfo(t) != null ||
|
||||
hasExistingAnnotation(it)
|
||||
}
|
||||
@@ -3975,7 +3987,7 @@ open class KotlinFileExtractor(
|
||||
target.parent
|
||||
} else {
|
||||
val st = extensionReceiverParameter.type as? IrSimpleType
|
||||
if (isNullable != null && st?.isNullable() != isNullable) {
|
||||
if (isNullable != null && st?.isNullableCodeQL() != isNullable) {
|
||||
verboseln("Nullablility of type didn't match")
|
||||
return false
|
||||
}
|
||||
@@ -4621,9 +4633,9 @@ open class KotlinFileExtractor(
|
||||
val isPrimitiveArrayCreation = !isBuiltinCallKotlin(c, "arrayOf")
|
||||
val elementType =
|
||||
if (isPrimitiveArrayCreation) {
|
||||
c.type.getArrayElementType(pluginContext.irBuiltIns)
|
||||
c.type.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
|
||||
} else {
|
||||
// TODO: is there any reason not to always use getArrayElementType?
|
||||
// TODO: is there any reason not to always use getArrayElementTypeCodeQL?
|
||||
if (c.typeArgumentsCount == 1) {
|
||||
c.getTypeArgument(0).also {
|
||||
if (it == null) {
|
||||
|
||||
@@ -12,7 +12,24 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.addAnnotations
|
||||
import org.jetbrains.kotlin.ir.types.classFqName
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.types.isNullableAny
|
||||
import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.types.typeOrNull
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.types.typeWithArguments
|
||||
import org.jetbrains.kotlin.ir.types.IrDynamicType
|
||||
import org.jetbrains.kotlin.ir.types.IrErrorType
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrStarProjection
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeArgument
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
|
||||
@@ -679,7 +696,7 @@ open class KotlinUsesExtractor(
|
||||
private fun getInvariantNullableArrayType(arrayType: IrSimpleType): IrSimpleType =
|
||||
if (arrayType.isPrimitiveArray()) arrayType
|
||||
else {
|
||||
val componentType = arrayType.getArrayElementType(pluginContext.irBuiltIns)
|
||||
val componentType = arrayType.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
|
||||
val componentTypeBroadened =
|
||||
when (componentType) {
|
||||
is IrSimpleType ->
|
||||
@@ -690,7 +707,7 @@ open class KotlinUsesExtractor(
|
||||
val unchanged =
|
||||
componentType == componentTypeBroadened &&
|
||||
(arrayType.arguments[0] as? IrTypeProjection)?.variance == Variance.INVARIANT &&
|
||||
componentType.isNullable()
|
||||
componentType.isNullableCodeQL()
|
||||
if (unchanged) arrayType
|
||||
else
|
||||
IrSimpleTypeImpl(
|
||||
@@ -705,7 +722,7 @@ open class KotlinUsesExtractor(
|
||||
Kotlin arrays can be broken down as:
|
||||
|
||||
isArray(t)
|
||||
|- t.isBoxedArray
|
||||
|- t.isBoxedArrayCodeQL
|
||||
| |- t.isArray() e.g. Array<Boolean>, Array<Boolean?>
|
||||
| |- t.isNullableArray() e.g. Array<Boolean>?, Array<Boolean?>?
|
||||
|- t.isPrimitiveArray() e.g. BooleanArray
|
||||
@@ -715,7 +732,7 @@ open class KotlinUsesExtractor(
|
||||
Primitive arrays are represented as e.g. boolean[].
|
||||
*/
|
||||
|
||||
private fun isArray(t: IrType) = t.isBoxedArray || t.isPrimitiveArray()
|
||||
private fun isArray(t: IrType) = t.isBoxedArrayCodeQL || t.isPrimitiveArray()
|
||||
|
||||
data class ArrayInfo(
|
||||
val elementTypeResults: TypeResults,
|
||||
@@ -756,7 +773,7 @@ open class KotlinUsesExtractor(
|
||||
) {
|
||||
pluginContext.irBuiltIns.anyType
|
||||
} else {
|
||||
t.getArrayElementType(pluginContext.irBuiltIns)
|
||||
t.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
|
||||
}
|
||||
|
||||
val recInfo = useArrayType(elementType, t.isPrimitiveArray())
|
||||
@@ -844,7 +861,7 @@ open class KotlinUsesExtractor(
|
||||
if (
|
||||
(context == TypeContext.RETURN ||
|
||||
(context == TypeContext.OTHER && otherIsPrimitive)) &&
|
||||
!s.isNullable() &&
|
||||
!s.isNullableCodeQL() &&
|
||||
getKotlinType(s)?.hasEnhancedNullability() != true &&
|
||||
primitiveName != null
|
||||
) {
|
||||
@@ -860,7 +877,7 @@ open class KotlinUsesExtractor(
|
||||
val kotlinClassId = useClassInstance(kotlinClass, listOf()).typeResult.id
|
||||
val kotlinResult =
|
||||
if (true) TypeResult(fakeKotlinType(), "TODO", "TODO")
|
||||
else if (s.isNullable()) {
|
||||
else if (s.isNullableCodeQL()) {
|
||||
val kotlinSignature =
|
||||
"$kotlinPackageName.$kotlinClassName?" // TODO: Is this right?
|
||||
val kotlinLabel = "@\"kt_type;nullable;$kotlinPackageName.$kotlinClassName\""
|
||||
@@ -902,21 +919,21 @@ open class KotlinUsesExtractor(
|
||||
return extractErrorType()
|
||||
}
|
||||
}
|
||||
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
|
||||
(s.isBoxedArrayCodeQL && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
|
||||
val arrayInfo = useArrayType(s, false)
|
||||
return arrayInfo.componentTypeResults
|
||||
}
|
||||
owner is IrClass -> {
|
||||
val args = if (s.codeQlIsRawType()) null else s.arguments
|
||||
|
||||
return useSimpleTypeClass(owner, args, s.isNullable())
|
||||
return useSimpleTypeClass(owner, args, s.isNullableCodeQL())
|
||||
}
|
||||
owner is IrTypeParameter -> {
|
||||
val javaResult = useTypeParameter(owner)
|
||||
val aClassId = makeClass("kotlin", "TypeParam") // TODO: Wrong
|
||||
val kotlinResult =
|
||||
if (true) TypeResult(fakeKotlinType(), "TODO", "TODO")
|
||||
else if (s.isNullable()) {
|
||||
else if (s.isNullableCodeQL()) {
|
||||
val kotlinSignature = "${javaResult.signature}?" // TODO: Wrong
|
||||
val kotlinLabel = "@\"kt_type;nullable;type_param\"" // TODO: Wrong
|
||||
val kotlinId: Label<DbKt_nullable_type> =
|
||||
@@ -1200,7 +1217,7 @@ open class KotlinUsesExtractor(
|
||||
}
|
||||
|
||||
private fun extendsAdditionAllowed(t: IrType) =
|
||||
if (t.isBoxedArray) {
|
||||
if (t.isBoxedArrayCodeQL) {
|
||||
if (t is IrSimpleType) {
|
||||
arrayExtendsAdditionAllowed(t)
|
||||
} else {
|
||||
@@ -1493,7 +1510,7 @@ open class KotlinUsesExtractor(
|
||||
}
|
||||
} else {
|
||||
t.classOrNull?.let { tCls ->
|
||||
if (t.isBoxedArray) {
|
||||
if (t.isBoxedArrayCodeQL) {
|
||||
(t.arguments.singleOrNull() as? IrTypeProjection)?.let { elementTypeArg
|
||||
->
|
||||
val elementType = elementTypeArg.type
|
||||
@@ -1506,7 +1523,7 @@ open class KotlinUsesExtractor(
|
||||
)
|
||||
return tCls
|
||||
.typeWithArguments(listOf(newArg))
|
||||
.codeQlWithHasQuestionMark(t.isNullable())
|
||||
.codeQlWithHasQuestionMark(t.isNullableCodeQL())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2086,12 +2103,12 @@ open class KotlinUsesExtractor(
|
||||
}
|
||||
|
||||
if (owner is IrClass) {
|
||||
if (t.isBoxedArray) {
|
||||
val elementType = t.getArrayElementType(pluginContext.irBuiltIns)
|
||||
if (t.isBoxedArrayCodeQL) {
|
||||
val elementType = t.getArrayElementTypeCodeQL(pluginContext.irBuiltIns)
|
||||
val erasedElementType = erase(elementType)
|
||||
return owner
|
||||
.typeWith(erasedElementType)
|
||||
.codeQlWithHasQuestionMark(t.isNullable())
|
||||
.codeQlWithHasQuestionMark(t.isNullableCodeQL())
|
||||
}
|
||||
|
||||
return if (t.arguments.isNotEmpty())
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.github.codeql.utils.versions.*
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.fir.java.JavaBinarySourceElement
|
||||
import org.jetbrains.kotlin.fir.java.VirtualFileBasedSourceElement
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
@@ -89,8 +89,8 @@ fun getIrClassVirtualFile(irClass: IrClass): VirtualFile? {
|
||||
is BinaryJavaClass -> return element.virtualFile
|
||||
}
|
||||
}
|
||||
is JavaBinarySourceElement -> {
|
||||
return cSource.javaClass.virtualFile
|
||||
is VirtualFileBasedSourceElement -> {
|
||||
return cSource.virtualFile
|
||||
}
|
||||
is KotlinJvmBinarySourceElement -> {
|
||||
val binaryClass = cSource.binaryClass
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.github.codeql.Logger
|
||||
import com.github.codeql.getJavaEquivalentClassId
|
||||
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
|
||||
import com.github.codeql.utils.versions.createImplicitParameterDeclarationWithWrappedDescriptor
|
||||
import com.github.codeql.utils.versions.*
|
||||
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
@@ -18,15 +19,18 @@ import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.DescriptorlessExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.addAnnotations
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrStarProjection
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeArgument
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.classId
|
||||
import org.jetbrains.kotlin.ir.util.constructedClassType
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.kotlinFqName
|
||||
import org.jetbrains.kotlin.ir.util.parents
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -57,7 +61,7 @@ private fun IrSimpleType.substituteTypeArguments(
|
||||
}
|
||||
}
|
||||
|
||||
return IrSimpleTypeImpl(classifier, isNullable(), newArguments, annotations)
|
||||
return IrSimpleTypeImpl(classifier, isNullableCodeQL(), newArguments, annotations)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,7 +100,7 @@ private fun subProjectedType(
|
||||
else {
|
||||
val newProjectedType =
|
||||
substitutedTypeArg.type.let {
|
||||
if (t.isNullable()) it.codeQlWithHasQuestionMark(true) else it
|
||||
if (t.isNullableCodeQL()) it.codeQlWithHasQuestionMark(true) else it
|
||||
}
|
||||
val newVariance = combineVariance(outerVariance, substitutedTypeArg.variance)
|
||||
makeTypeProjection(newProjectedType, newVariance)
|
||||
@@ -113,7 +117,7 @@ private fun IrTypeArgument.upperBound(context: IrPluginContext) =
|
||||
when (this.variance) {
|
||||
Variance.INVARIANT -> this.type
|
||||
Variance.IN_VARIANCE ->
|
||||
if (this.type.isNullable()) context.irBuiltIns.anyNType
|
||||
if (this.type.isNullableCodeQL()) context.irBuiltIns.anyNType
|
||||
else context.irBuiltIns.anyType
|
||||
Variance.OUT_VARIANCE -> this.type
|
||||
}
|
||||
@@ -128,7 +132,7 @@ private fun IrTypeArgument.lowerBound(context: IrPluginContext) =
|
||||
Variance.INVARIANT -> this.type
|
||||
Variance.IN_VARIANCE -> this.type
|
||||
Variance.OUT_VARIANCE ->
|
||||
if (this.type.isNullable()) context.irBuiltIns.nothingNType
|
||||
if (this.type.isNullableCodeQL()) context.irBuiltIns.nothingNType
|
||||
else context.irBuiltIns.nothingType
|
||||
}
|
||||
else -> context.irBuiltIns.nothingType
|
||||
@@ -211,7 +215,7 @@ fun IrTypeArgument.withQuestionMark(b: Boolean): IrTypeArgument =
|
||||
this.type.let {
|
||||
when (it) {
|
||||
is IrSimpleType ->
|
||||
if (it.isNullable() == b) this
|
||||
if (it.isNullableCodeQL() == b) this
|
||||
else makeTypeProjection(it.codeQlWithHasQuestionMark(b), this.variance)
|
||||
else -> this
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
|
||||
typealias IrBuiltIns = IrBuiltIns
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.kotlin.fir.java
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
|
||||
|
||||
@@ -7,5 +8,6 @@ import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
|
||||
We need this class to exist, but the compiler will never give us an
|
||||
instance of it.
|
||||
*/
|
||||
abstract class JavaBinarySourceElement private constructor(val javaClass: BinaryJavaClass) :
|
||||
SourceElement {}
|
||||
abstract class VirtualFileBasedSourceElement private constructor(val javaClass: BinaryJavaClass) : SourceElement {
|
||||
abstract val virtualFile: VirtualFile
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
|
||||
fun IrType.isNullableCodeQL(): Boolean =
|
||||
this.isNullable()
|
||||
|
||||
val IrType.isBoxedArrayCodeQL: Boolean by IrType::isBoxedArray
|
||||
|
||||
fun IrType.getArrayElementTypeCodeQL(irBuiltIns: IrBuiltIns): IrType =
|
||||
this.getArrayElementType(irBuiltIns)
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.github.codeql.utils.versions
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
|
||||
typealias IrBuiltIns = org.jetbrains.kotlin.ir.IrBuiltIns
|
||||
@@ -1,3 +0,0 @@
|
||||
/*
|
||||
The compiler provides this class, so we don't have to do anything.
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user