CodeQL library for Ruby¶
When you’re analyzing a Ruby program, you can make use of the large collection of classes in the CodeQL library for Ruby.
Overview¶
CodeQL ships with an extensive library for analyzing Ruby code. The classes in this library present the data from a CodeQL database in an object-oriented form and provide abstractions and predicates to help you with common analysis tasks.
The library is implemented as a set of CodeQL modules, that is, files with the extension .qll
. The
module ruby.qll imports most other standard library modules, so you can include the complete
library by beginning your query with:
import codeql.ruby.AST
The CodeQL libraries model various aspects of Ruby code, depending on the type of query you want to write. For example the abstract syntax tree (AST) library is used for locating program elements, to match syntactic elements in the source code. This can be used to find values, patterns and structures.
The control flow graph (CFG) is imported using
import codeql.ruby.CFG
The CFG models the control flow between statements and expressions, for example whether one expression can flow to another expression, or whether an expression “dominates” another one, meaning that all paths to an expression must flow through another expression first.
The data flow library is imported using
import codeql.ruby.DataFlow
Data flow tracks the flow of data through the program, including through function calls (interprocedural data flow). Data flow is particularly useful for security queries, where untrusted data flows to vulnerable parts of the program to exploit it. Related to data flow, is the taint-tracking library, which finds how data can influence other values in a program, even when it is not copied exactly.
The API graphs library is used to locate methods in libraries. This is particuarly useful when locating particular functions or parameters that could be used as a source or sink of data in a security query.
To summarize, the main Ruby modules are:
Import | Description |
---|---|
ruby |
The standard Ruby library |
codeql.ruby.AST |
The abstract syntax tree library (also imported by ruby.qll) |
codeql.ruby.ApiGraphs |
The API graphs library |
codeql.ruby.CFG |
The control flow graph library |
codeql.ruby.DataFlow |
The data flow library |
codeql.ruby.TaintTracking |
The taint tracking library |
The CodeQL examples in this article are only excerpts and are not meant to represent complete queries.
Abstract syntax¶
The abstract syntax tree (AST) represents the elements of the source code organized into a tree. The AST viewer in Visual Studio Code shows the AST nodes, including the relevant CodeQL classes and predicates.
All CodeQL AST classes inherit from the AstNode class, which provides the following member predicates to all AST classes:
Predicate | Description |
---|---|
getEnclosingModule() |
Gets the enclosing module, if any. |
getEnclosingMethod() |
Gets the enclosing method, if any. |
getLocation() |
Gets the location of this node. |
getAChild() |
Gets a child node of this node. |
getParent() |
Gets the parent of this AstNode, if this node is not a root node. |
getDesugared |
Gets the desugared version of this AST node, if any. |
isSynthesized() |
Holds if this node was synthesized to represent an implicit AST node not present in the source code. |
Modules¶
Modules represent the main structural elements of Ruby programs, and include modules (Module
),
namespaces (Namespace
) and classes (ClassDeclaration
).
CodeQL class | Description and selected predicates |
---|---|
Module |
A representation of a runtime module or class value.
|
Namespace |
A class or module definition.
|
ClassDeclaration |
A class definition. |
SingletonClass |
A definition of a singleton class on an object. |
ModuleDeclaration |
A module definition. |
Toplevel |
The node representing the entire Ruby source file. |
The following example lists all methods in the class ApiController:
import codeql.ruby.AST
from ClassDeclaration m
where m.getName() = "ApiController"
select m, m.getAMethod()
Callables¶
Callables are elements that can be called, including methods and blocks.
CodeQL class | Description and main predicates |
---|---|
Callable |
A callable.
|
Private |
A call to private . |
Method |
A method.
|
SingletonMethod |
A singleton method. |
Lambda |
A lambda (anonymous method). |
Block |
A block. |
DoBlock |
A block enclosed within do and end. |
BraceBlock |
A block defined using curly braces. |
Parameters are the values that are passed into callables. Unlike other CodeQL language models, parameters in Ruby are not variables themselves, but can introduce variables into the callable. The variables of a parameter are given by the getAVariable() predicate.
CodeQL class | Description and main predicates |
---|---|
Parameter |
A parameter.
|
PatternParameter |
A parameter defined using a pattern. |
TuplePatternParameter |
A parameter defined using a tuple pattern. |
NamedParameter |
A named parameter.
|
SimpleParameter |
A simple (normal) parameter. |
BlockParameter |
A parameter that is a block. |
HashSplatParameter |
A hash-splat (or double-splat) parameter. |
KeywordParameter |
A keyword parameter, including a default value if the parameter is optional.
|
OptionalParameter |
An optional parameter.
|
SplatParameter |
A splat parameter. |
Example
import codeql.ruby.AST
from Method m
where m.getName() = "show"
select m.getParameter(0)
Statements¶
Statements are the elements of code blocks. Statements that produce a value are called expressions and have CodeQL class Expr. The remaining statement types (that do not produce values) are listed below.
CodeQL class | Description and main predicates |
---|---|
Stmt |
The base class for all statements.
|
EmptyStmt |
An empty statement. |
BeginExpr |
A begin statement. |
BeginBlock |
A BEGIN block. |
EndBlock |
An END block. |
UndefStmt |
An undef statement. |
AliasStmt |
An alias statement. |
ReturningStmt |
A statement that may return a value: return, break and next. |
ReturnStmt |
A return statement. |
BreakStmt |
A break statement. |
NextStmt |
A next statement. |
RedoStmt |
A redo statement. |
RetryStmt |
A retry statement. |
The following example finds all literals that are returned by a return statement.
import codeql.ruby.AST
from ReturnStmt return, Literal lit
where lit.getParent() = return
select lit, "Returning a literal " + lit.getValueText()
Expressions¶
Expressions are types of statement that evaluate to a value. The CodeQL class Expr is the base class of all expression types.
CodeQL class | Description and main predicates |
---|---|
Expr |
An expression. This is the root class for all expressions.
|
Self |
A reference to the current object. |
Pair |
A pair expression. |
RescueClause |
A rescue clause. |
RescueModifierExpr |
An expression with a rescue modifier. |
StringConcatenation |
A concatenation of string literals.
|
CodeQL class | Description |
---|---|
StmtSequence |
A sequence of expressions.
|
BodyStmt |
A sequence of statements representing the body of a method, class, module, or do-block.
|
ParenthesizedExpr |
A parenthesized expression sequence, typically containing a single expression. |
Literals are expressions that evaluate directly to the given value. The CodeQL Ruby library models all types of Ruby literal.
CodeQL class | Description |
---|---|
Literal |
A literal. This is the base class for all literals.
|
NumericLiteral |
A numerical literal. The literal types are IntegerLiteral , FloatLiteral , RationalLiteral , and ComplexLiteral . |
NilLiteral |
A nil literal. |
BooleanLiteral |
A Boolean value. The classes TrueLiteral and FalseLiteral match true and false respectively. |
StringComponent |
A component of a string. Either a StringTextComponent , StringEscapeSequenceComponent , or StringInterpolationComponent . |
RegExpLiteral |
A regular expression literal. |
SymbolLiteral |
A symbol literal. |
SubshellLiteral |
A subshell literal. |
CharacterLiteral |
A character literal. |
ArrayLiteral |
An array literal. |
HashLiteral |
A hash literal. |
RangeLiteral |
A range literal. |
MethodName |
A method name literal. |
The following example defines a string literal class containing the text “username”:
class UsernameLiteral extends Literal
{
UsernameLiteral() { this.getValueText().toLowerCase().matches("%username%") }
}
Operations are types of expression that typically perform some sort of calculation. Most operations are MethodCalls
because often
there is an underlying call to the operation.
CodeQL class | Description |
---|---|
Operation |
An operation. |
UnaryOperation |
A unary operation. Types of unary operation include |
DefinedExpr |
A call to the special defined? operator |
BinaryOperation |
A binary operation, that includes many other operation categories such as BinaryArithmeticOperation , BinaryBitwiseOperation , ComparisonOperation , SpaceshipExpr , and Assignment . |
BinaryArithmeticOperation |
A binary arithmetic operation. Includes: AddExpr , SubExpr , MulExpr , DivExpr , ModuloExpr , and ExponentExpr . |
BinaryLogicalOperation |
A binary logical operation. Includes: LogicalAndExpr and LogicalOrExpr . |
BinaryBitwiseOperation |
A binary bitwise operation. Includes: LShiftExpr , RShiftExpr , BitwiseAndExpr , BitwiseOrExpr , and BitwiseXorExpr . |
ComparisonOperation |
A comparison operation, including the classes EqualityOperation , EqExpr , NEExpr , CaseEqExpr , RelationalOperation , GTExpr , GEExpr , LTExpr , and LEExpr . |
RegExpMatchExpr |
A regexp match expression. |
NoRegExpMatchExpr |
A regexp-doesn’t-match expression. |
Assignment |
An assignment. Assignments are simple assignments ( The assignment arithmetic operations ( The assignment logical operations ( The assignment bitwise operations ( |
The following example finds “chained assignments” (of the form A=B=C
):
import codeql.ruby.AST
from Assignment op
where op.getRightOperand() instanceof Assignment
select op, "This is a chained assignment."
Calls pass control to another function, include explicit method calls (MethodCall
), but also include other types of call such as super calls or yield calls.
CodeQL class | Description and main predicates |
---|---|
Call |
A call.
|
MethodCall |
A method call.
|
SetterMethodCall |
A call to a setter method. |
ElementReference |
An element reference; a call to the [] method. |
YieldCall |
A call to yield. |
SuperCall |
A call to super. |
BlockArgument |
A block argument in a method call. |
The following example finds all method calls to a method called delete.
import codeql.ruby.AST
from MethodCall call
where call.getMethodName() = "delete"
select call, "Call to 'delete'."
Control expressions are expressions used for control flow. They are classed as expressions because they can produce a value.
CodeQL class | Description and main predicates |
---|---|
ControlExpr |
A control expression, such as a case, if, unless, ternary-if (?:), while, until (including expression-modifier variants), and for. |
ConditionalExpr |
A conditional expression.
|
IfExpr |
An if or elsif expression.
|
UnlessExpr |
An unless expression. |
IfModifierExpr |
An expression modified using if. |
UnlessModifierExpr |
An expression modified using unless. |
TernaryIfExpr |
A conditional expression using the ternary (?:) operator. |
CaseExpr |
A case expression. |
WhenExpr |
A when branch of a case expression. |
Loop |
A loop. That is, a for loop, a while or until loop, or their expression-modifier variants. |
ConditionalLoop |
A loop using a condition expression. That is, a while or until loop, or their expression-modifier variants.
|
WhileExpr |
A while loop. |
UntilExpr |
An until loop. |
WhileModifierExpr |
An expression looped using the while modifier. |
UntilModifierExpr |
An expression looped using the until modifier. |
ForExpr |
A for loop. |
The following example finds if-expressions that are missing a then branch.
import codeql.ruby.AST
from IfExpr expr
where not exists(expr.getThen())
select expr, "This if-expression is redundant."
Variables¶
Variables are names that hold values in a Ruby program. If you want to query any type
of variable, then use the Variable
class, otherwise use one of the subclasses
LocalVariable
, InstanceVariable
, ClassVariable
or GlobalVariable
.
Local variables have the scope of a single function or block, instance variables have the scope of an object (like member variables), class variables have the scope of a class and are shared between all instances of that class (like static variables), and global variables have the scope of the entire program.
CodeQL class | Description and main predicates |
---|---|
Variable |
A variable declared in a scope.
|
LocalVariable |
A local variable. |
InstanceVariable |
An instance variable. |
ClassVariable |
A class variable. |
GlobalVariable |
A global variable. |
The following example finds all class variables in the class StaticController:
import codeql.ruby.AST
from ClassDeclaration cd, ClassVariable v
where
v.getDeclaringScope() = cd and
cd.getName() = "StaticController"
select v, "This is a static variable in 'StaticController'."
Variable accesses are the uses of a variable in the source code. Note that variables, and uses of variables are different concepts.
Variables are modelled using the Variable
class, whereas uses of the variable are modelled using the VariableAccess
class.
Variable.getAnAccess()
gets the accesses of a variable.
Variable accesses come in two types: reads of the variable (a ReadAccess
), and writes to the variable (a WriteAccess
).
Accesses are a type of expression, so extend the Expr
class.
CodeQL class | Description and main predicates |
---|---|
VariableAccess |
An access to a variable.
|
VariableReadAccess |
An access to a variable where the value is read. |
VariableWriteAccess |
An access to a variable where the value is updated. |
LocalVariableAccess |
An access to a local variable. |
LocalVariableWriteAccess |
An access to a local variable where the value is updated. |
LocalVariableReadAccess |
An access to a local variable where the value is read. |
GlobalVariableAccess |
An access to a global variable where the value is updated. |
InstanceVariableAccess |
An access to a global variable where the value is read. |
InstanceVariableReadAccess |
An access to an instance variable. |
InstanceVariableWriteAccess |
An access to an instance variable where the value is updated. |
ClassVariableAccess |
An access to a class variable. |
ClassVariableWriteAccess |
An access to a class variable where the value is updated. |
ClassVariableReadAccess |
An access to a class variable where the value is read. |
The following example finds writes to class variables in the class StaticController:
import codeql.ruby.AST
from ClassVariableWriteAccess write, ClassDeclaration cd, ClassVariable v
where
v.getDeclaringScope() = cd and
cd.getName() = "StaticController" and
write.getVariable() = v
select write, "'StaticController' class variable is written here."