diff --git a/README.md b/README.md index 0e8be06..a1fc765 100644 --- a/README.md +++ b/README.md @@ -64,25 +64,32 @@ as an example: object Metrics extends QueryBundle { @q - def tooManyParameters(n: Int = 4): Query = Query( - name = "too-many-parameters", - title = s"Number of parameters larger than $n", - description = - s"This query identifies functions with more than $n formal parameters", - score = 2.0, traversal = { cpg => - cpg.method.filter(_.parameter.size > n) - } - ) + def tooManyParameters(n: Int = 4): Query = + Query.make( + name = "too-many-params", + author = Crew.fabs, + title = s"Number of parameters larger than $n", + description = s"This query identifies functions with more than $n formal parameters", + score = 1.0, + withStrRep({ cpg => + cpg.method.internal.filter(_.parameter.size > n) + }), + tags = List(QueryTags.metrics) + ) @q - def tooHighComplexity(n: Int = 4): Query = Query( - title = s"Cyclomatic complexity higher than $n", - description = - s"This query identifies functions with a cyclomatic complexity higher than $n", - score = 2.0, traversal = { cpg => - cpg.method.filter(_.controlStructure.size > n) - } - ) + def tooHighComplexity(n: Int = 4): Query = + Query.make( + name = "too-high-complexity", + author = Crew.fabs, + title = s"Cyclomatic complexity higher than $n", + description = s"This query identifies functions with a cyclomatic complexity higher than $n", + score = 1.0, + withStrRep({ cpg => + cpg.method.internal.filter(_.controlStructure.size > n) + }), + tags = List(QueryTags.metrics) + ) ... } ``` diff --git a/project/Versions.scala b/project/Versions.scala index 63e1762..55ef54f 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -1,4 +1,4 @@ /* Declare dependency versions in one place */ object Versions { - val cpg = "1.3.99" + val cpg = "1.3.102" } diff --git a/src/main/scala/io/joern/scanners/c/CopyLoops.scala b/src/main/scala/io/joern/scanners/c/CopyLoops.scala index 824479b..3c45f9e 100644 --- a/src/main/scala/io/joern/scanners/c/CopyLoops.scala +++ b/src/main/scala/io/joern/scanners/c/CopyLoops.scala @@ -9,17 +9,19 @@ object CopyLoops extends QueryBundle { @q def isCopyLoop(): Query = - queryInit( - "copy-loop", - Crew.fabs, - "Copy loop detected", - """ + Query.make( + name = "copy-loop", + author = Crew.fabs, + title = "Copy loop detected", + description = + """ |For (buf, indices) pairs, determine those inside control structures (for, while, if ...) |where any of the calls made outside of the body (block) are Inc operations. Determine |the first argument of that Inc operation and check if they are used as indices for |the write operation into the buffer. |""".stripMargin, - 2, { cpg => + score = 2, + withStrRep({ cpg => cpg.assignment.target.isArrayAccess .map { access => (access.array, access.subscripts.code.toSet) @@ -35,8 +37,7 @@ object CopyLoops extends QueryBundle { (incIdentifiers & subscripts).nonEmpty } .map(_._1) - }, - List() + }), ) } diff --git a/src/main/scala/io/joern/scanners/c/CredentialDrop.scala b/src/main/scala/io/joern/scanners/c/CredentialDrop.scala index 9d36aad..38c65ab 100644 --- a/src/main/scala/io/joern/scanners/c/CredentialDrop.scala +++ b/src/main/scala/io/joern/scanners/c/CredentialDrop.scala @@ -11,44 +11,49 @@ object CredentialDrop extends QueryBundle { @q def userCredDrop(): Query = - queryInit( - "setuid-without-setgid", - Crew.malte, - "Process user ID is changed without changing groups first", - """ + Query.make( + name = "setuid-without-setgid", + author = Crew.malte, + title = "Process user ID is changed without changing groups first", + description = + """ |The set*uid system calls do not affect the groups a process belongs to. However, often |there exists a group that is equivalent to a user (e.g. wheel or shadow groups are often |equivalent to the root user). |Group membership can only be changed by the root user. |Changes to the user should therefore always be preceded by calls to set*gid and setgroups, |""".stripMargin, - 2, { cpg => + score = 2, + withStrRep({ cpg => cpg .method("set(res|re|e|)uid") .callIn .whereNot(_.dominatedBy.isCall.name("set(res|re|e|)?gid")) - }, - List(QueryTags.setxid) + }), + tags = List(QueryTags.setxid) ) @q def groupCredDrop(): Query = - queryInit( - "setgid-without-setgroups", - Crew.malte, - "Process group membership is changed without setting ancillary groups first", - """ + Query.make( + name = "setgid-without-setgroups", + author = Crew.malte, + title = + "Process group membership is changed without setting ancillary groups first", + description = + """ |The set*gid system calls do not affect the ancillary groups a process belongs to. |Changes to the group membership should therefore always be preceded by a call to setgroups. |Otherwise the process may still be a secondary member of the group it tries to disavow. |""".stripMargin, - 2, { cpg => + score = 2, + withStrRep({ cpg => cpg .method("set(res|re|e|)gid") .callIn .whereNot(_.dominatedBy.isCall.name("setgroups")) - }, - List(QueryTags.setxid) + }), + tags = List(QueryTags.setxid) ) } diff --git a/src/main/scala/io/joern/scanners/c/DangerousFunctions.scala b/src/main/scala/io/joern/scanners/c/DangerousFunctions.scala index e3a213d..cf285f3 100644 --- a/src/main/scala/io/joern/scanners/c/DangerousFunctions.scala +++ b/src/main/scala/io/joern/scanners/c/DangerousFunctions.scala @@ -11,33 +11,37 @@ object DangerousFunctions extends QueryBundle { @q def getsUsed(): Query = - queryInit( - "call-to-gets", - Crew.suchakra, - "Dangerous function gets() used", - """ + Query.make( + name = "call-to-gets", + author = Crew.suchakra, + title = "Dangerous function gets() used", + description = + """ | Avoid `gets` function as it can lead to reads beyond buffer | boundary and cause | buffer overflows. Some secure alternatives are `fgets` and `gets_s`. |""".stripMargin, - 8, { cpg => + score = 8, + withStrRep({ cpg => cpg.method("gets").callIn - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) @q def argvUsedInPrintf(): Query = - queryInit( - "format-controlled-printf", - Crew.suchakra, - "Non-constant format string passed to printf/sprintf/vsprintf", - """ + Query.make( + name = "format-controlled-printf", + author = Crew.suchakra, + title = "Non-constant format string passed to printf/sprintf/vsprintf", + description = + """ | Avoid user controlled format strings like "argv" in printf, sprintf and vsprintf | functions as they can cause memory corruption. Some secure | alternatives are `snprintf` and `vsnprintf`. |""".stripMargin, - 4, { cpg => + score = 4, + withStrRep({ cpg => cpg .method("printf") .callIn @@ -46,94 +50,104 @@ object DangerousFunctions extends QueryBundle { .method("(sprintf|vsprintf)") .callIn .whereNot(_.argument.order(2).isLiteral) - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) @q def scanfUsed(): Query = - queryInit( - "call-to-scanf", - Crew.suchakra, - "Insecure function scanf() used", - """ + Query.make( + name = "call-to-scanf", + author = Crew.suchakra, + title = "Insecure function scanf() used", + description = + """ | Avoid `scanf` function as it can lead to reads beyond buffer | boundary and cause buffer overflows. A secure alternative is `fgets`. |""".stripMargin, - 4, { cpg => + score = 4, + withStrRep({ cpg => cpg.method("scanf").callIn - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) @q def strcatUsed(): Query = - queryInit( - "call-to-strcat", - Crew.suchakra, - "Dangerous functions `strcat` or `strncat` used", - """ + Query.make( + name = "call-to-strcat", + author = Crew.suchakra, + title = "Dangerous functions `strcat` or `strncat` used", + description = + """ | Avoid `strcat` or `strncat` functions. These can be used insecurely | causing non null-termianted strings leading to memory corruption. | A secure alternative is `strcat_s`. |""".stripMargin, - 4, { cpg => + score = 4, + withStrRep({ cpg => cpg.method("(strcat|strncat)").callIn - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) @q def strcpyUsed(): Query = - queryInit( - "call-to-strcpy", - Crew.suchakra, - "Dangerous functions `strcpy` or `strncpy` used", - """ + Query.make( + name = "call-to-strcpy", + author = Crew.suchakra, + title = "Dangerous functions `strcpy` or `strncpy` used", + description = + """ | Avoid `strcpy` or `strncpy` function. `strcpy` does not check buffer | lengths. | A possible mitigation could be `strncpy` which could prevent | buffer overflows but does not null-terminate strings leading to | memory corruption. A secure alternative (on BSD) is `strlcpy`. |""".stripMargin, - 4, { cpg => + score = 4, + withStrRep({ cpg => cpg.method("(strcpy|strncpy)").callIn - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) @q def strtokUsed(): Query = - queryInit( - "call-to-strtok", - Crew.suchakra, - "Dangerous function strtok() used", - """ + Query.make( + name = "call-to-strtok", + author = Crew.suchakra, + title = "Dangerous function strtok() used", + description = + """ | Avoid `strtok` function as it modifies the original string in place | and appends a null character after each token. This makes the | original string unsafe. Suggested alternative is `strtok_r` with | `saveptr`. |""".stripMargin, - 4, { cpg => + score = 4, + withStrRep({ cpg => cpg.method("strtok").callIn - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) @q def getwdUsed(): Query = - queryInit( - "call-to-getwd", - Crew.claudiu, - "Dangerous function getwd() used", - """ + Query.make( + name = "call-to-getwd", + author = Crew.claudiu, + title = "Dangerous function getwd() used", + description = + """ | Avoid the `getwd` function, it does not check buffer lengths. | Use `getcwd` instead, as it checks the buffer size. |""".stripMargin, - 4, { cpg => + score = 4, + withStrRep({ cpg => cpg.method("getwd").callIn - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) } diff --git a/src/main/scala/io/joern/scanners/c/HeapBasedOverflow.scala b/src/main/scala/io/joern/scanners/c/HeapBasedOverflow.scala index c8b3ff0..7a4b3a4 100644 --- a/src/main/scala/io/joern/scanners/c/HeapBasedOverflow.scala +++ b/src/main/scala/io/joern/scanners/c/HeapBasedOverflow.scala @@ -20,12 +20,13 @@ object HeapBasedOverflow extends QueryBundle { * */ @q def mallocMemcpyIntOverflow()(implicit context: EngineContext): Query = - queryInit( - "malloc-memcpy-int-overflow", - Crew.fabs, - "Dangerous copy-operation into heap-allocated buffer", - "-", - 4, { cpg => + Query.make( + name = "malloc-memcpy-int-overflow", + author = Crew.fabs, + title = "Dangerous copy-operation into heap-allocated buffer", + description = "-", + score = 4, + withStrRep({ cpg => val src = cpg .method(".*malloc$") .callIn @@ -45,8 +46,8 @@ object HeapBasedOverflow extends QueryBundle { .whereNot(_.argument(1).codeExact(memcpyCall.argument(3).code)) .hasNext } - }, - List(QueryTags.integers) + }), + tags = List(QueryTags.integers) ) } diff --git a/src/main/scala/io/joern/scanners/c/IntegerTruncations.scala b/src/main/scala/io/joern/scanners/c/IntegerTruncations.scala index c485492..8af562b 100644 --- a/src/main/scala/io/joern/scanners/c/IntegerTruncations.scala +++ b/src/main/scala/io/joern/scanners/c/IntegerTruncations.scala @@ -16,24 +16,26 @@ object IntegerTruncations extends QueryBundle { * */ @q def strlenAssignmentTruncations(): Query = - queryInit( - "strlen-truncation", - Crew.fabs, - "Truncation in assignment involving `strlen` call", - """ + Query.make( + name = "strlen-truncation", + author = Crew.fabs, + title = "Truncation in assignment involving `strlen` call", + description = + """ |The return value of `strlen` is stored in a variable that is known |to be of type `int` as opposed to `size_t`. `int` is only 32 bit |wide on many 64 bit platforms, and thus, this may result in a |truncation. |""".stripMargin, - 2, { cpg => + score = 2, + withStrRep({ cpg => cpg .method("strlen") .callIn .inAssignment .target .evalType("(g?)int") - }, - List(QueryTags.integers) + }), + tags = List(QueryTags.integers) ) } diff --git a/src/main/scala/io/joern/scanners/c/Metrics.scala b/src/main/scala/io/joern/scanners/c/Metrics.scala index 6fb9166..0c00a56 100644 --- a/src/main/scala/io/joern/scanners/c/Metrics.scala +++ b/src/main/scala/io/joern/scanners/c/Metrics.scala @@ -9,84 +9,94 @@ object Metrics extends QueryBundle { @q def tooManyParameters(n: Int = 4): Query = - queryInit( - "too-many-params", - Crew.fabs, - s"Number of parameters larger than $n", - s"This query identifies functions with more than $n formal parameters", - 1.0, { cpg => + Query.make( + name = "too-many-params", + author = Crew.fabs, + title = s"Number of parameters larger than $n", + description = + s"This query identifies functions with more than $n formal parameters", + score = 1.0, + withStrRep({ cpg => cpg.method.internal.filter(_.parameter.size > n) - }, - List(QueryTags.metrics) + }), + tags = List(QueryTags.metrics) ) @q def tooHighComplexity(n: Int = 4): Query = - queryInit( - "too-high-complexity", - Crew.fabs, - s"Cyclomatic complexity higher than $n", - s"This query identifies functions with a cyclomatic complexity higher than $n", - 1.0, { cpg => + Query.make( + name = "too-high-complexity", + author = Crew.fabs, + title = s"Cyclomatic complexity higher than $n", + description = + s"This query identifies functions with a cyclomatic complexity higher than $n", + score = 1.0, + withStrRep({ cpg => cpg.method.internal.filter(_.controlStructure.size > n) - }, - List(QueryTags.metrics) + }), + tags = List(QueryTags.metrics) ) @q def tooLong(n: Int = 1000): Query = - queryInit( - "too-long", - Crew.fabs, - s"More than $n lines", - s"This query identifies functions that are more than $n lines long", - 1.0, { cpg => + Query.make( + name = "too-long", + author = Crew.fabs, + title = s"More than $n lines", + description = + s"This query identifies functions that are more than $n lines long", + score = 1.0, + withStrRep({ cpg => cpg.method.internal.filter(_.numberOfLines > n) - }, - List(QueryTags.metrics) + }), + tags = List(QueryTags.metrics) ) @q def multipleReturns(): Query = - queryInit( - "multiple-returns", - Crew.fabs, - s"Multiple returns", - "This query identifies functions with more than one return", - 1.0, { cpg => + Query.make( + name = "multiple-returns", + author = Crew.fabs, + title = s"Multiple returns", + description = "This query identifies functions with more than one return", + score = 1.0, + withStrRep({ cpg => cpg.method.internal.filter(_.ast.isReturn.l.size > 1) - }, - List(QueryTags.metrics) + }), + tags = List(QueryTags.metrics) ) @q def tooManyLoops(n: Int = 4): Query = - queryInit( - "too-many-loops", - Crew.fabs, - s"More than $n loops", - s"This query identifies functions with more than $n loops", - 1.0, { cpg => + Query.make( + name = "too-many-loops", + author = Crew.fabs, + title = s"More than $n loops", + description = s"This query identifies functions with more than $n loops", + score = 1.0, + withStrRep({ cpg => cpg.method.internal .filter( _.ast.isControlStructure .parserTypeName("(For|Do|While).*") .size > n) - }, - List(QueryTags.metrics) + }), + tags = List(QueryTags.metrics) ) @q def tooNested(n: Int = 3): Query = - queryInit( - "too-nested", - Crew.fabs, - s"Nesting level higher than $n", - s"This query identifies functions with a nesting level higher than $n", - 1.0, { cpg => + Query.make( + name = "too-nested", + author = Crew.fabs, + title = s"Nesting level higher than $n", + description = + s"This query identifies functions with a nesting level higher than $n", + score = 1.0, + withStrRep({ cpg => cpg.method.internal.filter(_.depth(_.isControlStructure) > n) - }, - List(QueryTags.metrics) + }), + tags = List(QueryTags.metrics) ) } diff --git a/src/main/scala/io/joern/scanners/c/NullTermination.scala b/src/main/scala/io/joern/scanners/c/NullTermination.scala index 2de7114..014bce2 100644 --- a/src/main/scala/io/joern/scanners/c/NullTermination.scala +++ b/src/main/scala/io/joern/scanners/c/NullTermination.scala @@ -3,7 +3,7 @@ package io.joern.scanners.c import io.joern.scanners.{Crew, QueryTags} import io.shiftleft.semanticcpg.language._ import io.shiftleft.dataflowengineoss.language._ -import io.shiftleft.console.{Query, QueryBundle, q} +import io.shiftleft.console.{Query, QueryBundle, q, TraversalWithStrRep} import io.shiftleft.dataflowengineoss.queryengine.EngineContext import io.shiftleft.macros.QueryMacros._ @@ -13,11 +13,11 @@ object NullTermination extends QueryBundle { @q def strncpyNoNullTerm()(implicit engineContext: EngineContext): Query = - queryInit( - "strncpy-no-null-term", - Crew.fabs, - "strncpy is used and no null termination is nearby", - """ + Query.make( + name = "strncpy-no-null-term", + author = Crew.fabs, + title = "strncpy is used and no null termination is nearby", + description = """ | Upon calling `strncpy` with a source string that is larger | than the destination buffer, the destination buffer is not | null-terminated by `strncpy` and there is no explicit @@ -25,7 +25,8 @@ object NullTermination extends QueryBundle { | buffer size is at least 1 larger than the size passed | to `strncpy`. |""".stripMargin, - 4, { cpg => + score = 4, + withStrRep({ cpg => val allocations = cpg.method(".*malloc$").callIn.argument(1).l cpg .method("strncpy") @@ -44,8 +45,8 @@ object NullTermination extends QueryBundle { .isEmpty } .map(_._2) - }, - List(QueryTags.strings) + }), + tags = List(QueryTags.strings) ) } diff --git a/src/main/scala/io/joern/scanners/c/RetvalChecks.scala b/src/main/scala/io/joern/scanners/c/RetvalChecks.scala index bf8b2dd..47ebbb0 100644 --- a/src/main/scala/io/joern/scanners/c/RetvalChecks.scala +++ b/src/main/scala/io/joern/scanners/c/RetvalChecks.scala @@ -9,16 +9,18 @@ object RetvalChecks extends QueryBundle { @q def uncheckedReadRecvMalloc(): Query = - queryInit( - "unchecked-read-recv-malloc", - Crew.fabs, - "Unchecked read/recv/malloc", - """ + Query.make( + name = "unchecked-read-recv-malloc", + author = Crew.fabs, + title = "Unchecked read/recv/malloc", + description = + """ |The return value of a read/recv/malloc call is not checked directly and |the variable it has been assigned to (if any) does not |occur in any check within the caller. |""".stripMargin, - 3.0, { cpg => + score = 3.0, + withStrRep({ cpg => implicit val noResolve: NoResolve.type = NoResolve val callsNotDirectlyChecked = cpg .method("(read|recv|malloc)") @@ -37,8 +39,7 @@ object RetvalChecks extends QueryBundle { val targets = call.inAssignment.target.code.toSet (targets & checkedVars).nonEmpty } - }, - List() + }), ) } diff --git a/src/main/scala/io/joern/scanners/c/SignedLeftShift.scala b/src/main/scala/io/joern/scanners/c/SignedLeftShift.scala index a973367..6242ef4 100644 --- a/src/main/scala/io/joern/scanners/c/SignedLeftShift.scala +++ b/src/main/scala/io/joern/scanners/c/SignedLeftShift.scala @@ -10,21 +10,22 @@ object SignedLeftShift extends QueryBundle { @q def signedLeftShift(): Query = - queryInit( - "signed-left-shift", - Crew.malte, - "Signed Shift May Cause Undefined Behavior", - """ + Query.make( + name = "signed-left-shift", + author = Crew.malte, + title = "Signed Shift May Cause Undefined Behavior", + description = + """ |Signed integer overflow is undefined behavior. Shifts of signed values to the |left are very prone to overflow. |""".stripMargin, - 2, { cpg => + score = 2, + withStrRep({ cpg => cpg.call .nameExact(Operators.shiftLeft, Operators.assignmentShiftLeft) .where(_.argument(1).typ.fullNameExact("int", "long")) .filterNot(_.argument.isLiteral.size == 2) // assume such constant values produces a correct result - }, - List() + }), ) } diff --git a/src/main/scala/io/joern/scanners/c/UseAfterFree.scala b/src/main/scala/io/joern/scanners/c/UseAfterFree.scala index 0558bfc..ee1cab1 100644 --- a/src/main/scala/io/joern/scanners/c/UseAfterFree.scala +++ b/src/main/scala/io/joern/scanners/c/UseAfterFree.scala @@ -15,11 +15,12 @@ object UseAfterFree extends QueryBundle { @q def freeFieldNoReassign()(implicit context: EngineContext): Query = - queryInit( - "free-field-no-reassign", - Crew.fabs, - "A field of a parameter is free'd and not reassigned on all paths", - """ + Query.make( + name = "free-field-no-reassign", + author = Crew.fabs, + title = "A field of a parameter is free'd and not reassigned on all paths", + description = + """ | The function is able to modify a field of a structure passed in by | the caller. It frees this field and does not guarantee that on | all paths to the exit, the field is reassigned. If any @@ -28,7 +29,8 @@ object UseAfterFree extends QueryBundle { | or clear the entire structure, as in that case, it is unlikely that the | passed in structure will be used again. |""".stripMargin, - 5.0, { cpg => + score = 5.0, + withStrRep({ cpg => val freeOfStructField = cpg .method("free") .callIn @@ -50,17 +52,18 @@ object UseAfterFree extends QueryBundle { freeOfStructField.argument(1).filter { arg => arg.method.methodReturn.reachableBy(arg).nonEmpty } - }, - List(QueryTags.uaf) + }), + tags = List(QueryTags.uaf) ) @q def freeReturnedValue()(implicit context: EngineContext): Query = - queryInit( - "free-returned-value", - Crew.malte, - "A value that is returned through a parameter is free'd in a path", - """ + Query.make( + name = "free-returned-value", + author = Crew.malte, + title = "A value that is returned through a parameter is free'd in a path", + description = + """ |The function sets a field of a function parameter to a value of a local |variable. |This variable is then freed in some paths. Unless the value set in the @@ -69,7 +72,8 @@ object UseAfterFree extends QueryBundle { | |Finds bugs like CVE-2019-18902. |""".stripMargin, - 5.0, { cpg => + score = 5.0, + withStrRep({ cpg => def outParams = cpg.parameter .typeFullName(".+\\*") @@ -110,23 +114,25 @@ object UseAfterFree extends QueryBundle { case (id, freeCall) => freeCall.dominatedBy.exists(_ == id) } .flatMap(_._1) - }, - List(QueryTags.uaf) + }), + tags = List(QueryTags.uaf) ) @q def freePostDominatesUsage()(implicit context: EngineContext): Query = - queryInit( - "free-follows-value-reuse", - Crew.malte, - "A value that is free'd is reused without reassignment.", - """ + Query.make( + name = "free-follows-value-reuse", + author = Crew.malte, + title = "A value that is free'd is reused without reassignment.", + description = + """ |A value is used after being free'd in a path that leads to it |without reassignment. | |Modeled after CVE-2019-18903. |""".stripMargin, - 5.0, { cpg => + score = 5.0, + withStrRep({ cpg => cpg.method .name("(.*_)?free") .filter(_.parameter.size == 1) @@ -146,8 +152,8 @@ object UseAfterFree extends QueryBundle { .isIdentifier .codeExact(freedIdentifierCode) }) - }, - List(QueryTags.uaf) + }), + tags = List(QueryTags.uaf) ) } diff --git a/src/main/scala/io/joern/scanners/java/DangerousFunctions.scala b/src/main/scala/io/joern/scanners/java/DangerousFunctions.scala index 23c6958..5d93108 100644 --- a/src/main/scala/io/joern/scanners/java/DangerousFunctions.scala +++ b/src/main/scala/io/joern/scanners/java/DangerousFunctions.scala @@ -11,19 +11,22 @@ object DangerousFunctions extends QueryBundle { @q def execUsed(): Query = - queryInit( - "call-to-exec", - Crew.niko, - "Dangerous function 'java.lang.Runtime.exec:java.lang.Process(java.lang.String)' used", - """ + Query.make( + name = "call-to-exec", + author = Crew.niko, + title = + "Dangerous function 'java.lang.Runtime.exec:java.lang.Process(java.lang.String)' used", + description = + """ | A call to the function `java.lang.Runtime.exec:java.lang.Process(java.lang.String)` | could result in a potential remote code execution. |""".stripMargin, - 8, { cpg => + score = 8, + withStrRep({ cpg => cpg .method("java.lang.Runtime.exec") .callIn - }, - List(QueryTags.badfn) + }), + tags = List(QueryTags.badfn) ) }