Skip to content

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

Open
kumarak wants to merge 3 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 3 commits into
github:mainfrom
trail-of-forks:kumarak/cpp-protobuf-flow-models

Conversation

@kumarak

@kumarak kumarak commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

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.

Comment thread cpp/ql/lib/ext/Protobuf.model.yml Outdated
Comment thread cpp/ql/test/library-tests/dataflow/external-models/protobuf.cpp Outdated
Comment thread cpp/ql/lib/change-notes/2026-08-27-protobuf-models.md Outdated

@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.

Some further comments. I think the .yml file looks good now. I would still significantly reduce the number of comments, which don't seem to add much.

---
category: minorAnalysis
---
* Added flow summaries for the Protocol Buffers C++ API (`google::protobuf::MessageLite`, covering `Message` and all generated messages).

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.

Suggested change
* Added flow summaries for the Protocol Buffers C++ API (`google::protobuf::MessageLite`, covering `Message` and all generated messages).
* Added flow summaries for the Protocol Buffers `google::protobuf::MessageLite` C++ API.

Comment on lines +6 to +10
# Flow summaries for the Protocol Buffers C++ API. All of these methods are declared on
# `google::protobuf::MessageLite`; `subtypes` covers `Message` and every generated message.
#
# File-descriptor variants (`{Parse,Serialize}*FromFileDescriptor`) are intentionally omitted:
# the descriptor is an `int`, not a data buffer, so there is no buffer argument to model.

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.

Suggested change
# Flow summaries for the Protocol Buffers C++ API. All of these methods are declared on
# `google::protobuf::MessageLite`; `subtypes` covers `Message` and every generated message.
#
# File-descriptor variants (`{Parse,Serialize}*FromFileDescriptor`) are intentionally omitted:
# the descriptor is an `int`, not a data buffer, so there is no buffer argument to model.
# File-descriptor variants (`{Parse,Serialize}*FromFileDescriptor`) are intentionally omitted:
# the descriptor is an `int`, not a data buffer, so there is no buffer argument to model.

Comment on lines +12 to +15
# Deserialization: the encoded input taints the message (`this`). The `*FromString` methods each
# have a `string_view` overload (the buffer is the by-value argument, so `Argument[0]`) and a
# `const Cord &` overload (the buffer is behind a reference, so `Argument[*0]`). The remaining
# inputs below are pointers or references, so they take `Argument[*0]`.

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.

Suggested change
# Deserialization: the encoded input taints the message (`this`). The `*FromString` methods each
# have a `string_view` overload (the buffer is the by-value argument, so `Argument[0]`) and a
# `const Cord &` overload (the buffer is behind a reference, so `Argument[*0]`). The remaining
# inputs below are pointers or references, so they take `Argument[*0]`.
# Deserialization

- ["google::protobuf", "MessageLite", True, "MergeFromCodedStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
- ["google::protobuf", "MessageLite", True, "MergePartialFromCodedStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]

# Serialization into an output buffer/stream: the message (`this`) taints `Argument[*0]`.

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.

Suggested change
# Serialization into an output buffer/stream: the message (`this`) taints `Argument[*0]`.
# Serialization

- ["google::protobuf", "MessageLite", True, "SerializeToCodedStream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
- ["google::protobuf", "MessageLite", True, "SerializePartialToCodedStream", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]

# Serialization returning the bytes: the message (`this`) taints the (by-value) return value.

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.

Suggested change
# Serialization returning the bytes: the message (`this`) taints the (by-value) return value.
# Serialization returning bytes

}

namespace absl {
// `absl::string_view` is passed by value; `absl::Cord` is passed by const reference.

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 is completely out-of-context here. I'd just remove it.

Suggested change
// `absl::string_view` is passed by value; `absl::Cord` is passed by const reference.

Comment on lines +59 to +61
// A faithful subset of `MessageLite`. The string/Cord/stream signatures mirror the real
// `message_lite.h`; the iostream-based methods are declared on `Message` in the real headers
// but are modeled here on `MessageLite` (with `subtypes` covering `Message`).

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 read like a shortcut was taken that does not accurately represent actual protobuf. This should be fixed.


// Every modeled method is called below so its summary step is covered by `steps.ql`. Endpoint
// mistakes and rows that fail to bind show up as missing lines in `steps.expected`.
void test_step_coverage() {

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.

None of the "tests" below tell me that any of this is actually working. Ideally there should be sink calls here with // $ ir annotations.

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