CodeQL for Golang Practise(2)

Basic Query for Go code

See Basic query for Go code

Key points:

  • Practise the query in LGTM
  • Sample query
import go   // Imports the standard CodeQL libraries for Go.

from Method m, Variable recv, Write w, Field f   // Defines the variables for the query. 
where
  recv = m.getReceiver() and
  w.writesField(recv.getARead(), f, _) and
  not recv.getType() instanceof PointerType   // Defines a condition on the variables.
  not exists(ReturnStmt ret | ret.getExpr() = recv.getARead().asExpr())  // Remove false positive results
select w, "This update to " + f + " has no effect, because " + recv + " is not a pointer."  // Defines what to report for each match.

Gojenkins on LGTM

In last post the gojenkins repo is clones and analyzed locally, but since it is open source project, so LGTM has already had the results.

Moreover, we can see some errors that has already been identified by the built-in codeql scanner.

2020_12_15_1

And the error is identified by the signature:

2020_12_15_2

To query this project, click the query this project button, will be redirected to the query console.

Data Flow Analysis

Data flow analysis is used to compute the possible values that a variable can hold at various points in a program, determining how those values propagate through the program and where they are used.

Usage:

  • Discover insecure ways of data using
  • Discover dangerous arguments
  • Discover sensitive data leakage
  • Understand the program’s behaviour
    • Find unintialized variables
    • Find resource leaks

Example Queries on LGTM.com

Instead of trying complex queries in the beginning, it is good to read some sample queries and try to understand their meanings.

Call to built-in function

When we try the example queries Call to built-in function:

import go

from DataFlow::CallNode call
where call = Builtin::len().getACall()
select call

It will shows all the places that using the built-in function len.

2020_12_15_3

2020_12_15_4

Call to library function

Finds calls to “fmt.Println”.

import go

from Function println, DataFlow::CallNode call
where
  println.hasQualifiedName("fmt", "Println") and
  call = println.getACall()
select call

Sample Matched result:

fmt.Println(href)

Call to Method

Finds calls to the Get method of type Header from the net/http package.

import go

from Method get, DataFlow::CallNode call
where
  get.hasQualifiedName("net/http", "Header", "Get") and
  call = get.getACall()
select call

Sample Matched result:

textSize := rsp.Header.Get("X-Text-Size")

Comparison with Nil

import go

from DataFlow::EqualityTestNode eq, DataFlow::Node nd, DataFlow::Node nil
where
  nil = Builtin::nil().getARead() and
  eq.eq(_, nd, nil)
select eq

Sample Matched result:

if err != nil {
	return nil, err
}

Comparison with Zero

import go

from DataFlow::RelationalComparisonNode cmp, DataFlow::Node unsigned, DataFlow::Node zero
where
  zero.getNumericValue() = 0 and
  unsigned.getType().getUnderlyingType() instanceof UnsignedIntegerType and
  cmp.leq(_, zero, unsigned, 0)
select cmp, unsigned

Compile-time Constant

import go

from DataFlow::Node zero
where zero.getNumericValue() = 0
select zero

Field Read

Finds code that reads Request.Method.

import go

from Field reqm, Read read
where
  reqm.hasQualifiedName("net/http", "Request", "Method") and
  read = reqm.getARead()
select read

Field Write

Finds assignments to field Status of type Response from package net/http.

import go

from Field status, Write write
where
  status.hasQualifiedName("net/http", "Response", "Status") and
  write = status.getAWrite()
select write, write.getRhs()

Function

Finds functions called “main”.

import go

from Function main
where main.getName() = "main"
select main

If statements with empty then branch

import go

from IfStmt i
where i.getThen().getNumStmt() = 0
select i

Increment statements in loops

Finds increment statements that are nested in a loop.

import go

from IncStmt s, LoopStmt l
where s.getParent+() = l
select s, l

Parameter

Finds parameters of type “ResponseWriter” from package “net/http”.

import go

from Parameter req
where req.getType().hasQualifiedName("net/http", "ResponseWriter")
select req

Receiver Variable

Finds receiver variables of pointer type.

import go

from ReceiverVariable recv
where recv.getType() instanceof PointerType
select recv

Result variable

Finds result variables of type “error”.

import go

from ResultVariable err
where err.getType() = Builtin::error().getType()
select err

Type

Finds type Request from package net/http.

import go

from Type request
where request.hasQualifiedName("net/http", "Request")
select request

Variable

Finds variables called “err”.

import go

from Variable err
where err.getName() = "err"
select err, err.getDeclaration()

Variable Read

Finds code that reads a variable called err.

import go

from Variable err, Read read
where
  err.getName() = "err" and
  read = err.getARead()
select read

Variable Write

Finds assignments to variables named “err”.

import go

from Variable err, Write write
where
  err.getName() = "err" and
  write = err.getAWrite()
select write, write.getRhs()

Reference