Merge pull request #4329 from erik-krogh/DVSA

Approved by esbena
This commit is contained in:
CodeQL CI
2020-10-12 05:23:29 -07:00
committed by GitHub
16 changed files with 211 additions and 0 deletions

View File

@@ -3,6 +3,8 @@
## General improvements
* Support for the following frameworks and libraries has been improved:
- [AWS Serverless](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html)
- [Alibaba Serverless](https://www.alibabacloud.com/help/doc-detail/156876.htm)
- [bluebird](https://www.npmjs.com/package/bluebird)
- [express](https://www.npmjs.com/package/express)
- [fast-json-stable-stringify](https://www.npmjs.com/package/fast-json-stable-stringify)

View File

@@ -94,6 +94,7 @@ import semmle.javascript.frameworks.PropertyProjection
import semmle.javascript.frameworks.React
import semmle.javascript.frameworks.ReactNative
import semmle.javascript.frameworks.Request
import semmle.javascript.frameworks.ServerLess
import semmle.javascript.frameworks.ShellJS
import semmle.javascript.frameworks.SystemCommandExecutors
import semmle.javascript.frameworks.SQL

View File

@@ -0,0 +1,112 @@
/**
* Provides classes and predicates for working with serverless handlers.
* E.g. AWS: https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html
*/
import javascript
/**
* Provides classes and predicates for working with serverless handlers.
* In particular a `RemoteFlowSource` is added for AWS and Alibaba serverless.
*/
private module ServerLess {
/**
* Holds if the `.yml` file `ymlFile` contains a serverless configuration with `handler` and `codeURI` properties.
* `codeURI` defaults to the empty string if no explicit value is set in the configuration.
*/
private predicate hasServerlessHandler(File ymlFile, string handler, string codeURI) {
exists(YAMLMapping resource | ymlFile = resource.getFile() |
// There exists at least "AWS::Serverless::Function" and "Aliyun::Serverless::Function"
resource.lookup("Type").(YAMLScalar).getValue().regexpMatch(".*::Serverless::Function") and
exists(YAMLMapping properties | properties = resource.lookup("Properties") |
handler = properties.lookup("Handler").(YAMLScalar).getValue() and
if exists(properties.lookup("CodeUri"))
then codeURI = properties.lookup("CodeUri").(YAMLScalar).getValue()
else codeURI = ""
)
)
}
/**
* Gets a string where an ending "/." is simplified to "/" (if it exists).
*/
bindingset[base]
private string removeTrailingDot(string base) {
if base.regexpMatch(".*/\\.")
then result = base.substring(0, base.length() - 1)
else result = base
}
/**
* Gets a string where a leading "./" is simplified to "" (if it exists).
*/
bindingset[base]
private string removeLeadingDotSlash(string base) {
if base.regexpMatch("\\./.*") then result = base.substring(2, base.length()) else result = base
}
/**
* Gets a path to a file from a `codeURI` property and a file name from a serverless configuration.
*
* For example if `codeURI` is "function/." and `file` is "index", then the result becomes "function/index.js".
*/
bindingset[codeURI, file]
private string getPathFromHandlerProperties(string codeURI, string file) {
exists(string folder | folder = removeLeadingDotSlash(removeTrailingDot(codeURI)) |
result = folder + file + ".js"
)
}
/**
* Holds if `file` has a serverless handler function with name `func`.
*/
private predicate hasServerlessHandler(File file, string func) {
exists(File ymlFile, string handler, string codeURI, string fileName |
hasServerlessHandler(ymlFile, handler, codeURI) and
// Splits a `handler` into two components. The `fileName` to the left of the dot, and the `func` to the right.
// E.g. if `handler` is "index.foo", then `fileName` is "index" and `func` is "foo".
exists(string pattern | pattern = "(.*)\\.(.*)" |
fileName = handler.regexpCapture(pattern, 1) and
func = handler.regexpCapture(pattern, 2)
)
|
file.getAbsolutePath() =
ymlFile.getParentContainer().getAbsolutePath() + "/" +
getPathFromHandlerProperties(codeURI, fileName)
)
}
/**
* Gets a function that is a serverless request handler.
*
* For example: if an AWS serverless resource contains the following properties (in the "template.yml" file):
* ```yaml
* Handler: mylibrary.handler
* Runtime: nodejs12.x
* CodeUri: backend/src/
* ```
*
* And a file "mylibrary.js" exists in the folder "backend/src" (relative to the "template.yml" file).
* Then the result of this predicate is a function exported as "handler" from "mylibrary.js".
* The "mylibrary.js" file could for example look like:
*
* ```JavaScript
* module.exports.handler = function (event) { ... }
* ```
*/
private DataFlow::FunctionNode getAServerlessHandler() {
exists(File file, string handler, Module mod | hasServerlessHandler(file, handler) |
mod.getFile() = file and
result = mod.getAnExportedValue(handler).getAFunctionValue()
)
}
/**
* A serverless request handler event, seen as a RemoteFlowSource.
*/
private class ServerlessHandlerEventAsRemoteFlow extends RemoteFlowSource {
ServerlessHandlerEventAsRemoteFlow() { this = getAServerlessHandler().getParameter(0) }
override string getSourceType() { result = "Serverless event" }
}
}

View File

@@ -86,6 +86,9 @@ module CodeInjection {
|
this = c.getArgument(index)
)
or
// node-serialize is not intended to be safe for untrusted inputs
this = DataFlow::moduleMember("node-serialize", "unserialize").getACall().getArgument(0)
}
}

View File

@@ -0,0 +1,5 @@
| tst1/backend/src/mylibrary.js:1:36:1:40 | event |
| tst2/nodejs/index.js:1:36:1:40 | event |
| tst3/function/index.js:1:36:1:40 | event |
| tst4/app.js:1:36:1:40 | event |
| tst5/app.js:1:36:1:40 | event |

View File

@@ -0,0 +1,3 @@
import javascript
query RemoteFlowSource remoteFlow() { any() }

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,19 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: 'Serverless thing'
Globals:
Api:
Cors:
AllowMethods: "'*'"
AllowHeaders: "'*'"
AllowOrigin: "'*'"
Resources:
OrderManagerJsFunction:
Type: 'AWS::Serverless::Function'
Properties:
FunctionName: MY-SERVERLESS-THING
Handler: mylibrary.handler
Runtime: nodejs12.x
CodeUri: backend/src/

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,18 @@
Transform: 'Aliyun::Serverless-2018-04-03'
Resources:
fc-mongo:
Type: 'Aliyun::Serverless::Service'
Properties:
Description: MyServiceThing
nodejs:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: index.handler
Runtime: nodejs10
CodeUri: nodejs/
python:
Type: 'Aliyun::Serverless::Function'
Properties:
Handler: 'index.handler'
Runtime: python3
CodeUri: python/

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,10 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: An AWS Lambda application.
Resources:
function:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs12.x
CodeUri: function/.

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,12 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: A AWS Lambda function.
Resources:
helloworld:
Type: 'AWS::Serverless::Function'
Properties:
Handler: app.handler
Runtime: nodejs6.10
CodeUri: ./
Description: A AWS Lambda function.

View File

@@ -0,0 +1,3 @@
module.exports.handler = function (event) {
console.log(event);
}

View File

@@ -0,0 +1,11 @@
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: A AWS Lambda function.
Resources:
helloworld:
Type: 'AWS::Serverless::Function'
Properties:
Handler: app.handler
Runtime: nodejs6.10
Description: A AWS Lambda function.