diff --git a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll index 4e908bf5dfe..fede4750c0f 100644 --- a/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll +++ b/csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll @@ -186,13 +186,6 @@ private Expr aspWrittenValue(AspInlineMember m) { m.getMember().(Callable).canReturn(result) } -private string makeUrl(Location l) { - exists(string path, int sl, int sc, int el, int ec | - l.hasLocationInfo(path, sl, sc, el, ec) and - result = "file://" + path + ":" + sl + ":" + sc + ":" + el + ":" + ec - ) -} - /** * A sink for writes to properties that are accessed in ASP pages. * @@ -208,10 +201,7 @@ private class AspxCodeSink extends Sink { AspxCodeSink() { this.getExpr() = aspWrittenValue(inline) } - override string explanation() { - result = - "member is [[\"accessed inline\"|\"" + makeUrl(inline.getLocation()) + "\"]] in an ASPX page" - } + override string explanation() { result = "member is accessed inline in an ASPX page" } } /** A sink for the output stream associated with a `HttpListenerResponse`. */ diff --git a/docs/codeql/codeql-language-guides/customizing-library-models-for-java-and-kotlin.rst b/docs/codeql/codeql-language-guides/customizing-library-models-for-java-and-kotlin.rst index 608235636f1..a3435002c85 100644 --- a/docs/codeql/codeql-language-guides/customizing-library-models-for-java-and-kotlin.rst +++ b/docs/codeql/codeql-language-guides/customizing-library-models-for-java-and-kotlin.rst @@ -69,6 +69,26 @@ The CodeQL library for Java and Kotlin analysis exposes the following extensible The extensible predicates are populated using the models defined in data extension files. +Specifying types in Java and Kotlin models +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Nested and inner classes** are denoted by joining the enclosing type and the nested type with a dollar sign (``$``), for example ``Outer$Inner``. This applies both to the type column and to nested types in a signature. For example, the ``Level`` enum nested inside the ``Logger`` interface, nested inside the ``System`` class, is written as ``System$Logger$Level``: + +.. code-block:: yaml + + - ["java.lang", "System$Logger", True, "log", "(System$Logger$Level,String)", "", "Argument[1]", "log-injection", "manual"] + +**Generics** are erased, so type parameters are removed: + +- In the type column, leave out any type parameters, so ``List`` becomes ``List``. +- In the signature, replace each type parameter with its upper bound, or ``Object`` if it has none. So ``T`` from ```` becomes ``Object``, and ``T`` from ```` becomes ``Number``. + +For example, ``forEach`` on ``Iterable`` takes a ``Consumer`` argument, so the type is ``Iterable`` and the signature is ``(Consumer)``: + +.. code-block:: yaml + + - ["java.lang", "Iterable", True, "forEach", "(Consumer)", "", "Argument[this].Element", "Argument[0].Parameter[0]", "value", "manual"] + Examples of custom model definitions ------------------------------------ diff --git a/java/documentation/library-coverage/coverage.csv b/java/documentation/library-coverage/coverage.csv index 389a84f1d16..7a4f6ce91ce 100644 --- a/java/documentation/library-coverage/coverage.csv +++ b/java/documentation/library-coverage/coverage.csv @@ -188,6 +188,8 @@ org.apache.hadoop.hive.ql.metadata,1,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,, org.apache.hc.client5.http.async.methods,84,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,84,,,,,,,,,,,,,,,,,, org.apache.hc.client5.http.classic.methods,37,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,37,,,,,,,,,,,,,,,,,, org.apache.hc.client5.http.fluent,19,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,19,,,,,,,,,,,,,,,,,, +org.apache.hc.client5.http.protocol,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 +org.apache.hc.client5.http.utils,,,7,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,7, org.apache.hc.core5.benchmark,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,, org.apache.hc.core5.function,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1, org.apache.hc.core5.http,73,2,45,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,72,,,,,,,,,,,,,,,,2,45, diff --git a/java/documentation/library-coverage/coverage.rst b/java/documentation/library-coverage/coverage.rst index 14a5286295f..3f4432d1b8e 100644 --- a/java/documentation/library-coverage/coverage.rst +++ b/java/documentation/library-coverage/coverage.rst @@ -40,6 +40,6 @@ Java framework & library support `Spring `_,``org.springframework.*``,46,494,143,26,,28,14,,35 `Thymeleaf `_,``org.thymeleaf``,,2,2,,,,,, `jOOQ `_,``org.jooq``,,,1,,,1,,, - Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6034,775,148,6,14,18,,186 - Totals,,382,26403,2707,421,16,137,33,1,415 + Others,"``actions.osgi``, ``antlr``, ``ch.ethz.ssh2``, ``cn.hutool.core.codec``, ``com.alibaba.com.caucho.hessian.io``, ``com.alibaba.druid.sql``, ``com.alibaba.fastjson2``, ``com.amazonaws.auth``, ``com.auth0.jwt.algorithms``, ``com.azure.identity``, ``com.caucho.burlap.io``, ``com.caucho.hessian.io``, ``com.cedarsoftware.util.io``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.esotericsoftware.yamlbeans``, ``com.hubspot.jinjava``, ``com.jcraft.jsch``, ``com.microsoft.sqlserver.jdbc``, ``com.mitchellbosecke.pebble``, ``com.opensymphony.xwork2``, ``com.sshtools.j2ssh.authentication``, ``com.sun.crypto.provider``, ``com.sun.jndi.ldap``, ``com.sun.net.httpserver``, ``com.sun.net.ssl``, ``com.sun.rowset``, ``com.sun.security.auth.module``, ``com.sun.security.ntlm``, ``com.sun.security.sasl.digest``, ``com.thoughtworks.xstream``, ``com.trilead.ssh2``, ``com.unboundid.ldap.sdk``, ``com.zaxxer.hikari``, ``flexjson``, ``hudson``, ``io.jsonwebtoken``, ``io.undertow.server.handlers.resource``, ``javafx.scene.web``, ``jenkins``, ``jodd.json``, ``liquibase.database.jvm``, ``liquibase.statement.core``, ``net.lingala.zip4j``, ``net.schmizz.sshj``, ``net.sf.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.acegisecurity``, ``org.antlr.runtime``, ``org.apache.avro``, ``org.apache.commons.codec``, ``org.apache.commons.compress.archivers.tar``, ``org.apache.commons.exec``, ``org.apache.commons.fileupload``, ``org.apache.commons.httpclient.util``, ``org.apache.commons.jelly``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.lang``, ``org.apache.commons.logging``, ``org.apache.commons.net``, ``org.apache.commons.ognl``, ``org.apache.cxf.catalog``, ``org.apache.cxf.common.classloader``, ``org.apache.cxf.common.jaxb``, ``org.apache.cxf.common.logging``, ``org.apache.cxf.configuration.jsse``, ``org.apache.cxf.helpers``, ``org.apache.cxf.resource``, ``org.apache.cxf.staxutils``, ``org.apache.cxf.tools.corba.utils``, ``org.apache.cxf.tools.util``, ``org.apache.cxf.transform``, ``org.apache.directory.ldap.client.api``, ``org.apache.hadoop.fs``, ``org.apache.hadoop.hive.metastore``, ``org.apache.hadoop.hive.ql.exec``, ``org.apache.hadoop.hive.ql.metadata``, ``org.apache.hc.client5.http.async.methods``, ``org.apache.hc.client5.http.classic.methods``, ``org.apache.hc.client5.http.fluent``, ``org.apache.hc.client5.http.protocol``, ``org.apache.hc.client5.http.utils``, ``org.apache.hive.hcatalog.templeton``, ``org.apache.ibatis.jdbc``, ``org.apache.ibatis.mapping``, ``org.apache.log4j``, ``org.apache.shiro.authc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.apache.shiro.mgt``, ``org.apache.sshd.client.session``, ``org.apache.tools.ant``, ``org.apache.tools.zip``, ``org.codehaus.cargo.container.installer``, ``org.dom4j``, ``org.exolab.castor.xml``, ``org.fusesource.leveldbjni``, ``org.geogebra.web.full.main``, ``org.gradle.api.file``, ``org.ho.yaml``, ``org.influxdb``, ``org.jabsorb``, ``org.jboss.vfs``, ``org.jdbi.v3.core``, ``org.jenkins.ui.icon``, ``org.jenkins.ui.symbol``, ``org.keycloak.models.map.storage``, ``org.kohsuke.stapler``, ``org.lastaflute.web``, ``org.mvel2``, ``org.openjdk.jmh.runner.options``, ``org.owasp.esapi``, ``org.pac4j.jwt.config.encryption``, ``org.pac4j.jwt.config.signature``, ``org.scijava.log``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.libs.ws``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``, ``software.amazon.awssdk.transfer.s3.model``, ``sun.jvmstat.perfdata.monitor.protocol.local``, ``sun.jvmstat.perfdata.monitor.protocol.rmi``, ``sun.misc``, ``sun.net.ftp``, ``sun.net.www.protocol.http``, ``sun.security.acl``, ``sun.security.jgss.krb5``, ``sun.security.krb5``, ``sun.security.pkcs``, ``sun.security.pkcs11``, ``sun.security.provider``, ``sun.security.ssl``, ``sun.security.x509``, ``sun.tools.jconsole``",127,6042,775,148,6,14,18,,186 + Totals,,382,26411,2707,421,16,137,33,1,415 diff --git a/python/ql/lib/CHANGELOG.md b/python/ql/lib/CHANGELOG.md index 7d4f024be7a..a8122f03eb1 100644 --- a/python/ql/lib/CHANGELOG.md +++ b/python/ql/lib/CHANGELOG.md @@ -70,7 +70,7 @@ No user-facing changes. ### Minor Analysis Improvements -* Added new full SSRF sanitization barrier from the new AntiSSRF library. +* Added new full SSRF sanitization barrier from the new AntiSSRF library. * When a guard such as `isSafe(x)` is defined, we now also automatically handle `isSafe(x) == true` and `isSafe(x) != false`. ## 6.1.1 @@ -169,7 +169,7 @@ No user-facing changes. ### Minor Analysis Improvements - The modelling of Psycopg2 now supports the use of `psycopg2.pool` connection pools for handling database connections. -* Removed `lxml` as an XML bomb sink. The underlying libxml2 library now includes [entity reference loop detection](https://github.com/lxml/lxml/blob/f33ac2c2f5f9c4c4c1fc47f363be96db308f2fa6/doc/FAQ.txt#L1077) that prevents XML bomb attacks. +* Removed `lxml` as an XML bomb sink. The underlying libxml2 library now includes [entity reference loop detection](https://github.com/lxml/lxml/blob/f33ac2c2f5f9c4c4c1fc47f363be96db308f2fa6/doc/FAQ.txt#L1077) that prevents XML bomb attacks. ## 4.0.13 @@ -262,7 +262,7 @@ No user-facing changes. ### Minor Analysis Improvements * The sensitive data library has been improved so that `snake_case` style variable names are recognized more reliably. This may result in more sensitive data being identified, and more results from queries that use the sensitive data library. -- Additional taint steps through methods of `lxml.etree.Element` and `lxml.etree.ElementTree` objects from the `lxml` PyPI package have been modeled. +- Additional taint steps through methods of `lxml.etree.Element` and `lxml.etree.ElementTree` objects from the `lxml` PyPI package have been modeled. ## 3.1.0 @@ -316,7 +316,7 @@ No user-facing changes. ### Minor Analysis Improvements -* The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries. +* The common sanitizer guard `StringConstCompareBarrier` has been renamed to `ConstCompareBarrier` and expanded to cover comparisons with other constant values such as `None`. This may result in fewer false positive results for several queries. ## 2.0.0 @@ -545,7 +545,7 @@ No user-facing changes. ### New Features -* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`. +* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`. Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed. ### Minor Analysis Improvements @@ -572,7 +572,7 @@ No user-facing changes. * Deleted many deprecated predicates and classes with uppercase `API`, `HTTP`, `XSS`, `SQL`, etc. in their names. Use the PascalCased versions instead. * Deleted the deprecated `getName()` predicate from the `Container` class, use `getAbsolutePath()` instead. * Deleted many deprecated module names that started with a lowercase letter, use the versions that start with an uppercase letter instead. -* Deleted many deprecated predicates in `PointsTo.qll`. +* Deleted many deprecated predicates in `PointsTo.qll`. * Deleted many deprecated files from the `semmle.python.security` package. * Deleted the deprecated `BottleRoutePointToExtension` class from `Extensions.qll`. * Type tracking is now aware of flow summaries. This leads to a richer API graph, and may lead to more results in some queries. @@ -729,7 +729,7 @@ No user-facing changes. ### Deprecated APIs * Some unused predicates in `SsaDefinitions.qll`, `TObject.qll`, `protocols.qll`, and the `pointsto/` folder have been deprecated. -* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide. +* Some classes/modules with upper-case acronyms in their name have been renamed to follow our style-guide. The old name still exists as a deprecated alias. ### Minor Analysis Improvements @@ -748,9 +748,9 @@ No user-facing changes. ### Deprecated APIs -* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide. +* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide. The old name still exists as a deprecated alias. -* The utility files previously in the `semmle.python.security.performance` package have been moved to the `semmle.python.security.regexp` package. +* The utility files previously in the `semmle.python.security.performance` package have been moved to the `semmle.python.security.regexp` package. The previous files still exist as deprecated aliases. ### Minor Analysis Improvements @@ -843,9 +843,9 @@ No user-facing changes. ### Deprecated APIs -* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide. +* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide. The old name still exists as a deprecated alias. -* Some modules that started with a lowercase letter have been renamed to follow our style-guide. +* Some modules that started with a lowercase letter have been renamed to follow our style-guide. The old name still exists as a deprecated alias. ### New Features diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll index 13afd6a4276..02fae4611f4 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll @@ -170,7 +170,13 @@ module TypeTrackingInput implements Shared::TypeTrackingInput { /** Holds if there is a level step from `nodeFrom` to `nodeTo`, which may depend on the call graph. */ predicate levelStepCall(Node nodeFrom, LocalSourceNode nodeTo) { - instanceFieldStep(nodeFrom, nodeTo) + // HOTFIX: `instanceFieldStep` is temporarily disabled (via `and none()`). + // It uses `classInstanceTracker(cls)` -- itself a type-tracker run -- + // from inside `levelStepCall`, creating a structural mutual recursion + // that causes catastrophic query slowdowns on some OOP-heavy Python + // codebases (e.g. mypy and dask). The `and none()` should be removed + // once that recursion is redesigned. + instanceFieldStep(nodeFrom, nodeTo) and none() or inheritedFieldStep(nodeFrom, nodeTo) } diff --git a/python/ql/test/library-tests/dataflow/typetracking/attribute_tests.py b/python/ql/test/library-tests/dataflow/typetracking/attribute_tests.py index b6bca72507f..09fed01398e 100644 --- a/python/ql/test/library-tests/dataflow/typetracking/attribute_tests.py +++ b/python/ql/test/library-tests/dataflow/typetracking/attribute_tests.py @@ -157,7 +157,7 @@ class MyClass2(object): print(self.foo) # $ tracked MISSING: tracked=foo instance = MyClass2() -print(instance.foo) # $ tracked MISSING: tracked=foo +print(instance.foo) # $ MISSING: tracked=foo tracked instance.print_foo() # $ MISSING: tracked=foo @@ -195,7 +195,7 @@ class Sub1(Base1): sub1 = Sub1() sub1.read_foo() -print(sub1.foo) # $ tracked MISSING: tracked=foo +print(sub1.foo) # $ MISSING: tracked=foo tracked # attribute written in a subclass method, read in an inherited base class method @@ -210,7 +210,7 @@ class Sub2(Base2): sub2 = Sub2() sub2.read_bar() -print(sub2.bar) # $ tracked MISSING: tracked=bar +print(sub2.bar) # $ MISSING: tracked=bar tracked # attribute written in a base class method, read on an instance of the subclass @@ -223,4 +223,4 @@ class Sub3(Base3): pass sub3 = Sub3() -print(sub3.baz) # $ tracked MISSING: tracked=baz +print(sub3.baz) # $ MISSING: tracked=baz tracked diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected index 8f60394d8a2..4cbcb33440b 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/SqlInjection.expected @@ -1,7 +1,6 @@ #select | app.py:23:20:23:24 | ControlFlowNode for query | app.py:20:18:20:21 | ControlFlowNode for name | app.py:23:20:23:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:20:18:20:21 | ControlFlowNode for name | user-provided value | | app.py:30:20:30:24 | ControlFlowNode for query | app.py:27:19:27:22 | ControlFlowNode for name | app.py:30:20:30:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:27:19:27:22 | ControlFlowNode for name | user-provided value | -| app.py:37:20:37:24 | ControlFlowNode for query | app.py:34:19:34:22 | ControlFlowNode for name | app.py:37:20:37:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:34:19:34:22 | ControlFlowNode for name | user-provided value | | app.py:44:20:44:24 | ControlFlowNode for query | app.py:41:19:41:22 | ControlFlowNode for name | app.py:44:20:44:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:41:19:41:22 | ControlFlowNode for name | user-provided value | | app.py:51:20:51:24 | ControlFlowNode for query | app.py:48:19:48:22 | ControlFlowNode for name | app.py:51:20:51:24 | ControlFlowNode for query | This SQL query depends on a $@. | app.py:48:19:48:22 | ControlFlowNode for name | user-provided value | | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | sql_injection.py:14:15:14:22 | ControlFlowNode for username | sql_injection.py:21:24:21:77 | ControlFlowNode for BinaryExpr | This SQL query depends on a $@. | sql_injection.py:14:15:14:22 | ControlFlowNode for username | user-provided value | @@ -25,8 +24,6 @@ edges | app.py:21:5:21:9 | ControlFlowNode for query | app.py:23:20:23:24 | ControlFlowNode for query | provenance | | | app.py:27:19:27:22 | ControlFlowNode for name | app.py:28:5:28:9 | ControlFlowNode for query | provenance | | | app.py:28:5:28:9 | ControlFlowNode for query | app.py:30:20:30:24 | ControlFlowNode for query | provenance | | -| app.py:34:19:34:22 | ControlFlowNode for name | app.py:35:5:35:9 | ControlFlowNode for query | provenance | | -| app.py:35:5:35:9 | ControlFlowNode for query | app.py:37:20:37:24 | ControlFlowNode for query | provenance | | | app.py:41:19:41:22 | ControlFlowNode for name | app.py:42:5:42:9 | ControlFlowNode for query | provenance | | | app.py:42:5:42:9 | ControlFlowNode for query | app.py:44:20:44:24 | ControlFlowNode for query | provenance | | | app.py:48:19:48:22 | ControlFlowNode for name | app.py:49:5:49:9 | ControlFlowNode for query | provenance | | @@ -54,9 +51,6 @@ nodes | app.py:27:19:27:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | app.py:28:5:28:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | app.py:30:20:30:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:34:19:34:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | -| app.py:35:5:35:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | -| app.py:37:20:37:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | app.py:41:19:41:22 | ControlFlowNode for name | semmle.label | ControlFlowNode for name | | app.py:42:5:42:9 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | | app.py:44:20:44:24 | ControlFlowNode for query | semmle.label | ControlFlowNode for query | diff --git a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/app.py b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/app.py index 4de61346d8f..8046f1ef52e 100644 --- a/python/ql/test/query-tests/Security/CWE-089-SqlInjection/app.py +++ b/python/ql/test/query-tests/Security/CWE-089-SqlInjection/app.py @@ -31,10 +31,10 @@ async def unsafe2(name: str): # $ Source cursor.close() @app.get("/unsafe3/") -async def unsafe3(name: str): # $ Source +async def unsafe3(name: str): # $ MISSING: Source query = "select * from users where name=" + name cursor = hdb_con3.cursor() - cursor.execute(query) # $ Alert + cursor.execute(query) # $ MISSING: Alert cursor.close() @app.get("/unsafe4/") diff --git a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll index 09e2505eb5c..fe5a8b03841 100644 --- a/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll +++ b/rust/ql/lib/codeql/rust/security/HardcodedCryptographicValueExtensions.qll @@ -62,24 +62,34 @@ module HardcodedCryptographicValue { abstract class Barrier extends DataFlow::Node { } /** - * A literal, considered as a flow source. + * Holds if `e` is a literal or a combination of literals that is constant. */ - private class LiteralSource extends Source { - LiteralSource() { this.asExpr() instanceof LiteralExpr } + private predicate isConstant(Expr e) { + e instanceof LiteralExpr // e.g. `0` + or + forex(Expr elem | elem = e.(ArrayListExpr).getExpr(_) | isConstant(elem)) // e.g. `[0, 0, 0, 0]` + or + isConstant(e.(ArrayRepeatExpr).getRepeatOperand()) // e.g. `[0; 10]` + or + // e.g. `const MY_CONST: u64 = ...` + // the constant initializer / body is the preferred source location for flow paths, when available. + e = any(Const c).getBody() + or + // e.g. `u64::MAX` + // when the constant initializer is not available as a source location (case above), use the access instead. + e instanceof ConstAccess and + not exists(e.(ConstAccess).getConst().getBody()) + or + // e.g. `1 << 4` + isConstant(e.(BinaryExpr).getLhs()) and + isConstant(e.(BinaryExpr).getRhs()) } /** - * An array initialized from a list of literals, considered as a single flow source. For example: - * ``` - * [0, 0, 0, 0] - * [0; 10] - * ``` + * A constant, considered as a flow source. */ - private class ArrayListSource extends Source { - ArrayListSource() { - this.asExpr().(ArrayListExpr).getExpr(_) instanceof LiteralExpr or - this.asExpr().(ArrayRepeatExpr).getRepeatOperand() instanceof LiteralExpr - } + private class ConstantSource extends Source { + ConstantSource() { isConstant(this.asExpr()) } } /** @@ -155,4 +165,24 @@ module HardcodedCryptographicValue { ) } } + + /** + * An arithmetic or bitwise operation that acts as a barrier. + * + * This prevents false positives where a hard-coded value is combined with + * non-constant data through operations like `+`, `^`, or `+=` (including string concatenation). + */ + private class ArithmeticOperationBarrier extends Barrier { + ArithmeticOperationBarrier() { + // binary operations (e.g. `a + b`, `a ^ b`) + this.asExpr() = any(BinaryArithmeticOperation a).getAnOperand() + or + this.asExpr() = any(BinaryBitwiseOperation a).getAnOperand() + or + // compound assignments (e.g. `a += b`, `a ^= b`) + this.asExpr() = any(AssignArithmeticOperation a).getAnOperand() + or + this.asExpr() = any(AssignBitwiseOperation a).getAnOperand() + } + } } diff --git a/rust/ql/src/change-notes/2026-06-25-hard-coded-cryptographic-value-arithmetic-barrier.md b/rust/ql/src/change-notes/2026-06-25-hard-coded-cryptographic-value-arithmetic-barrier.md new file mode 100644 index 00000000000..bee0af58314 --- /dev/null +++ b/rust/ql/src/change-notes/2026-06-25-hard-coded-cryptographic-value-arithmetic-barrier.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The `rust/hard-coded-cryptographic-value` query now treats arithmetic and bitwise operations, including string append operations, as barriers. This addresses false positive results where hard-coded constants are combined with non-constant data, such as incrementing a nonce or appending variable data to a constant prefix. diff --git a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected index f416e2b7b38..f3dfe9220a4 100644 --- a/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected +++ b/rust/ql/test/query-tests/security/CWE-798/HardcodedCryptographicValue.expected @@ -10,45 +10,50 @@ | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:21:28:21:34 | [0; 64] | test_cookie.rs:22:16:22:24 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:22:16:22:24 | ...::from | a key | | test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:42:14:42:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:42:14:42:32 | ...::from | a key | | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:53:14:53:32 | ...::from | This hard-coded value is used as $@. | test_cookie.rs:53:14:53:32 | ...::from | a key | -| test_heuristic.rs:44:31:44:38 | [0u8; 16] | test_heuristic.rs:44:31:44:38 | [0u8; 16] | test_heuristic.rs:45:41:45:48 | const_iv | This hard-coded value is used as $@. | test_heuristic.rs:45:41:45:48 | const_iv | an initialization vector | -| test_heuristic.rs:63:30:63:37 | "secret" | test_heuristic.rs:63:30:63:37 | "secret" | test_heuristic.rs:63:30:63:37 | "secret" | This hard-coded value is used as $@. | test_heuristic.rs:63:30:63:37 | "secret" | a password | -| test_heuristic.rs:64:20:64:27 | [0u8; 16] | test_heuristic.rs:64:20:64:27 | [0u8; 16] | test_heuristic.rs:64:19:64:27 | &... | This hard-coded value is used as $@. | test_heuristic.rs:64:19:64:27 | &... | a nonce | -| test_heuristic.rs:65:31:65:38 | [0u8; 16] | test_heuristic.rs:65:31:65:38 | [0u8; 16] | test_heuristic.rs:65:30:65:38 | &... | This hard-coded value is used as $@. | test_heuristic.rs:65:30:65:38 | &... | a salt | -| test_heuristic.rs:67:22:67:22 | 0 | test_heuristic.rs:67:22:67:22 | 0 | test_heuristic.rs:67:22:67:22 | 0 | This hard-coded value is used as $@. | test_heuristic.rs:67:22:67:22 | 0 | a salt | -| test_heuristic.rs:69:32:69:32 | 1 | test_heuristic.rs:69:32:69:32 | 1 | test_heuristic.rs:69:22:69:32 | ... + ... | This hard-coded value is used as $@. | test_heuristic.rs:69:22:69:32 | ... + ... | a salt | -| test_heuristic.rs:70:34:70:35 | 32 | test_heuristic.rs:70:34:70:35 | 32 | test_heuristic.rs:70:22:70:62 | ... ^ ... | This hard-coded value is used as $@. | test_heuristic.rs:70:22:70:62 | ... ^ ... | a salt | -| test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | test_heuristic.rs:70:22:70:62 | ... ^ ... | This hard-coded value is used as $@. | test_heuristic.rs:70:22:70:62 | ... ^ ... | a salt | +| test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | This hard-coded value is used as $@. | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | a salt | +| test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | This hard-coded value is used as $@. | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | a salt | +| test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | This hard-coded value is used as $@. | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | a salt | +| test_heuristic.rs:49:31:49:38 | [0u8; 16] | test_heuristic.rs:49:31:49:38 | [0u8; 16] | test_heuristic.rs:50:41:50:48 | const_iv | This hard-coded value is used as $@. | test_heuristic.rs:50:41:50:48 | const_iv | an initialization vector | +| test_heuristic.rs:68:30:68:37 | "secret" | test_heuristic.rs:68:30:68:37 | "secret" | test_heuristic.rs:68:30:68:37 | "secret" | This hard-coded value is used as $@. | test_heuristic.rs:68:30:68:37 | "secret" | a password | +| test_heuristic.rs:69:20:69:27 | [0u8; 16] | test_heuristic.rs:69:20:69:27 | [0u8; 16] | test_heuristic.rs:69:19:69:27 | &... | This hard-coded value is used as $@. | test_heuristic.rs:69:19:69:27 | &... | a nonce | +| test_heuristic.rs:70:31:70:38 | [0u8; 16] | test_heuristic.rs:70:31:70:38 | [0u8; 16] | test_heuristic.rs:70:30:70:38 | &... | This hard-coded value is used as $@. | test_heuristic.rs:70:30:70:38 | &... | a salt | +| test_heuristic.rs:72:22:72:22 | 0 | test_heuristic.rs:72:22:72:22 | 0 | test_heuristic.rs:72:22:72:22 | 0 | This hard-coded value is used as $@. | test_heuristic.rs:72:22:72:22 | 0 | a salt | +| test_heuristic.rs:76:22:76:27 | ... << ... | test_heuristic.rs:76:22:76:27 | ... << ... | test_heuristic.rs:76:22:76:27 | ... << ... | This hard-coded value is used as $@. | test_heuristic.rs:76:22:76:27 | ... << ... | a salt | +| test_heuristic.rs:78:22:78:29 | ...::MAX | test_heuristic.rs:78:22:78:29 | ...::MAX | test_heuristic.rs:78:22:78:29 | ...::MAX | This hard-coded value is used as $@. | test_heuristic.rs:78:22:78:29 | ...::MAX | a salt | +| test_heuristic.rs:79:22:79:33 | ... / ... | test_heuristic.rs:79:22:79:33 | ... / ... | test_heuristic.rs:79:22:79:33 | ... / ... | This hard-coded value is used as $@. | test_heuristic.rs:79:22:79:33 | ... / ... | a salt | +| test_heuristic.rs:86:29:86:32 | 1u64 | test_heuristic.rs:86:29:86:32 | 1u64 | test_heuristic.rs:87:22:87:31 | MY_CONST_5 | This hard-coded value is used as $@. | test_heuristic.rs:87:22:87:31 | MY_CONST_5 | a salt | +| test_heuristic.rs:88:29:88:33 | ... + ... | test_heuristic.rs:88:29:88:33 | ... + ... | test_heuristic.rs:89:22:89:31 | MY_CONST_6 | This hard-coded value is used as $@. | test_heuristic.rs:89:22:89:31 | MY_CONST_6 | a salt | edges | test_cipher.rs:18:9:18:14 | const1 [&ref] | test_cipher.rs:19:73:19:78 | const1 [&ref] | provenance | | | test_cipher.rs:18:28:18:36 | &... [&ref] | test_cipher.rs:18:9:18:14 | const1 [&ref] | provenance | | | test_cipher.rs:18:29:18:36 | [0u8; 16] | test_cipher.rs:18:28:18:36 | &... [&ref] | provenance | | | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | test_cipher.rs:19:30:19:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | -| test_cipher.rs:19:73:19:78 | const1 [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | provenance | MaD:17 | +| test_cipher.rs:19:73:19:78 | const1 [&ref] | test_cipher.rs:19:49:19:79 | ...::from_slice(...) [&ref] | provenance | MaD:13 | | test_cipher.rs:25:9:25:14 | const4 [&ref] | test_cipher.rs:26:66:26:71 | const4 [&ref] | provenance | | | test_cipher.rs:25:28:25:36 | &... [&ref] | test_cipher.rs:25:9:25:14 | const4 [&ref] | provenance | | | test_cipher.rs:25:29:25:36 | [0u8; 16] | test_cipher.rs:25:28:25:36 | &... [&ref] | provenance | | | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | test_cipher.rs:26:30:26:40 | ...::new | provenance | MaD:4 Sink:MaD:4 | -| test_cipher.rs:26:66:26:71 | const4 [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | provenance | MaD:17 | +| test_cipher.rs:26:66:26:71 | const4 [&ref] | test_cipher.rs:26:42:26:72 | ...::from_slice(...) [&ref] | provenance | MaD:13 | | test_cipher.rs:29:9:29:14 | const5 [&ref] | test_cipher.rs:30:95:30:100 | const5 [&ref] | provenance | | | test_cipher.rs:29:28:29:36 | &... [&ref] | test_cipher.rs:29:9:29:14 | const5 [&ref] | provenance | | | test_cipher.rs:29:29:29:36 | [0u8; 16] | test_cipher.rs:29:28:29:36 | &... [&ref] | provenance | | | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | test_cipher.rs:30:30:30:40 | ...::new | provenance | MaD:5 Sink:MaD:5 | -| test_cipher.rs:30:95:30:100 | const5 [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | provenance | MaD:17 | +| test_cipher.rs:30:95:30:100 | const5 [&ref] | test_cipher.rs:30:72:30:101 | ...::from_slice(...) [&ref] | provenance | MaD:13 | | test_cipher.rs:37:9:37:14 | const7 | test_cipher.rs:38:74:38:79 | const7 | provenance | | | test_cipher.rs:37:27:37:74 | [...] | test_cipher.rs:37:9:37:14 | const7 | provenance | | | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | test_cipher.rs:38:30:38:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | -| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:17 | +| test_cipher.rs:38:73:38:79 | &const7 [&ref] | test_cipher.rs:38:49:38:80 | ...::from_slice(...) [&ref] | provenance | MaD:13 | | test_cipher.rs:38:74:38:79 | const7 | test_cipher.rs:38:73:38:79 | &const7 [&ref] | provenance | | | test_cipher.rs:41:9:41:14 | const8 [&ref] | test_cipher.rs:42:73:42:78 | const8 [&ref] | provenance | | | test_cipher.rs:41:28:41:76 | &... [&ref] | test_cipher.rs:41:9:41:14 | const8 [&ref] | provenance | | | test_cipher.rs:41:29:41:76 | [...] | test_cipher.rs:41:28:41:76 | &... [&ref] | provenance | | | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | test_cipher.rs:42:30:42:47 | ...::new | provenance | MaD:3 Sink:MaD:3 | -| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:17 | +| test_cipher.rs:42:73:42:78 | const8 [&ref] | test_cipher.rs:42:49:42:79 | ...::from_slice(...) [&ref] | provenance | MaD:13 | | test_cipher.rs:50:9:50:15 | const10 [element] | test_cipher.rs:51:75:51:81 | const10 [element] | provenance | | | test_cipher.rs:50:37:50:52 | ...::zeroed | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | provenance | Src:MaD:7 | | test_cipher.rs:50:37:50:54 | ...::zeroed(...) [element] | test_cipher.rs:50:9:50:15 | const10 [element] | provenance | | | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | test_cipher.rs:51:31:51:48 | ...::new | provenance | MaD:3 Sink:MaD:3 Sink:MaD:3 | -| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:17 | +| test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | test_cipher.rs:51:50:51:82 | ...::from_slice(...) [&ref, element] | provenance | MaD:13 | | test_cipher.rs:51:75:51:81 | const10 [element] | test_cipher.rs:51:74:51:81 | &const10 [&ref, element] | provenance | | | test_cipher.rs:73:9:73:14 | const2 [&ref] | test_cipher.rs:74:46:74:51 | const2 [&ref] | provenance | | | test_cipher.rs:73:18:73:26 | &... [&ref] | test_cipher.rs:73:9:73:14 | const2 [&ref] | provenance | | @@ -64,26 +69,27 @@ edges | test_cookie.rs:22:27:22:32 | array2 | test_cookie.rs:22:26:22:32 | &array2 [&ref] | provenance | | | test_cookie.rs:38:9:38:14 | array2 | test_cookie.rs:42:34:42:39 | array2 | provenance | | | test_cookie.rs:38:18:38:37 | ...::from(...) | test_cookie.rs:38:9:38:14 | array2 | provenance | | +| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:8 | +| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:9 | +| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:10 | +| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:11 | | test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:12 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:13 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:14 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:15 | -| test_cookie.rs:38:28:38:36 | [0u8; 64] | test_cookie.rs:38:18:38:37 | ...::from(...) | provenance | MaD:16 | | test_cookie.rs:42:34:42:39 | array2 | test_cookie.rs:42:14:42:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | | test_cookie.rs:49:9:49:14 | array3 [element] | test_cookie.rs:53:34:53:39 | array3 [element] | provenance | | -| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:18 | +| test_cookie.rs:49:23:49:25 | 0u8 | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | provenance | MaD:14 | | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | test_cookie.rs:49:9:49:14 | array3 [element] | provenance | | | test_cookie.rs:53:34:53:39 | array3 [element] | test_cookie.rs:53:14:53:32 | ...::from | provenance | MaD:2 Sink:MaD:2 | -| test_heuristic.rs:44:9:44:16 | const_iv [&ref] | test_heuristic.rs:45:41:45:48 | const_iv | provenance | | -| test_heuristic.rs:44:30:44:38 | &... [&ref] | test_heuristic.rs:44:9:44:16 | const_iv [&ref] | provenance | | -| test_heuristic.rs:44:31:44:38 | [0u8; 16] | test_heuristic.rs:44:30:44:38 | &... [&ref] | provenance | | -| test_heuristic.rs:64:20:64:27 | [0u8; 16] | test_heuristic.rs:64:19:64:27 | &... | provenance | | -| test_heuristic.rs:65:31:65:38 | [0u8; 16] | test_heuristic.rs:65:30:65:38 | &... | provenance | | -| test_heuristic.rs:69:32:69:32 | 1 | test_heuristic.rs:69:22:69:32 | ... + ... | provenance | MaD:8 | -| test_heuristic.rs:70:23:70:35 | ... << ... | test_heuristic.rs:70:22:70:62 | ... ^ ... | provenance | MaD:10 | -| test_heuristic.rs:70:34:70:35 | 32 | test_heuristic.rs:70:23:70:35 | ... << ... | provenance | MaD:11 | -| test_heuristic.rs:70:41:70:61 | ... & ... | test_heuristic.rs:70:22:70:62 | ... ^ ... | provenance | MaD:10 | -| test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | test_heuristic.rs:70:41:70:61 | ... & ... | provenance | MaD:9 | +| test_heuristic.rs:38:25:38:30 | 0xFFFF | test_heuristic.rs:81:22:81:31 | MY_CONST_1 | provenance | | +| test_heuristic.rs:39:25:39:59 | ... as u64 | test_heuristic.rs:82:22:82:31 | MY_CONST_2 | provenance | | +| test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | provenance | | +| test_heuristic.rs:40:27:40:32 | 0xFFFF | test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | provenance | | +| test_heuristic.rs:49:9:49:16 | const_iv [&ref] | test_heuristic.rs:50:41:50:48 | const_iv | provenance | | +| test_heuristic.rs:49:30:49:38 | &... [&ref] | test_heuristic.rs:49:9:49:16 | const_iv [&ref] | provenance | | +| test_heuristic.rs:49:31:49:38 | [0u8; 16] | test_heuristic.rs:49:30:49:38 | &... [&ref] | provenance | | +| test_heuristic.rs:69:20:69:27 | [0u8; 16] | test_heuristic.rs:69:19:69:27 | &... | provenance | | +| test_heuristic.rs:70:31:70:38 | [0u8; 16] | test_heuristic.rs:70:30:70:38 | &... | provenance | | +| test_heuristic.rs:86:29:86:32 | 1u64 | test_heuristic.rs:87:22:87:31 | MY_CONST_5 | provenance | | +| test_heuristic.rs:88:29:88:33 | ... + ... | test_heuristic.rs:89:22:89:31 | MY_CONST_6 | provenance | | models | 1 | Sink: <_ as crypto_common::KeyInit>::new_from_slice; Argument[0]; credentials-key | | 2 | Sink: ::from; Argument[0]; credentials-key | @@ -92,17 +98,13 @@ models | 5 | Sink: ::new; Argument[1]; credentials-iv | | 6 | Sink: ::from; Argument[0].Reference; credentials-key | | 7 | Source: core::mem::zeroed; ReturnValue.Element; constant-source | -| 8 | Summary: <_ as core::ops::arith::Add>::add; Argument[self,0]; ReturnValue; taint | -| 9 | Summary: <_ as core::ops::bit::BitAnd>::bitand; Argument[self,0]; ReturnValue; taint | -| 10 | Summary: <_ as core::ops::bit::BitXor>::bitxor; Argument[self,0]; ReturnValue; taint | -| 11 | Summary: <_ as core::ops::bit::Shl>::shl; Argument[self,0]; ReturnValue; taint | -| 12 | Summary: ::from; Argument[0].Field[alloc::borrow::Cow::Owned(0)]; ReturnValue; value | -| 13 | Summary: ::from; Argument[0].Field[alloc::bstr::ByteString(0)]; ReturnValue; value | -| 14 | Summary: ::from; Argument[0].Field[alloc::collections::binary_heap::BinaryHeap::data]; ReturnValue; value | -| 15 | Summary: ::from; Argument[0].Field[alloc::string::String::vec]; ReturnValue; value | -| 16 | Summary: ::from; Argument[0]; ReturnValue; taint | -| 17 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | -| 18 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | +| 8 | Summary: ::from; Argument[0].Field[alloc::borrow::Cow::Owned(0)]; ReturnValue; value | +| 9 | Summary: ::from; Argument[0].Field[alloc::bstr::ByteString(0)]; ReturnValue; value | +| 10 | Summary: ::from; Argument[0].Field[alloc::collections::binary_heap::BinaryHeap::data]; ReturnValue; value | +| 11 | Summary: ::from; Argument[0].Field[alloc::string::String::vec]; ReturnValue; value | +| 12 | Summary: ::from; Argument[0]; ReturnValue; taint | +| 13 | Summary: ::from_slice; Argument[0].Reference; ReturnValue.Reference; value | +| 14 | Summary: alloc::vec::from_elem; Argument[0]; ReturnValue.Element; value | nodes | test_cipher.rs:18:9:18:14 | const1 [&ref] | semmle.label | const1 [&ref] | | test_cipher.rs:18:28:18:36 | &... [&ref] | semmle.label | &... [&ref] | @@ -166,21 +168,28 @@ nodes | test_cookie.rs:49:23:49:29 | ...::from_elem(...) [element] | semmle.label | ...::from_elem(...) [element] | | test_cookie.rs:53:14:53:32 | ...::from | semmle.label | ...::from | | test_cookie.rs:53:34:53:39 | array3 [element] | semmle.label | array3 [element] | -| test_heuristic.rs:44:9:44:16 | const_iv [&ref] | semmle.label | const_iv [&ref] | -| test_heuristic.rs:44:30:44:38 | &... [&ref] | semmle.label | &... [&ref] | -| test_heuristic.rs:44:31:44:38 | [0u8; 16] | semmle.label | [0u8; 16] | -| test_heuristic.rs:45:41:45:48 | const_iv | semmle.label | const_iv | -| test_heuristic.rs:63:30:63:37 | "secret" | semmle.label | "secret" | -| test_heuristic.rs:64:19:64:27 | &... | semmle.label | &... | -| test_heuristic.rs:64:20:64:27 | [0u8; 16] | semmle.label | [0u8; 16] | -| test_heuristic.rs:65:30:65:38 | &... | semmle.label | &... | -| test_heuristic.rs:65:31:65:38 | [0u8; 16] | semmle.label | [0u8; 16] | -| test_heuristic.rs:67:22:67:22 | 0 | semmle.label | 0 | -| test_heuristic.rs:69:22:69:32 | ... + ... | semmle.label | ... + ... | -| test_heuristic.rs:69:32:69:32 | 1 | semmle.label | 1 | -| test_heuristic.rs:70:22:70:62 | ... ^ ... | semmle.label | ... ^ ... | -| test_heuristic.rs:70:23:70:35 | ... << ... | semmle.label | ... << ... | -| test_heuristic.rs:70:34:70:35 | 32 | semmle.label | 32 | -| test_heuristic.rs:70:41:70:61 | ... & ... | semmle.label | ... & ... | -| test_heuristic.rs:70:52:70:61 | 0xFFFFFFFF | semmle.label | 0xFFFFFFFF | +| test_heuristic.rs:38:25:38:30 | 0xFFFF | semmle.label | 0xFFFF | +| test_heuristic.rs:39:25:39:59 | ... as u64 | semmle.label | ... as u64 | +| test_heuristic.rs:39:62:40:33 | static MY_STATIC_3 | semmle.label | static MY_STATIC_3 | +| test_heuristic.rs:40:27:40:32 | 0xFFFF | semmle.label | 0xFFFF | +| test_heuristic.rs:49:9:49:16 | const_iv [&ref] | semmle.label | const_iv [&ref] | +| test_heuristic.rs:49:30:49:38 | &... [&ref] | semmle.label | &... [&ref] | +| test_heuristic.rs:49:31:49:38 | [0u8; 16] | semmle.label | [0u8; 16] | +| test_heuristic.rs:50:41:50:48 | const_iv | semmle.label | const_iv | +| test_heuristic.rs:68:30:68:37 | "secret" | semmle.label | "secret" | +| test_heuristic.rs:69:19:69:27 | &... | semmle.label | &... | +| test_heuristic.rs:69:20:69:27 | [0u8; 16] | semmle.label | [0u8; 16] | +| test_heuristic.rs:70:30:70:38 | &... | semmle.label | &... | +| test_heuristic.rs:70:31:70:38 | [0u8; 16] | semmle.label | [0u8; 16] | +| test_heuristic.rs:72:22:72:22 | 0 | semmle.label | 0 | +| test_heuristic.rs:76:22:76:27 | ... << ... | semmle.label | ... << ... | +| test_heuristic.rs:78:22:78:29 | ...::MAX | semmle.label | ...::MAX | +| test_heuristic.rs:79:22:79:33 | ... / ... | semmle.label | ... / ... | +| test_heuristic.rs:81:22:81:31 | MY_CONST_1 | semmle.label | MY_CONST_1 | +| test_heuristic.rs:82:22:82:31 | MY_CONST_2 | semmle.label | MY_CONST_2 | +| test_heuristic.rs:83:22:83:32 | MY_STATIC_3 | semmle.label | MY_STATIC_3 | +| test_heuristic.rs:86:29:86:32 | 1u64 | semmle.label | 1u64 | +| test_heuristic.rs:87:22:87:31 | MY_CONST_5 | semmle.label | MY_CONST_5 | +| test_heuristic.rs:88:29:88:33 | ... + ... | semmle.label | ... + ... | +| test_heuristic.rs:89:22:89:31 | MY_CONST_6 | semmle.label | MY_CONST_6 | subpaths diff --git a/rust/ql/test/query-tests/security/CWE-798/test_heuristic.rs b/rust/ql/test/query-tests/security/CWE-798/test_heuristic.rs index f8f16a16d12..dca4272a988 100644 --- a/rust/ql/test/query-tests/security/CWE-798/test_heuristic.rs +++ b/rust/ql/test/query-tests/security/CWE-798/test_heuristic.rs @@ -35,6 +35,11 @@ impl MyCryptor { } } +const MY_CONST_1: u64 = 0xFFFF; // $ Alert[rust/hard-coded-cryptographic-value] +const MY_CONST_2: u64 = std::env::consts::ARCH.len() as u64; // $ Alert[rust/hard-coded-cryptographic-value] +static MY_STATIC_3: u64 = 0xFFFF; // $ Alert[rust/hard-coded-cryptographic-value] +static MY_STATIC_4: u64 = std::env::consts::ARCH.len() as u64; + fn test(var_string: &str, var_data: &[u8;16], var_u64: u64) { encrypt_with("plaintext", var_data, var_data); @@ -66,6 +71,32 @@ fn test(var_string: &str, var_data: &[u8;16], var_u64: u64) { mc2.set_salt_u64(0); // $ Alert[rust/hard-coded-cryptographic-value] mc2.set_salt_u64(var_u64); - mc2.set_salt_u64(var_u64 + 1); // $ SPURIOUS: Alert[rust/hard-coded-cryptographic-value] - mc2.set_salt_u64((var_u64 << 32) ^ (var_u64 & 0xFFFFFFFF)); // $ SPURIOUS: Alert[rust/hard-coded-cryptographic-value] + mc2.set_salt_u64(var_u64 + 1); + mc2.set_salt_u64((var_u64 << 32) ^ (var_u64 & 0xFFFFFFFF)); + mc2.set_salt_u64(1 << 4); // $ Alert[rust/hard-coded-cryptographic-value] + + mc2.set_salt_u64(u64::MAX); // $ Alert[rust/hard-coded-cryptographic-value] + mc2.set_salt_u64(u64::MAX / 4); // $ Alert[rust/hard-coded-cryptographic-value] + + mc2.set_salt_u64(MY_CONST_1); // $ Sink[rust/hard-coded-cryptographic-value] + mc2.set_salt_u64(MY_CONST_2); // $ Sink[rust/hard-coded-cryptographic-value] + mc2.set_salt_u64(MY_STATIC_3); // $ Sink[rust/hard-coded-cryptographic-value] + mc2.set_salt_u64(MY_STATIC_4); + + const MY_CONST_5: u64 = 1u64; // $ Alert[rust/hard-coded-cryptographic-value] + mc2.set_salt_u64(MY_CONST_5); // $ Sink[rust/hard-coded-cryptographic-value] + const MY_CONST_6: u64 = 2 + 3; // $ Alert[rust/hard-coded-cryptographic-value] + mc2.set_salt_u64(MY_CONST_6); // $ Sink[rust/hard-coded-cryptographic-value] + + let mut key1 = "foo".to_string(); // $ MISSING: Alert[rust/hard-coded-cryptographic-value] + key1 += "bar"; // $ MISSING: Alert[rust/hard-coded-cryptographic-value] + let _ = MyCryptor::new(&key1); + + let mut key2 = "foo".to_string(); + key2 += var_string; + let _ = MyCryptor::new(&key2); + + let mut key3 = var_string.to_string(); + key3 += "bar"; + let _ = MyCryptor::new(&key3); }