mirror of
https://github.com/securego/gosec.git
synced 2024-12-25 12:05:52 +00:00
709ed1ba65
Currently, rule G204 warns you about every single use of the functions syscall.Exec, os.exec.CommandContext and os.Exec.Command. This can create false positives and it's not accurate because you can use those functions with perfectly secure arguments like hardcoded strings for example. With this change, G204 will warn you in 3 cases when passing arguments to a function which starts a new process the arguments: 1) are variables initialized by calling another function 2) are functions 3) are command-line arguments or environmental variables Closes: https://github.com/securego/gosec/issues/338 Signed-off-by: Martin Vrachev <mvrachev@vmware.com>
66 lines
2.2 KiB
Go
66 lines
2.2 KiB
Go
// (c) Copyright 2016 Hewlett Packard Enterprise Development LP
|
|
//
|
|
// 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 rules
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/types"
|
|
|
|
"github.com/securego/gosec"
|
|
)
|
|
|
|
type subprocess struct {
|
|
gosec.MetaData
|
|
gosec.CallList
|
|
}
|
|
|
|
func (r *subprocess) ID() string {
|
|
return r.MetaData.ID
|
|
}
|
|
|
|
// TODO(gm) The only real potential for command injection with a Go project
|
|
// is something like this:
|
|
//
|
|
// syscall.Exec("/bin/sh", []string{"-c", tainted})
|
|
//
|
|
// E.g. Input is correctly escaped but the execution context being used
|
|
// is unsafe. For example:
|
|
//
|
|
// syscall.Exec("echo", "foobar" + tainted)
|
|
func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
|
if node := r.ContainsCallExpr(n, c, false); node != nil {
|
|
for _, arg := range node.Args {
|
|
if ident, ok := arg.(*ast.Ident); ok {
|
|
obj := c.Info.ObjectOf(ident)
|
|
if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) {
|
|
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
|
|
}
|
|
} else if !gosec.TryResolve(arg, c) {
|
|
// the arg is not a constant or a variable but instead a function call or os.Args[i]
|
|
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with function call as argument or cmd arguments", gosec.Medium, gosec.High), nil
|
|
}
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
// NewSubproc detects cases where we are forking out to an external process
|
|
func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
|
rule := &subprocess{gosec.MetaData{ID: id}, gosec.NewCallList()}
|
|
rule.Add("os/exec", "Command")
|
|
rule.Add("os/exec", "CommandContext")
|
|
rule.Add("syscall", "Exec")
|
|
return rule, []ast.Node{(*ast.CallExpr)(nil)}
|
|
}
|