gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/securego/gosec/rules/readfile.go (about)

     1  // (c) Copyright 2016 Hewlett Packard Enterprise Development LP
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package rules
    16  
    17  import (
    18  	"go/ast"
    19  	"go/types"
    20  
    21  	"github.com/securego/gosec"
    22  )
    23  
    24  type readfile struct {
    25  	gosec.MetaData
    26  	gosec.CallList
    27  	pathJoin gosec.CallList
    28  }
    29  
    30  // ID returns the identifier for this rule
    31  func (r *readfile) ID() string {
    32  	return r.MetaData.ID
    33  }
    34  
    35  // isJoinFunc checks if there is a filepath.Join or other join function
    36  func (r *readfile) isJoinFunc(n ast.Node, c *gosec.Context) bool {
    37  	if call := r.pathJoin.ContainsCallExpr(n, c); call != nil {
    38  		for _, arg := range call.Args {
    39  			// edge case: check if one of the args is a BinaryExpr
    40  			if binExp, ok := arg.(*ast.BinaryExpr); ok {
    41  				// iterate and resolve all found identites from the BinaryExpr
    42  				if _, ok := gosec.FindVarIdentities(binExp, c); ok {
    43  					return true
    44  				}
    45  			}
    46  
    47  		// try and resolve identity
    48  		if ident, ok := arg.(*ast.Ident); ok {
    49  			obj := c.Info.ObjectOf(ident)
    50  			if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) {
    51  				return true
    52  			}
    53  		}
    54  	}
    55  }
    56  	return false
    57  }
    58  
    59  // Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile`
    60  func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
    61  	if node := r.ContainsCallExpr(n, c); node != nil {
    62  		for _, arg := range node.Args {
    63  			// handles path joining functions in Arg
    64  			// eg. os.Open(filepath.Join("/tmp/", file))
    65  			if callExpr, ok := arg.(*ast.CallExpr); ok {
    66  				if r.isJoinFunc(callExpr, c) {
    67  					return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
    68  				}
    69  			}
    70  			// handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob")
    71  			if binExp, ok := arg.(*ast.BinaryExpr); ok {
    72  				// resolve all found identites from the BinaryExpr
    73  				if _, ok := gosec.FindVarIdentities(binExp, c); ok {
    74  					return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
    75  				}
    76  			}
    77  
    78  			if ident, ok := arg.(*ast.Ident); ok {
    79  				obj := c.Info.ObjectOf(ident)
    80  				if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) {
    81  					return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
    82  				}
    83  			}
    84  		}
    85  	}
    86  	return nil, nil
    87  }
    88  
    89  // NewReadFile detects cases where we read files
    90  func NewReadFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
    91  	rule := &readfile{
    92  		pathJoin: gosec.NewCallList(),
    93  		CallList: gosec.NewCallList(),
    94  		MetaData: gosec.MetaData{
    95  			ID:         id,
    96  			What:       "Potential file inclusion via variable",
    97  			Severity:   gosec.Medium,
    98  			Confidence: gosec.High,
    99  		},
   100  	}
   101  	rule.pathJoin.Add("path/filepath", "Join")
   102  	rule.pathJoin.Add("path", "Join")
   103  	rule.Add("io/ioutil", "ReadFile")
   104  	rule.Add("os", "Open")
   105  	return rule, []ast.Node{(*ast.CallExpr)(nil)}
   106  }