← 返回首页
Customizing library models for C and C++ — CodeQL CodeQL docs
CodeQL documentation
CodeQL resources

Customizing library models for C and C++

You can model the methods and callables that control data flow in any framework or library. This is especially useful for custom frameworks or niche libraries, that are not supported by the standard CodeQL libraries.

Beta Notice - Unstable API

Library customization using data extensions is currently in beta and subject to change.

Breaking changes to this format may occur while in beta.

About this article

This article contains reference material about how to define custom models for sources, sinks, and flow summaries for C and C++ dependencies in data extension files.

About data extensions

You can customize analysis by defining models (summaries, sinks, and sources) of your code’s C and C++ dependencies in data extension files. Each model defines the behavior of one or more elements of your library or framework, such as callables. When you run dataflow analysis, these models expand the potential sources and sinks tracked by dataflow analysis and improve the precision of results.

Many of the security queries search for paths from a source of untrusted input to a sink that represents a vulnerability. This is known as taint tracking. Each source is a starting point for dataflow analysis to track tainted data and each sink is an end point.

Taint tracking queries also need to know how data can flow through elements that are not included in the source code. These are modeled as summaries. A summary model enables queries to synthesize the flow behavior through elements in dependency code that is not stored in your repository.

Syntax used to define an element in an extension file

Each model of an element is defined using a data extension where each tuple constitutes a model. A data extension file to extend the standard CPP queries included with CodeQL is a YAML file with the form:

extensions: - addsTo: pack: codeql/cpp-all extensible: <name of extensible predicate> data: - <tuple1> - <tuple2> - ...

Each YAML file may contain one or more top-level extensions.

Data extensions use union semantics, which means that the tuples of all extensions for a single extensible predicate are combined, duplicates are removed, and all of the remaining tuples are queryable by referencing the extensible predicate.

Publish data extension files in a CodeQL model pack to share

You can group one or more data extension files into a CodeQL model pack and publish it to the GitHub Container Registry. This makes it easy for anyone to download the model pack and use it to extend their analysis. For more information, see Creating a CodeQL model pack and Publishing and using CodeQL packs in the CodeQL CLI documentation.

Extensible predicates used to create custom models in C and C++

The CodeQL library for CPP analysis exposes the following extensible predicates:

The extensible predicates are populated using the models defined in data extension files.

Example of custom model definitions

The examples in this section are taken from the standard CodeQL CPP query pack published by GitHub. They demonstrate how to add tuples to extend extensible predicates that are used by the standard queries.

Example: Taint source from the boost::asio namespace

This example shows how the CPP query pack models the return value from the read_until function as a remote source.

boost::asio::read_until(socket, recv_buffer, '\0', error);

We need to add a tuple to the sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) extensible predicate by updating a data extension file.

extensions: - addsTo: pack: codeql/cpp-all extensible: sourceModel data: - ["boost::asio", "", False, "read_until", "", "", "Argument[*1]", "remote", "manual"]

The first five values identify the callable (in this case a free function) to be modeled as a source.

The sixth value should be left empty and is out of scope for this documentation. The remaining values are used to define the output specification, the kind, and the provenance (origin) of the source.

Example: Taint sink in the boost::asio namespace

This example shows how the CPP query pack models the second argument of the boost::asio::write function as a remote flow sink. A remote flow sink is where data is transmitted to other machines across a network, which is used for example by the “Cleartext transmission of sensitive information” (cpp/cleartext-transmission) query.

boost::asio::write(socket, send_buffer, error);

We need to add a tuple to the sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance) extensible predicate by updating a data extension file.

extensions: - addsTo: pack: codeql/cpp-all extensible: sinkModel data: - ["boost::asio", "", False, "write", "", "", "Argument[*1]", "remote-sink", "manual"]

The first five values identify the callable (in this case a free function) to be modeled as a sink.

The sixth value should be left empty and is out of scope for this documentation. The remaining values are used to define the output specification, the kind, and the provenance (origin) of the sink.

Example: Add flow through the boost::asio::buffer method

This example shows how the CPP query pack models flow through a function for a simple case.

boost::asio::write(socket, boost::asio::buffer(send_str), error);

We need to add tuples to the summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) extensible predicate by updating a data extension file:

extensions: - addsTo: pack: codeql/cpp-all extensible: summaryModel data: - ["boost::asio", "", False, "buffer", "", "", "Argument[*0]", "ReturnValue", "taint", "manual"]

The first five values identify the callable (in this case free function) to be modeled as a summary.

The sixth value should be left empty and is out of scope for this documentation. The remaining values are used to define the input and output specifications, the kind, and the provenance (origin) of the summary.

Example: Taint barrier using the mysql_real_escape_string function

This example shows how the CPP query pack models the mysql_real_escape_string function as a barrier for SQL injection. This function escapes special characters in a string for use in an SQL statement, which prevents SQL injection attacks.

char *query = "SELECT * FROM users WHERE name = '%s'"; char *name = get_untrusted_input(); char *escaped_name = new char[2 * strlen(name) + 1]; mysql_real_escape_string(mysql, escaped_name, name, strlen(name)); // The escaped_name is safe for SQL injection. sprintf(query_buffer, query, escaped_name);

We need to add a tuple to the barrierModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) extensible predicate by updating a data extension file.

extensions: - addsTo: pack: codeql/cpp-all extensible: barrierModel data: - ["", "", False, "mysql_real_escape_string", "", "", "Argument[*1]", "sql-injection", "manual"]

The first five values identify the callable (in this case a free function) to be modeled as a barrier.

The sixth value should be left empty and is out of scope for this documentation. The remaining values are used to define the output specification, the kind, and the provenance (origin) of the barrier.

Example: Add a barrier guard

This example shows how to model a barrier guard that stops the flow of taint when a conditional check is performed on data. A barrier guard model is used when a function returns a boolean that indicates whether the data is safe to use. Consider a function called is_safe which returns true when the data is considered safe.

if (is_safe(user_input)) { // The check guards the use, so the input is safe. mysql_query(user_input); // This is safe. }

We need to add a tuple to the barrierGuardModel(namespace, type, subtypes, name, signature, ext, input, acceptingValue, kind, provenance) extensible predicate by updating a data extension file.

extensions: - addsTo: pack: codeql/cpp-all extensible: barrierGuardModel data: - ["", "", False, "is_safe", "", "", "Argument[*0]", "true", "sql-injection", "manual"]

The first five values identify the callable (in this case a free function) to be modeled as a barrier guard.

The sixth value should be left empty and is out of scope for this documentation. The remaining values are used to define the input specification, the accepting-value, the kind, and the provenance (origin) of the barrier guard.

Threat models

Note

Threat models are currently in beta and subject to change. During the beta, threat models are supported only by Java, C#, Python and JavaScript/TypeScript analysis.

A threat model is a named class of dataflow sources that can be enabled or disabled independently. Threat models allow you to control the set of dataflow sources that you want to consider unsafe. For example, one codebase may only consider remote HTTP requests to be tainted, whereas another may also consider data from local files to be unsafe. You can use threat models to ensure that the relevant taint sources are used in a CodeQL analysis.

The kind property of the sourceModel determines which threat model a source is associated with. There are two main categories:

Note that subcategories can be turned included or excluded separately, so you can specify local without database, or just commandargs and environment without the rest of local.

The less commonly used categories are:

When running a CodeQL analysis, the remote threat model is included by default. You can optionally include other threat models as appropriate when using the CodeQL CLI and in GitHub code scanning. For more information, see Analyzing your code with CodeQL queries and Customizing your advanced setup for code scanning.