Semmle QL: TaintTracking hasFlow () Проблема с источниками, которые портят их аргументы - PullRequest
4 голосов
/ 30 сентября 2019

Я хочу сделать TaintTracking с функциями, которые портят их аргументы с помощью userinput. Пример:

fgets(buf, sizeof(buf), stdin); // buf is tainted
[...]
n = strlen(buf); // tainted argument to strlen
[...]
memcpy(somewhere, buf, n) // tainted call to memcpy

Семмл должен иметь возможность определить это с помощью запроса, подобного следующему (просто с fgets-> strlen в качестве примера). Я заимствую код из SecurityOptions:

import cpp
import semmle.code.cpp.dataflow.TaintTracking

class IsTaintedArg extends string {
  IsTaintedArg() { this = "IsTaintedArg" }
  predicate userInputArgument(FunctionCall functionCall, int arg) {
    exists(string fname |
      functionCall.getTarget().hasGlobalName(fname) and
      exists(functionCall.getArgument(arg)) and (fname = "fgets" and arg = 0) // argument 0 of fgets is tainted
    )
  }

  predicate isUserInput(Expr expr, string cause) {
    exists(FunctionCall fc, int i |
      this.userInputArgument(fc, i) and
      expr = fc.getArgument(i) and
      cause = fc.getTarget().getName()
    )
  }
}

class TaintedFormatConfig extends TaintTracking::Configuration {
  TaintedFormatConfig() { this = "TaintedFormatConfig" }
  override predicate isSource(DataFlow::Node source) {
    exists (IsTaintedArg opts |
      opts.isUserInput(source.asExpr(), _)
    )
  }
  override predicate isSink(DataFlow::Node sink) { 
    exists (FunctionCall fc | sink.asExpr() = fc.getArgument(0) and fc.getTarget().hasName("strlen")) // give me all calls that land in strlen's first argument
  }
}

from TaintedFormatConfig cfg, DataFlow::Node source, DataFlow::Node sink
where cfg.hasFlow(source, sink)
select sink, source

И все же не похоже, что он работает.

Когда я просто запрашиваю cfg.isSource() или cfg.isSink(), как источник, так и приемникраспознан. Но hasFlow() по-прежнему ничего не возвращает - хотя путь определенно должен существовать.

  • Я использую libssh2 для проверки своих результатов, пример потока существует здесь .

  • Мой запрос для проверки: здесь .

Кто-нибудь знает, что я могу сделать неправильно в запросевыше

1 Ответ

4 голосов
/ 30 сентября 2019

Недостающий бит находится в isSource, где отслеживание заражения начинается с 0-го аргумента до fgets. Использование asExpr опишет поток из этого аргумента в fgets. Нам нужен поток из fgets через этот аргумент. Вы получите это, заменив asExpr на asDefiningArgument.

Здесь - это ссылка на результаты вашего запроса, где я использовал asExpr и asDefiningArgumentв isSource. Это означает, что если вы расширите isUserInput в будущем, его выражения будут считаться источниками как в качестве их значения, так и в качестве выходных аргументов.

Новая версия запроса имеет 8 результатов, и некоторые из них сложнычтобы понять, когда вы видите только источник и приемник, потому что они могут быть в разных файлах. Я сделал очищенную версию запроса, в которой

  • генерирует объяснения пути между источниками и приемниками (@kind path-problem),
  • удаляет обтекание класса IsTaintedArg классавспомогательные предикаты
  • удаляют несколько неиспользуемых параметров и проверок, а
  • добавляет вызов к asDefiningArgument.

Вот полный запрос:

/**
 * @kind path-problem
 * @id taint-to-strlen
 */
import cpp
import semmle.code.cpp.dataflow.DataFlow
import DataFlow::PathGraph

predicate userInputArgument(FunctionCall functionCall, int arg) {
  functionCall.getTarget().hasGlobalName("fgets") and
  arg = 0 // argument 0 of fgets is tainted
}

predicate isUserInput(Expr expr) {
  exists(FunctionCall fc, int i |
    userInputArgument(fc, i) and
    expr = fc.getArgument(i)
  )
}

class TaintedFormatConfig extends DataFlow::Configuration {
  TaintedFormatConfig() { this = "TaintedFormatConfig" }
  override predicate isSource(DataFlow::Node source) {
    isUserInput(source.asExpr())
    or
    isUserInput(source.asDefiningArgument())
  }
  override predicate isSink(DataFlow::Node sink) { 
    exists (FunctionCall fc | sink.asExpr() = fc.getArgument(0) and fc.getTarget().hasName("strlen"))
  }
}

from TaintedFormatConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "Taint from fgets call in " + source.getNode().getFunction().getFile().getBaseName()

Вы можете увидеть результаты на https://lgtm.com/query/4800800615370766111/.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...