use of org.wso2.ballerinalang.compiler.semantics.model.symbols.TaintRecord in project ballerina by ballerina-lang.
the class TaintAnalyzer method analyzeInvocation.
// Private methods relevant to invocation analysis.
private void analyzeInvocation(BLangInvocation invocationExpr) {
BInvokableSymbol invokableSymbol = (BInvokableSymbol) invocationExpr.symbol;
Map<Integer, TaintRecord> taintTable = invokableSymbol.taintTable;
List<Boolean> returnTaintedStatus = new ArrayList<>();
TaintRecord allParamsUntaintedRecord = taintTable.get(ALL_UNTAINTED_TABLE_ENTRY_INDEX);
if (allParamsUntaintedRecord.taintError != null && allParamsUntaintedRecord.taintError.size() > 0) {
// This can occur when there is a error regardless of tainted status of parameters.
// Example: Tainted value returned by function is passed to another functions's sensitive parameter.
addTaintError(allParamsUntaintedRecord.taintError);
} else {
returnTaintedStatus = new ArrayList<>(taintTable.get(ALL_UNTAINTED_TABLE_ENTRY_INDEX).retParamTaintedStatus);
}
if (invocationExpr.argExprs != null) {
for (int argIndex = 0; argIndex < invocationExpr.argExprs.size(); argIndex++) {
BLangExpression argExpr = invocationExpr.argExprs.get(argIndex);
argExpr.accept(this);
// return-tainted-status when the given argument is in tainted state.
if (getObservedTaintedStatus()) {
TaintRecord taintRecord = taintTable.get(argIndex);
if (taintRecord == null) {
// This is when current parameter is "sensitive". Therefore, providing a tainted
// value to a sensitive parameter is invalid and should return a compiler error.
int requiredParamCount = invokableSymbol.params.size();
int defaultableParamCount = invokableSymbol.defaultableParams.size();
int totalParamCount = requiredParamCount + defaultableParamCount + (invokableSymbol.restParam == null ? 0 : 1);
BVarSymbol paramSymbol = getParamSymbol(invokableSymbol, argIndex, requiredParamCount, defaultableParamCount);
addTaintError(argExpr.pos, paramSymbol.name.value, DiagnosticCode.TAINTED_VALUE_PASSED_TO_SENSITIVE_PARAMETER);
} else if (taintRecord.taintError != null && taintRecord.taintError.size() > 0) {
// This is when current parameter is derived to be sensitive. The error already generated
// during taint-table generation will be used.
addTaintError(taintRecord.taintError);
} else {
// status of all returns to get accumulated tainted status of all returns for the invocation.
for (int returnIndex = 0; returnIndex < returnTaintedStatus.size(); returnIndex++) {
if (taintRecord.retParamTaintedStatus.get(returnIndex)) {
returnTaintedStatus.set(returnIndex, true);
}
}
}
if (stopAnalysis) {
break;
}
}
}
}
if (invocationExpr.expr != null) {
// When an invocation like stringValue.trim() happens, if stringValue is tainted, the result will
// also be tainted.
// TODO: TaintedIf annotation, so that it's possible to define what can taint or untaint the return.
invocationExpr.expr.accept(this);
for (int i = 0; i < returnTaintedStatus.size(); i++) {
if (getObservedTaintedStatus()) {
returnTaintedStatus.set(i, getObservedTaintedStatus());
}
}
}
taintedStatusList = returnTaintedStatus;
}
use of org.wso2.ballerinalang.compiler.semantics.model.symbols.TaintRecord in project ballerina by ballerina-lang.
the class TaintAnalyzer method visitInvokable.
private void visitInvokable(BLangInvokableNode invNode, SymbolEnv symbolEnv) {
if (invNode.symbol.taintTable == null) {
if (Symbols.isNative(invNode.symbol)) {
attachTaintTableBasedOnAnnotations(invNode);
return;
}
Map<Integer, TaintRecord> taintTable = new HashMap<>();
returnTaintedStatusList = null;
// Check the tainted status of return values when no parameter is tainted.
analyzeAllParamsUntaintedReturnTaintedStatus(taintTable, invNode, symbolEnv);
boolean isBlocked = processBlockedNode(invNode);
if (isBlocked) {
return;
}
int requiredParamCount = invNode.requiredParams.size();
int defaultableParamCount = invNode.defaultableParams.size();
int totalParamCount = requiredParamCount + defaultableParamCount + (invNode.restParam == null ? 0 : 1);
for (int paramIndex = 0; paramIndex < totalParamCount; paramIndex++) {
BLangVariable param = getParam(invNode, paramIndex, requiredParamCount, defaultableParamCount);
// If parameter is sensitive, it is invalid to have a case where tainted status of parameter is true.
if (hasAnnotation(param, ANNOTATION_SENSITIVE)) {
continue;
}
returnTaintedStatusList = null;
// Set each parameter "tainted", then analyze the body to observe the outcome of the function.
analyzeReturnTaintedStatus(taintTable, invNode, symbolEnv, paramIndex, requiredParamCount, defaultableParamCount);
}
invNode.symbol.taintTable = taintTable;
}
}
use of org.wso2.ballerinalang.compiler.semantics.model.symbols.TaintRecord in project ballerina by ballerina-lang.
the class TaintAnalyzer method analyzeLambdaExpressions.
private void analyzeLambdaExpressions(BLangInvocation invocationExpr, BLangExpression argExpr) {
BLangFunction function = ((BLangLambdaFunction) argExpr).function;
if (function.symbol.taintTable == null) {
addToBlockedList(invocationExpr);
} else {
int requiredParamCount = function.requiredParams.size();
int defaultableParamCount = function.defaultableParams.size();
int totalParamCount = requiredParamCount + defaultableParamCount + (function.restParam == null ? 0 : 1);
Map<Integer, TaintRecord> taintTable = function.symbol.taintTable;
for (int paramIndex = 0; paramIndex < totalParamCount; paramIndex++) {
TaintRecord taintRecord = taintTable.get(paramIndex);
BLangVariable param = getParam(function, paramIndex, requiredParamCount, defaultableParamCount);
if (taintRecord == null) {
addTaintError(argExpr.pos, param.name.value, DiagnosticCode.TAINTED_VALUE_PASSED_TO_SENSITIVE_PARAMETER);
} else if (taintRecord.taintError != null && taintRecord.taintError.size() > 0) {
addTaintError(taintRecord.taintError);
}
if (stopAnalysis) {
break;
}
}
}
}
use of org.wso2.ballerinalang.compiler.semantics.model.symbols.TaintRecord in project ballerina by ballerina-lang.
the class TaintAnalyzer method analyzeReturnTaintedStatus.
private void analyzeReturnTaintedStatus(Map<Integer, TaintRecord> taintTable, BLangInvokableNode invokableNode, SymbolEnv symbolEnv, int paramIndex, int requiredParamCount, int defaultableParamCount) {
resetTaintedStatusOfVariables(invokableNode.requiredParams);
resetTaintedStatusOfVariableDef(invokableNode.defaultableParams);
if (invokableNode.restParam != null) {
resetTaintedStatusOfVariables(Arrays.asList(new BLangVariable[] { invokableNode.restParam }));
}
// Mark the given parameter "tainted".
if (paramIndex != ALL_UNTAINTED_TABLE_ENTRY_INDEX) {
if (paramIndex < requiredParamCount) {
invokableNode.requiredParams.get(paramIndex).symbol.tainted = true;
} else if (paramIndex < requiredParamCount + defaultableParamCount) {
invokableNode.defaultableParams.get(paramIndex - requiredParamCount).var.symbol.tainted = true;
} else {
invokableNode.restParam.symbol.tainted = true;
}
}
analyzeReturnTaintedStatus(invokableNode, symbolEnv);
if (taintErrorSet.size() > 0) {
// When invocation returns an error (due to passing a tainted argument to a sensitive parameter) add current
// error to the table for future reference.
taintTable.put(paramIndex, new TaintRecord(null, new ArrayList<>(taintErrorSet)));
taintErrorSet.clear();
} else if (this.blockedNode == null) {
if (invokableNode.retParams.size() == 0) {
returnTaintedStatusList = new ArrayList<>();
} else {
updatedReturnTaintedStatusBasedOnAnnotations(invokableNode.retParams);
}
taintTable.put(paramIndex, new TaintRecord(returnTaintedStatusList, null));
}
}
use of org.wso2.ballerinalang.compiler.semantics.model.symbols.TaintRecord in project ballerina by ballerina-lang.
the class TaintAnalyzer method attachTaintTableBasedOnAnnotations.
private void attachTaintTableBasedOnAnnotations(BLangInvokableNode invokableNode) {
if (invokableNode.symbol.taintTable == null) {
// Extract tainted status of the function by lookint at annotations added to returns.
List<Boolean> retParamsTaintedStatus = new ArrayList<>();
for (BLangVariable retParam : invokableNode.retParams) {
retParamsTaintedStatus.add(hasAnnotation(retParam, ANNOTATION_TAINTED));
}
// Append taint table with tainted status when no parameter is tainted.
Map<Integer, TaintRecord> taintTable = new HashMap<>();
taintTable.put(ALL_UNTAINTED_TABLE_ENTRY_INDEX, new TaintRecord(retParamsTaintedStatus, null));
int requiredParamCount = invokableNode.requiredParams.size();
int defaultableParamCount = invokableNode.defaultableParams.size();
int totalParamCount = requiredParamCount + defaultableParamCount + (invokableNode.restParam == null ? 0 : 1);
if (totalParamCount > 0) {
// Append taint table with tainted status when each parameter is tainted.
for (int paramIndex = 0; paramIndex < totalParamCount; paramIndex++) {
BLangVariable param = getParam(invokableNode, paramIndex, requiredParamCount, defaultableParamCount);
// If parameter is sensitive, test for this parameter being tainted is invalid.
if (hasAnnotation(param, ANNOTATION_SENSITIVE)) {
continue;
}
taintTable.put(paramIndex, new TaintRecord(retParamsTaintedStatus, null));
}
}
invokableNode.symbol.taintTable = taintTable;
}
}
Aggregations