Skip to content

cpp: model Protocol Buffers parse/serialize taint flow - #22448

Open
kumarak wants to merge 2 commits into
github:mainfrom
trail-of-forks:kumarak/cpp-protobuf-flow-models
Open

cpp: model Protocol Buffers parse/serialize taint flow#22448
kumarak wants to merge 2 commits into
github:mainfrom
trail-of-forks:kumarak/cpp-protobuf-flow-models

Conversation

@kumarak

@kumarak kumarak commented Aug 27, 2026

Copy link
Copy Markdown

Add flow summaries for the protobuf C++ API on google::protobuf::MessageLite (subtypes=true, so Message and all generated messages are covered):

  • ParseFrom*/MergeFrom* (string, array, Cord, istream, zero-copy and coded-stream forms) propagate taint from the encoded input to the message.
  • SerializeTo*/AppendTo* propagate taint from the message to the output buffer or stream; SerializeAs*/AppendTo* to the return value.
  • File-descriptor variants are omitted (the fd is an int, not a buffer).

Add flow summaries for the protobuf C++ API on
google::protobuf::MessageLite (subtypes=true, so Message and all
generated messages are covered):

- ParseFrom*/MergeFrom* (string, array, Cord, istream, zero-copy and
  coded-stream forms) propagate taint from the encoded input to the
  message.
- SerializeTo*/AppendTo* propagate taint from the message to the output
  buffer or stream; SerializeAs*/... to the return value.

File-descriptor variants are omitted (the fd is an int, not a buffer).
@kumarak
kumarak requested a review from a team as a code owner August 27, 2026 15:30
Copilot AI balanced review requested due to automatic review settings August 27, 2026 15:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds C++ taint-flow summaries for Protocol Buffers MessageLite APIs and inherited generated message types.

Changes:

  • Models parse/merge and serialization flows.
  • Adds representative flow tests and expected results.
  • Documents the analysis improvement.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
cpp/ql/lib/ext/Protobuf.model.yml Defines protobuf flow summaries.
cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp Adds protobuf test fixtures.
cpp/ql/test/library-tests/dataflow/external-models/flow.expected Updates flow expectations.
cpp/ql/test/library-tests/dataflow/external-models/steps.expected Updates summary-step expectations.
cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md Records the new models.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +25 to +29
- ["google::protobuf", "MessageLite", True, "ParseFromZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["google::protobuf", "MessageLite", True, "ParsePartialFromZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["google::protobuf", "MessageLite", True, "ParseFromBoundedZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["google::protobuf", "MessageLite", True, "ParsePartialFromBoundedZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["google::protobuf", "MessageLite", True, "MergeFromBoundedZeroCopyStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]

@jketema jketema left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. I made a brief first pass over this, which should hopefully put you on the right path.

# the descriptor is an `int`, not a data buffer, so there is no buffer argument to model.

# Deserialization: the encoded input (`Argument[*0]`) taints the message (`this`).
- ["google::protobuf", "MessageLite", True, "ParseFromString", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]

@jketema jketema Aug 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have only looked at this one for now, but this seems incorrect, as protobuf specifies the following prototypes:

bool ParseFromString(absl::string_view data);
bool ParseFromString(const absl::Cord& data);

As the first of the string_view parameter is not a reference, Argument[*0] is incorrect, as the * indicates there is a pointer that needs to be dereferenced to get to the tainted data (a reference like in const absl::Cord& counts as one).

This means that this will need to be split up in two lines:

["google::protobuf", "MessageLite", True, "ParseFromString", "(string_view)", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
["google::protobuf", "MessageLite", True, "ParseFromString", "(const Cord &)", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]

Observe that the input arguments are different.

// in the real headers (message_lite.h), including the iostream-based ones.
class MessageLite {
public:
bool ParseFromString(const std::string &data);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks incorrect. The correct prototypes seem to be:

bool ParseFromString(absl::string_view data);
bool ParseFromString(const absl::Cord& data);

There are similar problems with at least some of the below prototypes too.

Comment thread cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md Outdated
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants