Added suggested changes

This commit is contained in:
Dimitar Banchev 2024-08-30 14:23:20 +02:00 committed by Cosmin Cojocar
parent a14ca4ac59
commit f5d312825f

View file

@ -27,7 +27,7 @@ import (
"github.com/securego/gosec/v2/issue" "github.com/securego/gosec/v2/issue"
) )
const defaultWhat = "Use of hardcoded IV/nonce for encryption" const defaultIssueDescription = "Use of hardcoded IV/nonce for encryption"
func newHardCodedNonce(id string, description string) *analysis.Analyzer { func newHardCodedNonce(id string, description string) *analysis.Analyzer {
return &analysis.Analyzer{ return &analysis.Analyzer{
@ -58,24 +58,30 @@ func runHardCodedNonce(pass *analysis.Pass) (interface{}, error) {
} }
var issues []*issue.Issue var issues []*issue.Issue
ssaPkgFunctions := ssaResult.SSA.SrcFuncs ssaPkgFunctions := ssaResult.SSA.SrcFuncs
savedArgsFromFunctions := *iterateAndGetArgsFromTrackedFunctions(ssaPkgFunctions, &calls) savedArgsFromFunctions := iterateAndGetArgsFromTrackedFunctions(ssaPkgFunctions, calls)
if savedArgsFromFunctions == nil {
return nil, errors.New("no tracked functions found, resulting in no variables to track")
}
for _, savedArg := range savedArgsFromFunctions { for _, savedArg := range savedArgsFromFunctions {
tmp, err := raiseIssue(savedArg, &calls, ssaPkgFunctions, pass, "") tmp, err := raiseIssue(savedArg, calls, ssaPkgFunctions, pass, "")
issues = append(issues, tmp...)
if err != nil { if err != nil {
return nil, err return issues, fmt.Errorf("raising issue error: %w", err)
} }
issues = append(issues, tmp...)
} }
return issues, nil return issues, nil
} }
func raiseIssue(val *ssa.Value, funcsToTrack *map[string][]int, ssaFuncs []*ssa.Function, pass *analysis.Pass, issueDescription string) ([]*issue.Issue, error) { func raiseIssue(val *ssa.Value, funcsToTrack map[string][]int, ssaFuncs []*ssa.Function, pass *analysis.Pass, issueDescription string) ([]*issue.Issue, error) {
var err error = nil if *val == nil {
var gosecIssue []*issue.Issue = nil return nil, errors.New("received a pointer to a <nil> ssa.Value")
}
var err error
var gosecIssue []*issue.Issue
if issueDescription == "" { if issueDescription == "" {
issueDescription = defaultWhat issueDescription = defaultIssueDescription
} }
switch valType := (*val).(type) { switch valType := (*val).(type) {
@ -95,9 +101,12 @@ func raiseIssue(val *ssa.Value, funcsToTrack *map[string][]int, ssaFuncs []*ssa.
} }
// When the value assigned to a variable is a function call. // When the value assigned to a variable is a function call.
// It goes and check if this function contains call to crypto/rand.Read in it's body(Assuming that calling crypto/rand.Read in a function, is used for the generation of nonce/iv ) // It goes and check if this function contains call to crypto/rand.Read
// in it's body(Assuming that calling crypto/rand.Read in a function,
// is used for the generation of nonce/iv )
case *ssa.Call: case *ssa.Call:
if calledFunction, ok := valType.Call.Value.(*ssa.Function); ok { if callValue := valType.Call.Value; callValue != nil {
if calledFunction, ok := callValue.(*ssa.Function); ok {
if contains, funcErr := isFuncContainsCryptoRand(calledFunction); !contains && funcErr == nil { if contains, funcErr := isFuncContainsCryptoRand(calledFunction); !contains && funcErr == nil {
issueDescription += " by passing a value from function which doesn't use crypto/rand" issueDescription += " by passing a value from function which doesn't use crypto/rand"
tmp, hasErr := iterateThroughReferrers(val, funcsToTrack, pass.Analyzer.Name, issueDescription, pass.Fset, issue.Medium) tmp, hasErr := iterateThroughReferrers(val, funcsToTrack, pass.Analyzer.Name, issueDescription, pass.Fset, issue.Medium)
@ -107,6 +116,7 @@ func raiseIssue(val *ssa.Value, funcsToTrack *map[string][]int, ssaFuncs []*ssa.
err = funcErr err = funcErr
} }
} }
}
// only checks from strings->[]byte // only checks from strings->[]byte
// might need to add additional types // might need to add additional types
@ -119,11 +129,12 @@ func raiseIssue(val *ssa.Value, funcsToTrack *map[string][]int, ssaFuncs []*ssa.
} }
case *ssa.Parameter: case *ssa.Parameter:
//arg given to tracked function is wrapped in another function, example: // arg given to tracked function is wrapped in another function, example:
// func encrypt(..,nonce,...){ // func encrypt(..,nonce,...){
// aesgcm.Seal() // aesgcm.Seal(nonce)
//} // }
// save parameter position, by checking the name of the variable used in tracked functions and comparing it with the name of the arg // save parameter position, by checking the name of the variable used in
// tracked functions and comparing it with the name of the arg
if valType.Parent() != nil { if valType.Parent() != nil {
trackedFunctions := make(map[string][]int) trackedFunctions := make(map[string][]int)
for index, funcArgs := range valType.Parent().Params { for index, funcArgs := range valType.Parent().Params {
@ -131,13 +142,12 @@ func raiseIssue(val *ssa.Value, funcsToTrack *map[string][]int, ssaFuncs []*ssa.
trackedFunctions[valType.Parent().String()] = []int{len(valType.Parent().Params), index} trackedFunctions[valType.Parent().String()] = []int{len(valType.Parent().Params), index}
} }
} }
result := iterateAndGetArgsFromTrackedFunctions(ssaFuncs, &trackedFunctions) result := iterateAndGetArgsFromTrackedFunctions(ssaFuncs, trackedFunctions)
issueDescription += " by passing a parameter to a function and" issueDescription += " by passing a parameter to a function and"
// recursively backtrack to where the origin of a variable passed to multiple functions is // recursively backtrack to where the origin of a variable passed to multiple functions is
for _, trackedVariable := range *result { for _, trackedVariable := range result {
tmp, hasErr := raiseIssue(trackedVariable, trackedFunctions, ssaFuncs, pass, issueDescription)
tmp, hasErr := raiseIssue(trackedVariable, &trackedFunctions, ssaFuncs, pass, issueDescription)
gosecIssue = append(gosecIssue, tmp...) gosecIssue = append(gosecIssue, tmp...)
err = hasErr err = hasErr
} }
@ -147,15 +157,19 @@ func raiseIssue(val *ssa.Value, funcsToTrack *map[string][]int, ssaFuncs []*ssa.
} }
// Iterate through all places that use the `variable` argument and check if it's used in one of the tracked functions // Iterate through all places that use the `variable` argument and check if it's used in one of the tracked functions
func iterateThroughReferrers(variable *ssa.Value, funcsToTrack *map[string][]int, analyzerID string, issueDescription string, fileSet *token.FileSet, issueConfidence issue.Score) ([]*issue.Issue, error) { func iterateThroughReferrers(variable *ssa.Value, funcsToTrack map[string][]int,
analyzerID string, issueDescription string,
fileSet *token.FileSet, issueConfidence issue.Score,
) ([]*issue.Issue, error) {
if funcsToTrack == nil || variable == nil || analyzerID == "" || issueDescription == "" || fileSet == nil { if funcsToTrack == nil || variable == nil || analyzerID == "" || issueDescription == "" || fileSet == nil {
return nil, errors.New("received a nil object") return nil, errors.New("received a nil object")
} }
var gosecIssues []*issue.Issue = nil var gosecIssues []*issue.Issue
// Go trough all functions that use the given arg variable // Go trough all functions that use the given arg variable
for _, referrer := range *(*variable).Referrers() { if varReferrers := (*variable).Referrers(); *varReferrers != nil {
for _, referrer := range *varReferrers {
// Iterate trough the functions we are interested // Iterate trough the functions we are interested
for trackedFunc := range *funcsToTrack { for trackedFunc := range funcsToTrack {
// Split the functions we are interested in, by the '.' because we will use the function name to do the comparison // Split the functions we are interested in, by the '.' because we will use the function name to do the comparison
// MIGHT GIVE SOME FALSE POSITIVES THIS WAY // MIGHT GIVE SOME FALSE POSITIVES THIS WAY
@ -166,6 +180,7 @@ func iterateThroughReferrers(variable *ssa.Value, funcsToTrack *map[string][]int
} }
} }
} }
}
return gosecIssues, nil return gosecIssues, nil
} }
@ -188,44 +203,51 @@ func isFuncContainsCryptoRand(funcCall *ssa.Function) (bool, error) {
return false, nil return false, nil
} }
func addToVarsMap(value *ssa.Value, mapToAddTo *map[string]*ssa.Value) { func addToVarsMap(value *ssa.Value, mapToAddTo map[string]*ssa.Value) {
key := (*value).Name() + (*value).Type().String() + (*value).String() + (*value).Parent().String() valDerefed := *value
(*mapToAddTo)[key] = value key := valDerefed.Name() + valDerefed.Type().String() + valDerefed.String() + valDerefed.Parent().String()
mapToAddTo[key] = value
} }
func isContainedInMap(value *ssa.Value, mapToCheck *map[string]*ssa.Value) bool { func isContainedInMap(value *ssa.Value, mapToCheck map[string]*ssa.Value) bool {
key := (*value).Name() + (*value).Type().String() + (*value).String() + (*value).Parent().String() valDerefed := *value
_, contained := (*mapToCheck)[key]
key := valDerefed.Name() + valDerefed.Type().String() + valDerefed.String() + valDerefed.Parent().String()
_, contained := mapToCheck[key]
return contained return contained
} }
func iterateAndGetArgsFromTrackedFunctions(ssaFuncs []*ssa.Function, trackedFunc *map[string][]int) *map[string]*ssa.Value { func iterateAndGetArgsFromTrackedFunctions(ssaFuncs []*ssa.Function, trackedFunc map[string][]int) map[string]*ssa.Value {
values := make(map[string]*ssa.Value) values := make(map[string]*ssa.Value)
for _, pkgFunc := range ssaFuncs { for _, pkgFunc := range ssaFuncs {
for _, funcBlock := range pkgFunc.Blocks { for _, funcBlock := range pkgFunc.Blocks {
for _, funcBlocInstr := range funcBlock.Instrs { for _, funcBlocInstr := range funcBlock.Instrs {
if funcCall, ok := funcBlocInstr.(*ssa.Call); ok { iterateTrackedFunctionsAndAddArgs(&funcBlocInstr, trackedFunc, values)
for trackedFuncName, trackedFuncArgsInfo := range *trackedFunc { }
}
}
return values
}
func iterateTrackedFunctionsAndAddArgs(funcBlocInstr *ssa.Instruction, trackedFunc map[string][]int, values map[string]*ssa.Value) {
if funcCall, ok := (*funcBlocInstr).(*ssa.Call); ok {
for trackedFuncName, trackedFuncArgsInfo := range trackedFunc {
// only process functions that have the same number of arguments as the ones we track // only process functions that have the same number of arguments as the ones we track
if len(funcCall.Call.Args) == trackedFuncArgsInfo[0] { if len(funcCall.Call.Args) == trackedFuncArgsInfo[0] {
tmpArg := funcCall.Call.Args[trackedFuncArgsInfo[1]] tmpArg := funcCall.Call.Args[trackedFuncArgsInfo[1]]
// check if the function is called from an object or directly from the package // check if the function is called from an object or directly from the package
if funcCall.Call.Method != nil { if funcCall.Call.Method != nil {
if methodFullname := funcCall.Call.Method.FullName(); methodFullname == trackedFuncName { if methodFullname := funcCall.Call.Method.FullName(); methodFullname == trackedFuncName {
if !isContainedInMap(&tmpArg, &values) { if !isContainedInMap(&tmpArg, values) {
addToVarsMap(&tmpArg, &values) addToVarsMap(&tmpArg, values)
} }
} }
} else if funcCall.Call.Value.String() == trackedFuncName { } else if funcCall.Call.Value.String() == trackedFuncName {
if !isContainedInMap(&tmpArg, &values) { if !isContainedInMap(&tmpArg, values) {
addToVarsMap(&tmpArg, &values) addToVarsMap(&tmpArg, values)
} }
} }
} }
} }
} }
}
}
}
return &values
} }