Add Fprintf to Rule G201

This commit is contained in:
cschoenduve-splunk 2018-08-21 00:31:38 -07:00 committed by Cosmin Cojocar
parent a7cff91312
commit b6891998ce

View file

@ -98,16 +98,35 @@ func NewSQLStrConcat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
type sqlStrFormat struct { type sqlStrFormat struct {
sqlStatement sqlStatement
calls gosec.CallList calls gosec.CallList
noIssue gosec.CallList
} }
// Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)" // Looks for "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
func (s *sqlStrFormat) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { func (s *sqlStrFormat) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
// argIndex changes the function argument which gets matched to the regex
argIndex := 0
// TODO(gm) improve confidence if database/sql is being used // TODO(gm) improve confidence if database/sql is being used
if node := s.calls.ContainsCallExpr(n, c); node != nil { if node := s.calls.ContainsCallExpr(n, c); node != nil {
// if the function is fmt.Fprintf, search for SQL statement in Args[1] instead
if sel, ok := node.Fun.(*ast.SelectorExpr); ok {
if sel.Sel.Name == "Fprintf" {
// if os.Stderr or os.Stdout is in Arg[0], mark as no issue
if arg, ok := node.Args[0].(*ast.SelectorExpr); ok {
if ident, ok := arg.X.(*ast.Ident); ok {
if s.noIssue.Contains(ident.Name, arg.Sel.Name) {
return nil, nil
}
}
}
// the function is Fprintf so set argIndex = 1
argIndex = 1
}
}
// concats callexpr arg strings together if needed before regex evaluation // concats callexpr arg strings together if needed before regex evaluation
if argExpr, ok := node.Args[0].(*ast.BinaryExpr); ok { if argExpr, ok := node.Args[argIndex].(*ast.BinaryExpr); ok {
if fullStr, ok := gosec.ConcatString(argExpr); ok { if fullStr, ok := gosec.ConcatString(argExpr); ok {
if s.MatchPatterns(fullStr) { if s.MatchPatterns(fullStr) {
return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence),
@ -116,7 +135,7 @@ func (s *sqlStrFormat) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error)
} }
} }
if arg, e := gosec.GetString(node.Args[0]); s.MatchPatterns(arg) && e == nil { if arg, e := gosec.GetString(node.Args[argIndex]); s.MatchPatterns(arg) && e == nil {
return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), nil return gosec.NewIssue(c, n, s.ID(), s.What, s.Severity, s.Confidence), nil
} }
} }
@ -126,7 +145,8 @@ func (s *sqlStrFormat) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error)
// NewSQLStrFormat looks for cases where we're building SQL query strings using format strings // NewSQLStrFormat looks for cases where we're building SQL query strings using format strings
func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
rule := &sqlStrFormat{ rule := &sqlStrFormat{
calls: gosec.NewCallList(), calls: gosec.NewCallList(),
noIssue: gosec.NewCallList(),
sqlStatement: sqlStatement{ sqlStatement: sqlStatement{
patterns: []*regexp.Regexp{ patterns: []*regexp.Regexp{
regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "), regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "),
@ -140,6 +160,7 @@ func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
}, },
}, },
} }
rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln") rule.calls.AddAll("fmt", "Sprint", "Sprintf", "Sprintln", "Fprintf")
rule.noIssue.AddAll("os", "Stdout", "Stderr")
return rule, []ast.Node{(*ast.CallExpr)(nil)} return rule, []ast.Node{(*ast.CallExpr)(nil)}
} }