Predicate

CodeQL中的Predicates(谓词)充当类似函数的功能,谓词实际上就是对元组集合的求值操作

QL内置了一些谓词可以直接使用,不需要导入

自定义谓词:

  • 返回结果类型(若谓词无返回值,前面写关键词predicate)

  • 谓词名称(第一个字母小写)

  • 谓词参数

  • 谓词主体

predicate name(type arg)
{
  statements
}

注:谓词的参数和返回值的值域都为有限的元组集合,即在谓词主体中要显式声明出来

  • 无返回值:

一般用于数据筛选吧,满足条件的输入才通过

predicate isSmall(int i) {
  i in [1 .. 9]
}
  • 有返回值:

将关键字predicate换为返回值的类型,返回值的变量为result

int getSuccessor(int i) {
  result = i + 1 and
  i in [1 .. 9]
}

在谓词里面,result可以作为参数传入其他谓词,如下面定义了getAParentOf这个谓词的”逆“

只需将result和其他变量的关系表达出来即可

Person getAChildOf(Person p) {
  p = getAParentOf(result)  # result的parent是p, 即p的child是result
}
  • 多返回值谓词

string getFunc(string action) {
  action = "rce" and result = "popen"
  or
  action = "rce" and result = "system"
  or
  action = "ssrf" and result = "file_get_contents"
  or
  action = "ssrf" and result = "curl_exec"
}

getFunc("rce")返回两个结果popensystem

getFunc("csrf")不返回结果

  • 递归谓词

string getANeighbor(string country) {
  country = "France" and result = "Belgium"
  or
  country = "France" and result = "Germany"
  or
  country = "Germany" and result = "Austria"
  or
  country = "Germany" and result = "Belgium"
  or
  country = getANeighbor(result)
}

上面谓词getANeighbor作的限定关系并没有直接体现对称关系,即x=getANeighbor(y)同时y=getANeighbor(x)

可以使用递归谓词来解决

getANeighbor("Belgium")返回FranceGermany

  • 谓词种类

可以分成三种谓词:

  1. non-member predicates

  2. member predicates

  3. characteristic predicates

int getSuccessor(int i) {  // 1. Non-member predicate
  result = i + 1 and
  i in [1 .. 9]
}

class FavoriteNumbers extends int {
  FavoriteNumbers() {  // 2. Characteristic predicate
    this = 1 or
    this = 4 or
    this = 9
  }

  string getName() {   // 3. Member predicate for the class `FavoriteNumbers`
    this = 1 and result = "one"
    or
    this = 4 and result = "four"
    or
    this = 9 and result = "nine"
  }
}
  • 集合绑定

上面说到谓词的参数和返回结果的值域都要是有限的tuple,即谓词只能包含有限数量的元组

如下的谓词编译时就会报错。

/*
  Compilation errors:
  ERROR: "i" is not bound to a value.
  ERROR: "result" is not bound to a value.
  ERROR: expression "i * 4" is not bound to a value.
*/
int multiplyBy4(int i) {
  result = i * 4
}

/*
  Compilation errors:
  ERROR: "str" is not bound to a value.
  ERROR: expression "str.length()" is not bound to a value.
*/
predicate shortString(string str) {
  str.length() < 10
}

可以通过在谓词上使用bindingset标志,其声明了该谓词的输入绑定到了有限的数据集合

bindingset[x] bindingset[y]
predicate plusOne(int x, int y) {
  x + 1 = y
}

from int x, int y
where y = 42 and plusOne(x, y)
select x, y

bindingset[x] bindingset[y]or关系,即x或y是有限的

bindingset[x, y]and关系,即x和y必须是有限的

bindingset[str, len]
string truncate(string str, int len) {
  if str.length() > len
  then result = str.prefix(len)
  else result = str
}

Last updated