/**
 * @name SQLI Vulnerability
 * @description Using untrusted strings in a sql query allows sql injection attacks.
 * @kind path-problem
 * @id cpp/sqlivulnerable
 * @problem.severity warning
 */


import cpp

// 1. source: count = read(STDIN_FILENO, buf, BUFSIZE);
// want buf
// from VariableAccess buf, FunctionCall read
// where read.getArgument(1) = buf and
// read.getTarget().getName() = "read"
// select read, buf
// predicate findBuf(VariableAccess buf, FunctionCall read) {
//     read.getArgument(1) = buf and
//     read.getTarget().getName() = "read"
// }
// from VariableAccess buf, FunctionCall read
// where findBuf(buf, read)
// select read, buf
// predicate findBuf(VariableAccess buf) {
//     exists(FunctionCall read |
//     read.getArgument(1) = buf and
//     read.getTarget().getName() = "read"
//     )
// }
// from VariableAccess buf
// where findBuf(buf)
// select buf
class FindBuf extends VariableAccess {
  FindBuf() {
    exists(FunctionCall read |
      read.getArgument(1) = this and
      read.getTarget().getName() = "read"
    )
  }
}

// from FindBuf buf
// select buf
// 2. sink:  rc = sqlite3_exec(db, query, NULL, 0, &zErrMsg);
class FindQuery extends VariableAccess {
  FindQuery() {
    exists(FunctionCall read |
      read.getArgument(1) = this and
      read.getTarget().getName() = "sqlite3_exec"
    )
  }
}

// from FindQuery fq
// select fq
// 3. dataflow between them
import semmle.code.cpp.dataflow.new.TaintTracking

module SqliFlowConfig implements DataFlow::ConfigSig {
  predicate isSource(DataFlow::Node source) { 
    exists(FindBuf fb | source.asDefiningArgument()  = fb) }

  predicate isSink(DataFlow::Node sink) { 
    exists(FindQuery fq |sink.asIndirectArgument() = fq) }
}

import MyFlow::PathGraph

module MyFlow = TaintTracking::Global<SqliFlowConfig>;

from MyFlow::PathNode source, MyFlow::PathNode sink
where MyFlow::flowPath(source, sink)
select sink, source, sink, "Possible SQL injection"
