From 420d1c10d5869bf14e6d987b048a4c40d885783c Mon Sep 17 00:00:00 2001 From: AkshayK Date: Thu, 27 Aug 2026 15:08:27 -0400 Subject: [PATCH] cpp: model BDE bdlbb::Blob byte-buffer taint flow Add flow summaries for the BDE segmented byte buffer BloombergLP::bdlbb::Blob so taint reaches a blob's payload bytes: - Accessor chain: Blob::buffer taints the returned BlobBuffer, and BlobBuffer::data/buffer taint the bytes. - bdlbb::BlobUtil::copy and getContiguousRangeOrCopy propagate taint between a blob and a flat buffer in both directions. This unblocks blob-carried sources such as bmqa::Message::getData, whose payload was previously stranded on the opaque Blob object. Not a duplicate; the bdlbb namespace had no coverage. Verified with a BloombergLP::bdlbb-shaped stub in the dataflow external-models harness. --- .../2026-08-27-bdlbb-blob-models.md | 4 ++ cpp/ql/lib/ext/bdlbb.model.yml | 19 +++++ .../dataflow/external-models/bdlbb.cpp | 69 +++++++++++++++++++ .../dataflow/external-models/flow.expected | 48 ++++++++++++- .../dataflow/external-models/steps.expected | 8 +++ 5 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 cpp/ql/lib/change-notes/2026-08-27-bdlbb-blob-models.md create mode 100644 cpp/ql/lib/ext/bdlbb.model.yml create mode 100644 cpp/ql/test/library-tests/dataflow/external-models/bdlbb.cpp diff --git a/cpp/ql/lib/change-notes/2026-08-27-bdlbb-blob-models.md b/cpp/ql/lib/change-notes/2026-08-27-bdlbb-blob-models.md new file mode 100644 index 000000000000..f1db9d3c3116 --- /dev/null +++ b/cpp/ql/lib/change-notes/2026-08-27-bdlbb-blob-models.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added flow summaries for the BDE `bdlbb::Blob` segmented byte buffer (`BloombergLP::bdlbb`). Taint now flows from a blob to its bytes through the `Blob::buffer`/`BlobBuffer::data` accessor chain and through the `bdlbb::BlobUtil::copy` and `getContiguousRangeOrCopy` helpers, so a blob populated from untrusted input (for example a BlazingMQ message body read via `bmqa::Message::getData`) is tracked into the payload bytes. diff --git a/cpp/ql/lib/ext/bdlbb.model.yml b/cpp/ql/lib/ext/bdlbb.model.yml new file mode 100644 index 000000000000..82577f72095e --- /dev/null +++ b/cpp/ql/lib/ext/bdlbb.model.yml @@ -0,0 +1,19 @@ +# Model of the BDE bdlbb::Blob segmented byte buffer (BloombergLP::bdlbb). +# Lets taint reach a blob's payload bytes, e.g. a message body filled by bmqa::Message::getData. +extensions: + - addsTo: + pack: codeql/cpp-all + extensible: summaryModel + data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance + # Accessor chain: a tainted blob taints its buffers, and a tainted buffer taints its bytes. + - ["BloombergLP::bdlbb", "Blob", true, "buffer", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"] + - ["BloombergLP::bdlbb", "BlobBuffer", true, "data", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"] + # BlobUtil read-out: the source blob (Argument[*1]) taints the destination buffer (and the + # returned contiguous range). + - ["BloombergLP::bdlbb", "BlobUtil", true, "copy", "", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlbb", "BlobUtil", true, "getContiguousRangeOrCopy", "", "", "Argument[*1]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlbb", "BlobUtil", true, "getContiguousRangeOrCopy", "", "", "Argument[*1]", "ReturnValue[*]", "taint", "manual"] + # BlobUtil write-in: the source buffer/blob (Argument[*2]) taints the destination blob. + # (`copy` is overloaded with the source at index 1 or 2; the two rows cover both layouts, + # the extra one only ever reading an int offset/position argument.) + - ["BloombergLP::bdlbb", "BlobUtil", true, "copy", "", "", "Argument[*2]", "Argument[*0]", "taint", "manual"] diff --git a/cpp/ql/test/library-tests/dataflow/external-models/bdlbb.cpp b/cpp/ql/test/library-tests/dataflow/external-models/bdlbb.cpp new file mode 100644 index 000000000000..3a086dd2eeae --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/external-models/bdlbb.cpp @@ -0,0 +1,69 @@ + +// --- stub library headers --- + +namespace bsl { + typedef unsigned long size_t; + template class allocator {}; + template struct char_traits {}; + template, class Allocator = allocator > + class basic_string { + public: + basic_string(const charT* s, const Allocator& a = Allocator()); + const charT* data() const; + size_t size() const; + }; + typedef basic_string string; +} + +namespace BloombergLP { +namespace bdlbb { + class BlobBuffer { + public: + char *data() const; + }; + + class Blob { + public: + const BlobBuffer &buffer(int index) const; + }; + + struct BlobUtil { + static void copy(char *dstBuffer, const Blob &srcBlob, int position, int length); + static void copy(Blob *dstBlob, int dstOffset, const char *srcBuffer, int length); + static char *getContiguousRangeOrCopy(char *dstBuffer, const Blob &srcBlob, int position, + int length, int alignment); + }; +} +} + +// --- test code --- + +char *source(); +void sink(char); + +// A blob populated from a tainted buffer taints the bytes read back out of it. +void test_BlobUtil_copy() { + bsl::string s(source()); + BloombergLP::bdlbb::Blob blob; + BloombergLP::bdlbb::BlobUtil::copy(&blob, 0, s.data(), s.size()); + char dst[16]; + BloombergLP::bdlbb::BlobUtil::copy(dst, blob, 0, 16); + sink(*dst); // $ ir +} + +void test_accessor_chain() { + bsl::string s(source()); + BloombergLP::bdlbb::Blob blob; + BloombergLP::bdlbb::BlobUtil::copy(&blob, 0, s.data(), s.size()); + const char *p = blob.buffer(0).data(); + sink(*p); // $ ir +} + +void test_getContiguousRangeOrCopy() { + bsl::string s(source()); + BloombergLP::bdlbb::Blob blob; + BloombergLP::bdlbb::BlobUtil::copy(&blob, 0, s.data(), s.size()); + char dst[16]; + char *r = BloombergLP::bdlbb::BlobUtil::getContiguousRangeOrCopy(dst, blob, 0, 16, 1); + sink(*r); // $ ir +} diff --git a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected index b6f5f4a4452f..5c2d162efaff 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/flow.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/flow.expected @@ -95,7 +95,12 @@ models | 94 | Summary: Azure::Core::IO; BodyStream; true; ReadToCount; ; ; Argument[-1]; Argument[*0]; taint; manual | | 95 | Summary: Azure::Core::IO; BodyStream; true; ReadToEnd; ; ; Argument[-1]; ReturnValue.Element; taint; manual | | 96 | Summary: Azure; Nullable; true; Value; ; ; Argument[-1]; ReturnValue[*]; taint; manual | -| 97 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | +| 97 | Summary: BloombergLP::bdlbb; Blob; true; buffer; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 98 | Summary: BloombergLP::bdlbb; BlobBuffer; true; data; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 99 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; ; ; Argument[*1]; Argument[*0]; taint; manual | +| 100 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; ; ; Argument[*2]; Argument[*0]; taint; manual | +| 101 | Summary: BloombergLP::bdlbb; BlobUtil; true; getContiguousRangeOrCopy; ; ; Argument[*1]; ReturnValue[*]; taint; manual | +| 102 | Summary: boost::asio; ; false; buffer; ; ; Argument[*0]; ReturnValue; taint; manual | edges | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:91:7:91:17 | recv_buffer | provenance | Src:MaD:56 | | asio_streams.cpp:87:34:87:44 | read_until output argument | asio_streams.cpp:93:29:93:39 | recv_buffer | provenance | Src:MaD:56 Sink:MaD:4 | @@ -104,7 +109,7 @@ edges | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:101:7:101:17 | send_buffer | provenance | | | asio_streams.cpp:100:44:100:62 | call to buffer | asio_streams.cpp:103:29:103:39 | send_buffer | provenance | Sink:MaD:4 | -| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:97 | +| asio_streams.cpp:100:64:100:71 | *send_str | asio_streams.cpp:100:44:100:62 | call to buffer | provenance | MaD:102 | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:257:5:257:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:262:5:262:8 | *resp | provenance | | | azure.cpp:253:48:253:60 | *call to GetBodyStream | azure.cpp:266:38:266:41 | *resp | provenance | | @@ -144,6 +149,24 @@ edges | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:294:38:294:53 | call to operator[] | azure.cpp:295:10:295:20 | contentType | provenance | | | azure.cpp:295:10:295:20 | contentType | azure.cpp:295:10:295:20 | contentType | provenance | | +| bdlbb.cpp:46:16:46:23 | call to source | bdlbb.cpp:48:49:48:52 | *call to data | provenance | TaintFunction | +| bdlbb.cpp:48:37:48:41 | copy output argument | bdlbb.cpp:50:42:50:45 | *blob | provenance | | +| bdlbb.cpp:48:49:48:52 | *call to data | bdlbb.cpp:48:37:48:41 | copy output argument | provenance | MaD:100 | +| bdlbb.cpp:50:37:50:39 | copy output argument | bdlbb.cpp:51:7:51:10 | * ... | provenance | | +| bdlbb.cpp:50:42:50:45 | *blob | bdlbb.cpp:50:37:50:39 | copy output argument | provenance | MaD:99 | +| bdlbb.cpp:55:16:55:23 | call to source | bdlbb.cpp:57:49:57:52 | *call to data | provenance | TaintFunction | +| bdlbb.cpp:57:37:57:41 | copy output argument | bdlbb.cpp:58:18:58:21 | *blob | provenance | | +| bdlbb.cpp:57:49:57:52 | *call to data | bdlbb.cpp:57:37:57:41 | copy output argument | provenance | MaD:100 | +| bdlbb.cpp:58:18:58:21 | *blob | bdlbb.cpp:58:29:58:32 | *call to buffer | provenance | MaD:97 | +| bdlbb.cpp:58:18:58:38 | *call to data | bdlbb.cpp:58:18:58:38 | *call to data | provenance | | +| bdlbb.cpp:58:18:58:38 | *call to data | bdlbb.cpp:59:7:59:8 | * ... | provenance | | +| bdlbb.cpp:58:29:58:32 | *call to buffer | bdlbb.cpp:58:18:58:38 | *call to data | provenance | MaD:98 | +| bdlbb.cpp:63:16:63:23 | call to source | bdlbb.cpp:65:49:65:52 | *call to data | provenance | TaintFunction | +| bdlbb.cpp:65:37:65:41 | copy output argument | bdlbb.cpp:67:72:67:75 | *blob | provenance | | +| bdlbb.cpp:65:49:65:52 | *call to data | bdlbb.cpp:65:37:65:41 | copy output argument | provenance | MaD:100 | +| bdlbb.cpp:67:12:67:65 | *call to getContiguousRangeOrCopy | bdlbb.cpp:67:12:67:65 | *call to getContiguousRangeOrCopy | provenance | | +| bdlbb.cpp:67:12:67:65 | *call to getContiguousRangeOrCopy | bdlbb.cpp:68:7:68:8 | * ... | provenance | | +| bdlbb.cpp:67:72:67:75 | *blob | bdlbb.cpp:67:12:67:65 | *call to getContiguousRangeOrCopy | provenance | MaD:101 | | test.cpp:7:47:7:52 | value2 | test.cpp:7:64:7:69 | value2 | provenance | | | test.cpp:7:64:7:69 | value2 | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | provenance | | | test.cpp:10:10:10:18 | call to ymlSource | test.cpp:10:10:10:18 | call to ymlSource | provenance | Src:MaD:48 | @@ -532,6 +555,27 @@ nodes | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | | azure.cpp:295:10:295:20 | contentType | semmle.label | contentType | +| bdlbb.cpp:46:16:46:23 | call to source | semmle.label | call to source | +| bdlbb.cpp:48:37:48:41 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:48:49:48:52 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:50:37:50:39 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:50:42:50:45 | *blob | semmle.label | *blob | +| bdlbb.cpp:51:7:51:10 | * ... | semmle.label | * ... | +| bdlbb.cpp:55:16:55:23 | call to source | semmle.label | call to source | +| bdlbb.cpp:57:37:57:41 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:57:49:57:52 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:58:18:58:21 | *blob | semmle.label | *blob | +| bdlbb.cpp:58:18:58:38 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:58:18:58:38 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:58:29:58:32 | *call to buffer | semmle.label | *call to buffer | +| bdlbb.cpp:59:7:59:8 | * ... | semmle.label | * ... | +| bdlbb.cpp:63:16:63:23 | call to source | semmle.label | call to source | +| bdlbb.cpp:65:37:65:41 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:65:49:65:52 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:67:12:67:65 | *call to getContiguousRangeOrCopy | semmle.label | *call to getContiguousRangeOrCopy | +| bdlbb.cpp:67:12:67:65 | *call to getContiguousRangeOrCopy | semmle.label | *call to getContiguousRangeOrCopy | +| bdlbb.cpp:67:72:67:75 | *blob | semmle.label | *blob | +| bdlbb.cpp:68:7:68:8 | * ... | semmle.label | * ... | | test.cpp:7:5:7:30 | *ymlStepGenerated_with_body | semmle.label | *ymlStepGenerated_with_body | | test.cpp:7:47:7:52 | value2 | semmle.label | value2 | | test.cpp:7:64:7:69 | value2 | semmle.label | value2 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected index 0fe13460cfbf..4a17c1d95d65 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/steps.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/steps.expected @@ -4,6 +4,14 @@ | azure.cpp:262:5:262:8 | *resp | azure.cpp:262:23:262:28 | ReadToCount output argument | | azure.cpp:287:79:287:98 | call to string | azure.cpp:287:62:287:99 | call to Url | | azure.cpp:289:24:289:56 | call to GetHeader | azure.cpp:289:63:289:65 | call to Value | +| bdlbb.cpp:48:49:48:52 | *call to data | bdlbb.cpp:48:37:48:41 | copy output argument | +| bdlbb.cpp:50:42:50:45 | *blob | bdlbb.cpp:50:37:50:39 | copy output argument | +| bdlbb.cpp:57:49:57:52 | *call to data | bdlbb.cpp:57:37:57:41 | copy output argument | +| bdlbb.cpp:58:18:58:21 | *blob | bdlbb.cpp:58:29:58:32 | *call to buffer | +| bdlbb.cpp:58:29:58:32 | *call to buffer | bdlbb.cpp:58:18:58:38 | *call to data | +| bdlbb.cpp:65:49:65:52 | *call to data | bdlbb.cpp:65:37:65:41 | copy output argument | +| bdlbb.cpp:67:72:67:75 | *blob | bdlbb.cpp:67:12:67:65 | *call to getContiguousRangeOrCopy | +| bdlbb.cpp:67:72:67:75 | *blob | bdlbb.cpp:67:67:67:69 | getContiguousRangeOrCopy output argument | | test.cpp:17:24:17:24 | x | test.cpp:17:10:17:22 | call to ymlStepManual | | test.cpp:21:27:21:27 | x | test.cpp:21:10:21:25 | call to ymlStepGenerated | | test.cpp:25:35:25:35 | x | test.cpp:25:11:25:33 | call to ymlStepManual_with_body |