Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement initial PoC for checking return values #846

Merged
merged 28 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
504966e
add new Op type GroupingOp
seelchen Aug 9, 2023
e597e47
first draft for translating `concepts` files into coko scripts
seelchen Aug 9, 2023
bf2939c
formatting and add comments
seelchen Aug 10, 2023
711ec97
move translation to own class and implement imports of concepts files
seelchen Aug 17, 2023
974a3ba
add the definition of the concepts files and implement some simple te…
seelchen Aug 17, 2023
7fedc5b
first draft for an evaluator that looks syntactically similar to conc…
seelchen Aug 18, 2023
7d01fe1
add concept of data items for modelling
seelchen Jun 9, 2023
0648657
rename file to have same name as class
seelchen Aug 24, 2023
c5a1ff4
continue development of whenever evaluator
seelchen Aug 24, 2023
4fb65e6
change the interface structure of DataItem, ConditionComponents and T…
seelchen Sep 4, 2023
0670594
start implementing the WheneverEvaluator for the cpg backend
seelchen Sep 4, 2023
c9d8cd1
add new type of Op that represents a dependency between two Ops
seelchen Sep 4, 2023
06ef4f1
add a implementation of the bsi-tr-rules interfaces for jca and a tes…
seelchen Sep 4, 2023
fbe5bed
formatting
seelchen Sep 8, 2023
06600c9
finish implementing cpgGetNodes for DataItems and change the return t…
seelchen Sep 8, 2023
32fd140
change CallAssertion to inherit from CallConditionComponent
seelchen Sep 8, 2023
e759cd6
implement toString functions for ConditionComponents
seelchen Sep 8, 2023
af9a6c7
implement some parts of the CpgWheneverEvaluator
seelchen Sep 8, 2023
d514843
change CpgWheneverEvaluator to be able to give more info in findings
seelchen Sep 8, 2023
201e11c
implement mode for JCACipherImpl
seelchen Sep 8, 2023
7717bc4
clean up and add comments/documentation
seelchen Sep 8, 2023
06bb894
add very simple test for WheneverEvaluator
seelchen Sep 8, 2023
f448458
Add fixes for CPG v8, Detekt and Spotless
fwendland Apr 11, 2024
7568e03
Merge branch 'main' into sl/concept-translator
fwendland Apr 11, 2024
9ec8694
Fix more detekt issues
fwendland Apr 11, 2024
3f38b66
update user feedback on wrong spec input
CodingDepot Apr 15, 2024
420a50f
Merge branch 'main' into sl/concept-translator
CodingDepot Apr 15, 2024
4ebf323
Merge branch 'main' into sl/concept-translator
fwendland Apr 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ package de.fraunhofer.aisec.codyze.backends.cpg.coko
import de.fraunhofer.aisec.codyze.backends.cpg.CPGBackend
import de.fraunhofer.aisec.codyze.backends.cpg.CPGConfiguration
import de.fraunhofer.aisec.codyze.backends.cpg.coko.dsl.*
import de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators.FollowsEvaluator
import de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators.NeverEvaluator
import de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators.OnlyEvaluator
import de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators.OrderEvaluator
import de.fraunhofer.aisec.codyze.backends.cpg.coko.evaluators.*
import de.fraunhofer.aisec.codyze.core.VersionProvider
import de.fraunhofer.aisec.codyze.core.backend.BackendConfiguration
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.CokoBackend
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.WheneverEvaluator
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.Condition
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.Op
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.Order
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.ConditionComponent
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.ordering.OrderToken
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.ordering.getOp
import de.fraunhofer.aisec.cpg.graph.Node
Expand Down Expand Up @@ -86,4 +86,13 @@ class CokoCpgBackend(config: BackendConfiguration) :
*/
override fun only(vararg ops: Op): OnlyEvaluator = OnlyEvaluator(ops.toList())
override fun never(vararg ops: Op): NeverEvaluator = NeverEvaluator(ops.toList())
override fun whenever(
premise: Condition.() -> ConditionComponent,
assertionBlock: WheneverEvaluator.() -> Unit
): WheneverEvaluator = CpgWheneverEvaluator(Condition().premise()).apply(assertionBlock)

override fun whenever(
premise: ConditionComponent,
assertionBlock: WheneverEvaluator.() -> Unit
): WheneverEvaluator = CpgWheneverEvaluator(premise).apply(assertionBlock)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2022, Fraunhofer AISEC. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.fraunhofer.aisec.codyze.backends.cpg.coko.dsl

import de.fraunhofer.aisec.codyze.backends.cpg.coko.Nodes
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.CokoBackend
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.ArgumentItem
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.DataItem
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.ReturnValueItem
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.Value
import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.declarations.VariableDeclaration
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference

/**
* Get all [Nodes] that are associated with this [DataItem].
*/
context(CokoBackend)
fun DataItem<*>.cpgGetAllNodes(): Nodes =
when (this@DataItem) {
is ReturnValueItem -> op.cpgGetAllNodes().flatMap { it.getVariableInNextDFGOrThis() }
is Value -> [email protected]()
is ArgumentItem -> op.cpgGetAllNodes().map { it.arguments[index] } // TODO: Do we count starting at 0 or 1?
}

/**
* Get all [Nodes] that are associated with this [DataItem].
*/
context(CokoBackend)
fun DataItem<*>.cpgGetNodes(): Nodes {
return when (this@DataItem) {
is ReturnValueItem -> op.cpgGetNodes().flatMap { it.getVariableInNextDFGOrThis() }
is Value -> [email protected]()
is ArgumentItem -> op.cpgGetNodes().map { it.arguments[index] } // TODO: Do we count starting at 0 or 1?
}
}

/**
* Get all [Nodes] that evaluate to the same value as [Value.value].
*/
context(CokoBackend)
private fun Value<*>.getNodes(): Nodes {
val value = this.value
return if (value is Node) {
listOf(value)
} else {
cpg.literals.filter { node ->
node.value == value
} + cpg.variables.filter { node ->
node.evaluate() == value
}
}
}

/**
* Returns all [VariableDeclaration]s and [DeclaredReferenceExpression]s that have a DFG edge from [this].
* If there are none, returns [this].
*/
private fun Node.getVariableInNextDFGOrThis(): Nodes =
this.nextDFG
.filter {
next ->
next is Reference || next is VariableDeclaration
}.ifEmpty { listOf(this) }
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,13 @@ import de.fraunhofer.aisec.codyze.backends.cpg.coko.Nodes
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.CokoBackend
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.CokoMarker
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.dsl.*
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.Definition
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.ParameterGroup
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.Signature
import de.fraunhofer.aisec.codyze.specificationLanguages.coko.core.modelling.*
import de.fraunhofer.aisec.cpg.TranslationResult
import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.declarations.ValueDeclaration
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.ConstructExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
import de.fraunhofer.aisec.cpg.query.dataFlow
import de.fraunhofer.aisec.cpg.query.executionPath

//
// all functions/properties defined here must use CokoBackend
Expand All @@ -42,19 +38,29 @@ val CokoBackend.cpg: TranslationResult

/** Get all [Nodes] that are associated with this [Op]. */
context(CokoBackend)
fun Op.cpgGetAllNodes(): Nodes =
fun Op.cpgGetAllNodes(): Collection<CallExpression> =
when (this@Op) {
is FunctionOp ->
[email protected] { def -> [email protected](def.fqn) }
is ConstructorOp -> [email protected](this.classFqn)
is GroupingOp -> [email protected] { it.cpgGetAllNodes() }
is ConditionalOp -> {
val resultNodes = resultOp.cpgGetAllNodes()
val conditionNodes = conditionOp.cpgGetAllNodes()
resultNodes.filter { resultNode ->
conditionNodes.any { conditionNode ->
dataFlow(conditionNode, resultNode).value
}
}
}
}

/**
* Get all [Nodes] that are associated with this [Op] and fulfill the [Signature]s of the
* [Definition]s.
*/
context(CokoBackend)
fun Op.cpgGetNodes(): Nodes =
fun Op.cpgGetNodes(): Collection<CallExpression> =
when (this@Op) {
is FunctionOp ->
[email protected]
Expand All @@ -74,6 +80,18 @@ fun Op.cpgGetNodes(): Nodes =
sig.unorderedParameters.all { it?.cpgFlowsTo(arguments) ?: false }
}
}
is GroupingOp -> [email protected] { it.cpgGetNodes() }
is ConditionalOp -> {
val resultNodes = resultOp.cpgGetNodes()
val conditionNodes = conditionOp.cpgGetNodes()
resultNodes.filter { resultNode ->
conditionNodes.any { conditionNode ->
// TODO: Is it correct to use the EOG relationship here?
val result = executionPath(conditionNode, resultNode)
result.value
}
}
}
}

/** Returns a list of [ValueDeclaration]s with the matching name. */
Expand Down Expand Up @@ -146,7 +164,10 @@ infix fun Any.cpgFlowsTo(that: Collection<Node>): Boolean =
true
} else {
when (this) {
is String -> that.any { Regex(this).matches((it as? Expression)?.evaluate()?.toString().orEmpty()) }
is String -> that.any {
val regex = Regex(this)
regex.matches((it as? Expression)?.evaluate()?.toString().orEmpty()) || regex.matches(it.code.orEmpty())
}
is Iterable<*> -> this.any { it?.cpgFlowsTo(that) ?: false }
is Array<*> -> this.any { it?.cpgFlowsTo(that) ?: false }
is Node -> that.any { dataFlow(this, it).value }
Expand Down Expand Up @@ -189,8 +210,10 @@ fun CallExpression.cpgSignature(vararg parameters: Any?, hasVarargs: Boolean = f
parameter.param cpgFlowsTo arguments[i]
// checks if the type of the argument is the same
is Type -> cpgCheckType(parameter, i)
// check if any of the Nodes from the Op flow to the argument
// check if any of the Nodes of the Op flow to the argument
is Op -> parameter.cpgGetNodes() cpgFlowsTo arguments[i]
// check if any of the Nodes of the DataItem flow to the argument
is DataItem<*> -> parameter.cpgGetNodes() cpgFlowsTo arguments[i]
// checks if there is dataflow from the parameter to the argument in the same position
else -> parameter cpgFlowsTo arguments[i]
}
Expand Down
Loading
Loading