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..ed52e5e091e2 --- /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 `BloombergLP::bdlbb::Blob` segmented byte buffer. diff --git a/cpp/ql/lib/ext/bdlbb.model.yml b/cpp/ql/lib/ext/bdlbb.model.yml new file mode 100644 index 000000000000..e5c50207c464 --- /dev/null +++ b/cpp/ql/lib/ext/bdlbb.model.yml @@ -0,0 +1,18 @@ +# 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 + - ["BloombergLP::bdlbb", "Blob", true, "buffer", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"] + - ["BloombergLP::bdlbb", "BlobBuffer", true, "data", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"] + - ["BloombergLP::bdlbb", "BlobBuffer", true, "buffer", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"] + # BlobUtil read-out + - ["BloombergLP::bdlbb", "BlobUtil", true, "copy", "(char *,const Blob &,int,int)", "", "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 + - ["BloombergLP::bdlbb", "BlobUtil", true, "copy", "(Blob *,int,const char *,int)", "", "Argument[*2]", "Argument[*0]", "taint", "manual"] + - ["BloombergLP::bdlbb", "BlobUtil", true, "copy", "(Blob *,int,const Blob &,int,int)", "", "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..c8ec9dfd031e --- /dev/null +++ b/cpp/ql/test/library-tests/dataflow/external-models/bdlbb.cpp @@ -0,0 +1,98 @@ + +// --- 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; + template class shared_ptr { + public: + T *get() const; + }; +} + +namespace BloombergLP { +namespace bdlbb { + class BlobBuffer { + public: + char *data() const; + bsl::shared_ptr &buffer(); + const bsl::shared_ptr &buffer() 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 void copy(Blob *dstBlob, int dstOffset, const Blob &srcBlob, int srcOffset, + 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 +} + +// The get() step comes from the built-in smart pointer model, not from bdlbb.model.yml. +void test_accessor_chain_shared_ptr() { + bsl::string s(source()); + BloombergLP::bdlbb::Blob blob; + BloombergLP::bdlbb::BlobUtil::copy(&blob, 0, s.data(), s.size()); + const char *p = blob.buffer(0).buffer().get(); + 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 +} + +// A blob copied into another blob carries the taint across. +void test_BlobUtil_copy_blob_to_blob() { + bsl::string s(source()); + BloombergLP::bdlbb::Blob src; + BloombergLP::bdlbb::BlobUtil::copy(&src, 0, s.data(), s.size()); + BloombergLP::bdlbb::Blob dst; + BloombergLP::bdlbb::BlobUtil::copy(&dst, 0, src, 0, 16); + char out[16]; + BloombergLP::bdlbb::BlobUtil::copy(out, dst, 0, 16); + sink(*out); // $ 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..96bd8c372936 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,14 @@ 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; buffer; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 99 | Summary: BloombergLP::bdlbb; BlobBuffer; true; data; ; ; Argument[-1]; ReturnValue[*]; taint; manual | +| 100 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (Blob *,int,const Blob &,int,int); ; Argument[*2]; Argument[*0]; taint; manual | +| 101 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (Blob *,int,const char *,int); ; Argument[*2]; Argument[*0]; taint; manual | +| 102 | Summary: BloombergLP::bdlbb; BlobUtil; true; copy; (char *,const Blob &,int,int); ; Argument[*1]; Argument[*0]; taint; manual | +| 103 | Summary: BloombergLP::bdlbb; BlobUtil; true; getContiguousRangeOrCopy; ; ; Argument[*1]; ReturnValue[*]; taint; manual | +| 104 | 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 +111,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:104 | | 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 +151,38 @@ 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:54:16:54:23 | call to source | bdlbb.cpp:56:49:56:52 | *call to data | provenance | TaintFunction | +| bdlbb.cpp:56:37:56:41 | copy output argument | bdlbb.cpp:58:42:58:45 | *blob | provenance | | +| bdlbb.cpp:56:49:56:52 | *call to data | bdlbb.cpp:56:37:56:41 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:58:37:58:39 | copy output argument | bdlbb.cpp:59:7:59:10 | * ... | provenance | | +| bdlbb.cpp:58:42:58:45 | *blob | bdlbb.cpp:58:37:58:39 | copy output argument | provenance | MaD:102 | +| 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:66:18:66:21 | *blob | provenance | | +| bdlbb.cpp:65:49:65:52 | *call to data | bdlbb.cpp:65:37:65:41 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:66:18:66:21 | *blob | bdlbb.cpp:66:29:66:32 | *call to buffer | provenance | MaD:97 | +| bdlbb.cpp:66:18:66:38 | *call to data | bdlbb.cpp:66:18:66:38 | *call to data | provenance | | +| bdlbb.cpp:66:18:66:38 | *call to data | bdlbb.cpp:67:7:67:8 | * ... | provenance | | +| bdlbb.cpp:66:29:66:32 | *call to buffer | bdlbb.cpp:66:18:66:38 | *call to data | provenance | MaD:99 | +| bdlbb.cpp:72:16:72:23 | call to source | bdlbb.cpp:74:49:74:52 | *call to data | provenance | TaintFunction | +| bdlbb.cpp:74:37:74:41 | copy output argument | bdlbb.cpp:75:18:75:21 | *blob | provenance | | +| bdlbb.cpp:74:49:74:52 | *call to data | bdlbb.cpp:74:37:74:41 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:75:18:75:21 | *blob | bdlbb.cpp:75:29:75:32 | *call to buffer | provenance | MaD:97 | +| bdlbb.cpp:75:18:75:46 | call to get | bdlbb.cpp:76:7:76:8 | * ... | provenance | | +| bdlbb.cpp:75:29:75:32 | *call to buffer | bdlbb.cpp:75:39:75:41 | *call to buffer | provenance | MaD:98 | +| bdlbb.cpp:75:39:75:41 | *call to buffer | bdlbb.cpp:75:18:75:46 | call to get | provenance | DataFlowFunction | +| bdlbb.cpp:80:16:80:23 | call to source | bdlbb.cpp:82:49:82:52 | *call to data | provenance | TaintFunction | +| bdlbb.cpp:82:37:82:41 | copy output argument | bdlbb.cpp:84:72:84:75 | *blob | provenance | | +| bdlbb.cpp:82:49:82:52 | *call to data | bdlbb.cpp:82:37:82:41 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | provenance | | +| bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | bdlbb.cpp:85:7:85:8 | * ... | provenance | | +| bdlbb.cpp:84:72:84:75 | *blob | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | provenance | MaD:103 | +| bdlbb.cpp:90:16:90:23 | call to source | bdlbb.cpp:92:48:92:51 | *call to data | provenance | TaintFunction | +| bdlbb.cpp:92:37:92:40 | copy output argument | bdlbb.cpp:94:46:94:48 | *src | provenance | | +| bdlbb.cpp:92:48:92:51 | *call to data | bdlbb.cpp:92:37:92:40 | copy output argument | provenance | MaD:101 | +| bdlbb.cpp:94:37:94:40 | copy output argument | bdlbb.cpp:96:42:96:44 | *dst | provenance | | +| bdlbb.cpp:94:46:94:48 | *src | bdlbb.cpp:94:37:94:40 | copy output argument | provenance | MaD:100 | +| bdlbb.cpp:96:37:96:39 | copy output argument | bdlbb.cpp:97:7:97:10 | * ... | provenance | | +| bdlbb.cpp:96:42:96:44 | *dst | bdlbb.cpp:96:37:96:39 | copy output argument | provenance | MaD:102 | | 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 +571,43 @@ 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:54:16:54:23 | call to source | semmle.label | call to source | +| bdlbb.cpp:56:37:56:41 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:56:49:56:52 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:58:37:58:39 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:58:42:58:45 | *blob | semmle.label | *blob | +| bdlbb.cpp:59:7:59:10 | * ... | 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:66:18:66:21 | *blob | semmle.label | *blob | +| bdlbb.cpp:66:18:66:38 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:66:18:66:38 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:66:29:66:32 | *call to buffer | semmle.label | *call to buffer | +| bdlbb.cpp:67:7:67:8 | * ... | semmle.label | * ... | +| bdlbb.cpp:72:16:72:23 | call to source | semmle.label | call to source | +| bdlbb.cpp:74:37:74:41 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:74:49:74:52 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:75:18:75:21 | *blob | semmle.label | *blob | +| bdlbb.cpp:75:18:75:46 | call to get | semmle.label | call to get | +| bdlbb.cpp:75:29:75:32 | *call to buffer | semmle.label | *call to buffer | +| bdlbb.cpp:75:39:75:41 | *call to buffer | semmle.label | *call to buffer | +| bdlbb.cpp:76:7:76:8 | * ... | semmle.label | * ... | +| bdlbb.cpp:80:16:80:23 | call to source | semmle.label | call to source | +| bdlbb.cpp:82:37:82:41 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:82:49:82:52 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | semmle.label | *call to getContiguousRangeOrCopy | +| bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | semmle.label | *call to getContiguousRangeOrCopy | +| bdlbb.cpp:84:72:84:75 | *blob | semmle.label | *blob | +| bdlbb.cpp:85:7:85:8 | * ... | semmle.label | * ... | +| bdlbb.cpp:90:16:90:23 | call to source | semmle.label | call to source | +| bdlbb.cpp:92:37:92:40 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:92:48:92:51 | *call to data | semmle.label | *call to data | +| bdlbb.cpp:94:37:94:40 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:94:46:94:48 | *src | semmle.label | *src | +| bdlbb.cpp:96:37:96:39 | copy output argument | semmle.label | copy output argument | +| bdlbb.cpp:96:42:96:44 | *dst | semmle.label | *dst | +| bdlbb.cpp:97:7:97:10 | * ... | 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..42d2c0183c34 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,20 @@ | 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:56:49:56:52 | *call to data | bdlbb.cpp:56:37:56:41 | copy output argument | +| bdlbb.cpp:58:42:58:45 | *blob | bdlbb.cpp:58:37:58:39 | copy output argument | +| bdlbb.cpp:65:49:65:52 | *call to data | bdlbb.cpp:65:37:65:41 | copy output argument | +| bdlbb.cpp:66:18:66:21 | *blob | bdlbb.cpp:66:29:66:32 | *call to buffer | +| bdlbb.cpp:66:29:66:32 | *call to buffer | bdlbb.cpp:66:18:66:38 | *call to data | +| bdlbb.cpp:74:49:74:52 | *call to data | bdlbb.cpp:74:37:74:41 | copy output argument | +| bdlbb.cpp:75:18:75:21 | *blob | bdlbb.cpp:75:29:75:32 | *call to buffer | +| bdlbb.cpp:75:29:75:32 | *call to buffer | bdlbb.cpp:75:39:75:41 | *call to buffer | +| bdlbb.cpp:82:49:82:52 | *call to data | bdlbb.cpp:82:37:82:41 | copy output argument | +| bdlbb.cpp:84:72:84:75 | *blob | bdlbb.cpp:84:12:84:65 | *call to getContiguousRangeOrCopy | +| bdlbb.cpp:84:72:84:75 | *blob | bdlbb.cpp:84:67:84:69 | getContiguousRangeOrCopy output argument | +| bdlbb.cpp:92:48:92:51 | *call to data | bdlbb.cpp:92:37:92:40 | copy output argument | +| bdlbb.cpp:94:46:94:48 | *src | bdlbb.cpp:94:37:94:40 | copy output argument | +| bdlbb.cpp:96:42:96:44 | *dst | bdlbb.cpp:96:37:96:39 | copy 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 | diff --git a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected index 15ae50bddc26..1fbe5da66459 100644 --- a/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected +++ b/cpp/ql/test/library-tests/dataflow/external-models/validatemodels.expected @@ -370,6 +370,8 @@ | Dubious signature "(BN_MONT_CTX *,const BIGNUM *,int,const unsigned char *,size_t,uint32_t,uint32_t)" in summary model. | | Dubious signature "(BN_RECP_CTX *,const BIGNUM *,BN_CTX *)" in summary model. | | Dubious signature "(BUF_MEM *,size_t)" in summary model. | +| Dubious signature "(Blob *,int,const Blob &,int,int)" in summary model. | +| Dubious signature "(Blob *,int,const char *,int)" in summary model. | | Dubious signature "(BrotliBitReader *const,uint64_t,uint64_t *)" in summary model. | | Dubious signature "(BrotliDecoderState *,BrotliDecoderStateInternal *,BrotliSharedDictionaryType,size_t,const uint8_t[])" in summary model. | | Dubious signature "(BrotliDecoderState *,BrotliDecoderStateInternal *,brotli_decoder_metadata_start_func,brotli_decoder_metadata_chunk_func,void *)" in summary model. | @@ -2948,6 +2950,7 @@ | Dubious signature "(char *,char *__restrict__,int,FILE *,FILE *__restrict__)" in summary model. | | Dubious signature "(char *,char *__restrict__,size_t,const char *,const char *__restrict__,const tm *,const tm *__restrict__,locale_t)" in summary model. | | Dubious signature "(char *,char,char **)" in summary model. | +| Dubious signature "(char *,const Blob &,int,int)" in summary model. | | Dubious signature "(char *,const char *)" in summary model. | | Dubious signature "(char *,const char **,const char **,const char **,const char **,const char **)" in summary model. | | Dubious signature "(char *,const char *,char **)" in summary model. |