Merge pull request #7763 from erik-krogh/unused-field

QL: add unused-field query
This commit is contained in:
Erik Krogh Kristensen
2022-05-18 09:15:16 +02:00
committed by GitHub
7 changed files with 39 additions and 15 deletions

View File

@@ -96,8 +96,6 @@ private class IntentFlagsOrDataChangedSanitizer extends IntentUriPermissionManip
* ```
*/
private class IntentFlagsOrDataCheckedGuard extends IntentUriPermissionManipulationGuard {
Expr condition;
IntentFlagsOrDataCheckedGuard() { intentFlagsOrDataChecked(this, _, _) }
override predicate checks(Expr e, boolean branch) { intentFlagsOrDataChecked(this, e, branch) }

View File

@@ -148,8 +148,6 @@ private predicate isDisallowedWord(CompileTimeConstantExpr word) {
/** A complementary guard that protects against path traversal, by looking for the literal `..`. */
class PathTraversalGuard extends Guard instanceof MethodAccess {
Expr checked;
PathTraversalGuard() {
super.getMethod().getDeclaringType() instanceof TypeString and
super.getMethod().hasName(["contains", "indexOf"]) and

View File

@@ -330,8 +330,6 @@ module ClientRequest {
* A model of a URL request made using `require("needle")(...)`.
*/
class PromisedNeedleRequest extends ClientRequest::Range {
DataFlow::Node url;
PromisedNeedleRequest() { this = DataFlow::moduleImport("needle").getACall() }
override DataFlow::Node getUrl() { result = this.getArgument(1) }

View File

@@ -683,8 +683,6 @@ private module ExpressJwt {
*/
private module NodeRsa {
private class CreateKey extends CryptographicKeyCreation, API::InvokeNode {
CryptographicAlgorithm algorithm;
CreateKey() {
this = API::moduleImport("node-rsa").getAnInstantiation()
or

View File

@@ -67,7 +67,10 @@ module ExperimentalFlask {
private class FlaskResponse extends DataFlow::CallCfgNode, HeaderDeclaration::Range {
KeyValuePair item;
FlaskResponse() { this = Flask::Response::classRef().getACall() }
FlaskResponse() {
this = Flask::Response::classRef().getACall() and
item = this.getArg(_).asExpr().(Dict).getAnItem()
}
override DataFlow::Node getNameArg() { result.asExpr() = item.getKey() }

View File

@@ -13,8 +13,6 @@ edges
| flask_bad.py:35:18:35:24 | ControlFlowNode for request | flask_bad.py:35:18:35:29 | ControlFlowNode for Attribute |
| flask_bad.py:35:18:35:29 | ControlFlowNode for Attribute | flask_bad.py:35:18:35:43 | ControlFlowNode for Subscript |
| flask_bad.py:35:18:35:43 | ControlFlowNode for Subscript | flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header |
| flask_bad.py:44:44:44:50 | ControlFlowNode for request | flask_bad.py:44:44:44:55 | ControlFlowNode for Attribute |
| flask_bad.py:44:44:44:55 | ControlFlowNode for Attribute | flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript |
nodes
| django_bad.py:5:18:5:58 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
@@ -36,9 +34,6 @@ nodes
| flask_bad.py:35:18:35:29 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_bad.py:35:18:35:43 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | semmle.label | ControlFlowNode for rfs_header |
| flask_bad.py:44:44:44:50 | ControlFlowNode for request | semmle.label | ControlFlowNode for request |
| flask_bad.py:44:44:44:55 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
subpaths
#select
| django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | django_bad.py:5:18:5:58 | ControlFlowNode for Attribute() | django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | django_bad.py:7:40:7:49 | ControlFlowNode for rfs_header | This | django_bad.py:5:18:5:58 | ControlFlowNode for Attribute() | user-provided value |
@@ -47,4 +42,3 @@ subpaths
| flask_bad.py:21:38:21:47 | ControlFlowNode for rfs_header | flask_bad.py:19:18:19:24 | ControlFlowNode for request | flask_bad.py:21:38:21:47 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | flask_bad.py:21:38:21:47 | ControlFlowNode for rfs_header | This | flask_bad.py:19:18:19:24 | ControlFlowNode for request | user-provided value |
| flask_bad.py:29:34:29:43 | ControlFlowNode for rfs_header | flask_bad.py:27:18:27:24 | ControlFlowNode for request | flask_bad.py:29:34:29:43 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | flask_bad.py:29:34:29:43 | ControlFlowNode for rfs_header | This | flask_bad.py:27:18:27:24 | ControlFlowNode for request | user-provided value |
| flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | flask_bad.py:35:18:35:24 | ControlFlowNode for request | flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | $@ HTTP header is constructed from a $@. | flask_bad.py:38:24:38:33 | ControlFlowNode for rfs_header | This | flask_bad.py:35:18:35:24 | ControlFlowNode for request | user-provided value |
| flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | flask_bad.py:44:44:44:50 | ControlFlowNode for request | flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | $@ HTTP header is constructed from a $@. | flask_bad.py:44:44:44:69 | ControlFlowNode for Subscript | This | flask_bad.py:44:44:44:50 | ControlFlowNode for request | user-provided value |

View File

@@ -0,0 +1,35 @@
/**
* @name UnusedField
* @description A field that is not used in the characteristic predicate will contain every value
* of its type when accessed in other predicates, which is probably not intended.
* @kind problem
* @problem.severity warning
* @id ql/unused-field
* @precision high
*/
import ql
from ClassType clz, ClassType implClz, FieldDecl field, string extraMsg
where
clz.getDeclaration().getAField() = field and
implClz.getASuperType*() = clz and
// The field is not accessed in the charpred (of any of the classes)
not exists(FieldAccess access |
access.getEnclosingPredicate() = [clz, implClz].getDeclaration().getCharPred()
) and
// The implementation class is not abstract, and the field is not an override
not implClz.getDeclaration().isAbstract() and
not field.isOverride() and
// There doesn't exist a class in between `clz` and `implClz` that binds `field`.
not exists(ClassType c, CharPred p |
c.getASuperType*() = clz and
implClz.getASuperType*() = c and
p = c.getDeclaration().getCharPred() and
exists(FieldAccess access | access.getName() = field.getName() |
access.getEnclosingPredicate() = p
)
) and
(if clz = implClz then extraMsg = "." else extraMsg = " of any class between it and $@.")
select clz, "The field $@ declared in $@ is not used in the characteristic predicate" + extraMsg,
field, field.getName(), clz, clz.getName(), implClz, implClz.getName()