trailofbits.go.nil-check-after-call.nil-check-after-call

profile photo of trailofbitstrailofbits
Author
232
Download Count*

Potential $FOO nil dereference when $BAR is called

Run Locally

Run in CI

Defintion

rules:
  - id: nil-check-after-call
    message: Potential `$FOO` nil dereference when `$BAR` is called
    languages:
      - go
    severity: WARNING
    metadata:
      category: security
      cwe: "CWE-253: Incorrect Check of Function Return Value"
      subcategory:
        - vuln
      confidence: MEDIUM
      likelihood: MEDIUM
      impact: MEDIUM
      technology:
        - --no-technology--
      description: Possible nil dereferences
      references:
        - https://blog.trailofbits.com/2019/11/07/attacking-go-vr-ttps/
      license: AGPL-3.0 license
      vulnerability_class:
        - Other
    patterns:
      - pattern-either:
          - pattern: |
              $FOO.$BAR(...)
              ...
              if $FOO != nil { ... }
          - pattern: |
              $FOO.$BAR(...)
              ...
              if $FOO == nil { ... }
          - pattern: |
              $FUNC(..., $FOO.$BAR(...), ...)
              ...
              if $FOO != nil { ... }
          - pattern: |
              $FUNC(..., $FOO.$BAR(...), ...)
              ...
              if $FOO == nil { ... }
      - pattern-not: |
          $FOO.$BAR(...)
          ...
          $FOO = ...
          ...
          if $FOO != nil { ... }
      - pattern-not: |
          $FOO.$BAR(...)
          ...
          ..., $FOO, ... = ...
          ...
          if $FOO == nil { ... }
      - pattern-not: |
          $FOO.$BAR(...)
          ...
          ..., $FOO, ... = ...
          ...
          if $FOO != nil { ... }
      - pattern-not: |
          $FOO.$BAR(...)
          ...
          $FOO = ...
          ...
          if $FOO == nil { ... }
      - pattern-not: |
          ..., $FOO = $FOO.$BAR(...)
          ...
          if $FOO == nil { ... }
      - pattern-not: |
          ..., $FOO = $FOO.$BAR(...)
          ...
          if $FOO != nil { ... }
      - pattern-not: |
          $FOO = $FOO.$BAR(...)
          ...
          if $FOO == nil { ... }
      - pattern-not: |
          $FOO = $FOO.$BAR(...)
          ...
          if $FOO != nil { ... }

Examples

nil-check-after-call.go

// code modified from https://gobyexample.com/methods

package main

import "fmt"

type rect struct {
	width, height int
}

func main() {
	rect1()
	rect2()
	rect3()
	rect4()
}

func NewRectangle(w, h int) (*rect, error) {
	if w == 0 || h == 0 {
		return nil, fmt.Errorf("invalid height or width ")
	}
	return &rect{width: w, height: h}, nil
}

func (r *rect) area() int {
	return r.width * r.height
}

func (r rect) perim() int {
	return 2*r.width + 2*r.height
}

func (r *rect) print() {
	fmt.Printf("Width: %d, Height: %d\n", r.width, r.height)
}

func rect1(){
	r, _ := NewRectangle(0, 2)
	// ruleid: nil-check-after-call
	fmt.Println("area: ", r.area())
	if r != nil {
		fmt.Println("perim:", r.perim())
	}
}

func rect2(){
	r, _ := NewRectangle(0, 2)
	// ruleid: nil-check-after-call
	r.print()
	if r != nil {
		fmt.Println("perim:", r.perim())
	}
}

func rect3(){
	r, err := NewRectangle(0, 2)
	if err != nil {
		return
	}
	r.print()
	r, err = NewRectangle(2, 3)
	// ruleid: nil-check-after-call
	r.print()
	if r != nil {
		fmt.Println("perim:", r.perim())
	}
}

func rect4(){
	r, err := NewRectangle(0, 2)
	if err != nil {
		return
	}
	r.print()

	r, err = NewRectangle(2, 3)
	// ruleid: nil-check-after-call
	fmt.Println("perim:", r.perim())
	if r == nil {
		return
	}
}