Skip to content

Commit 0622b4a

Browse files
committed
fix(cpp): address remaining bslx review feedback
1 parent ccff432 commit 0622b4a

8 files changed

Lines changed: 825 additions & 444 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
---
22
category: minorAnalysis
33
---
4-
* Added taint flow summaries for the BDE `bslx` byte-stream deserializers `BloombergLP::bslx::ByteInStream`, `BloombergLP::bslx::GenericInStream`, and `BloombergLP::bslx::InStreamFunctions::bdexStreamIn`, so that data read from a `bslx` in-stream is tracked as tainted.
4+
* Added taint flow summaries for the BDE `bslx` byte-stream deserializers `BloombergLP::bslx::ByteInStream`, `BloombergLP::bslx::GenericInStream`, and `BloombergLP::bslx::InStreamFunctions::bdexStreamIn`.

cpp/ql/lib/ext/bslx.model.yml

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@ extensions:
44
pack: codeql/cpp-all
55
extensible: summaryModel
66
data: # namespace, type, subtypes, name, signature, ext, input, output, kind, provenance
7-
# === bslx::ByteInStream: concrete byte-array in-stream ===
8-
# Taint in: the source buffer/streambuf taints the stream (`this`).
9-
# Note: MaD taint is additive, so `reset` cannot clear taint from a previously
10-
# tainted stream; a stream reset with a clean buffer keeps any earlier taint.
7+
# bslx::ByteInStream
118
- ["BloombergLP::bslx", "ByteInStream", true, "ByteInStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
12-
- ["BloombergLP::bslx", "ByteInStream", true, "reset", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
13-
# Taint out: the stream (`this`) taints the deserialized string/array output buffer.
14-
# Scalar getters (getLength, getVersion, getInt*, getUint*, getFloat*) are deliberately
15-
# not modeled as outputs: most queries sanitize taint through integers, so such rows
16-
# would add nothing. Their fluent `ReturnValue[*]` rows below are still modeled.
9+
# Input-taking resets replace the buffer; reset() only rewinds it.
10+
- ["BloombergLP::bslx", "ByteInStream", true, "reset", "(const char *,size_t)", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
11+
- ["BloombergLP::bslx", "ByteInStream", true, "reset", "(const StringRef &)", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
12+
# bslx::ByteInStream getters.
13+
# Scalar getters (getLength, getVersion, getInt*, getUint*, getFloat*) are not modeled,
14+
# as we are generally not interested in tainted scalar values.
1715
- ["BloombergLP::bslx", "ByteInStream", true, "getString", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
1816
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayInt8", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
1917
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayUint8", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
@@ -33,7 +31,7 @@ extensions:
3331
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayUint64", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
3432
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayFloat32", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
3533
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayFloat64", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
36-
# Fluent interface: each get* returns `*this`, keeping the returned stream tainted.
34+
# bslx::ByteInStream fluent interface
3735
- ["BloombergLP::bslx", "ByteInStream", true, "getLength", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
3836
- ["BloombergLP::bslx", "ByteInStream", true, "getVersion", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
3937
- ["BloombergLP::bslx", "ByteInStream", true, "getInt8", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
@@ -73,13 +71,11 @@ extensions:
7371
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayUint64", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
7472
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayFloat32", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
7573
- ["BloombergLP::bslx", "ByteInStream", true, "getArrayFloat64", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
76-
# === bslx::GenericInStream<STREAMBUF>: streambuf-backed in-stream ===
77-
# Taint in: the source buffer/streambuf taints the stream (`this`).
74+
# bslx::GenericInStream
7875
- ["BloombergLP::bslx", "GenericInStream", true, "GenericInStream", "", "", "Argument[*0]", "Argument[-1]", "taint", "manual"]
79-
# Taint out: the stream (`this`) taints the deserialized string/array output buffer.
80-
# Scalar getters (getLength, getVersion, getInt*, getUint*, getFloat*) are deliberately
81-
# not modeled as outputs: most queries sanitize taint through integers, so such rows
82-
# would add nothing. Their fluent `ReturnValue[*]` rows below are still modeled.
76+
# bslx::GenericInStream getters.
77+
# Scalar getters (getLength, getVersion, getInt*, getUint*, getFloat*) are not modeled,
78+
# as we are generally not interested in tainted scalar values.
8379
- ["BloombergLP::bslx", "GenericInStream", true, "getString", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
8480
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayInt8", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
8581
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayUint8", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
@@ -99,7 +95,7 @@ extensions:
9995
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayUint64", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
10096
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayFloat32", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
10197
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayFloat64", "", "", "Argument[-1]", "Argument[*0]", "taint", "manual"]
102-
# Fluent interface: each get* returns `*this`, keeping the returned stream tainted.
98+
# bslx::GenericInStream fluent interface
10399
- ["BloombergLP::bslx", "GenericInStream", true, "getLength", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
104100
- ["BloombergLP::bslx", "GenericInStream", true, "getVersion", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
105101
- ["BloombergLP::bslx", "GenericInStream", true, "getInt8", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
@@ -139,8 +135,6 @@ extensions:
139135
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayUint64", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
140136
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayFloat32", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
141137
- ["BloombergLP::bslx", "GenericInStream", true, "getArrayFloat64", "", "", "Argument[-1]", "ReturnValue[*]", "taint", "manual"]
142-
# === bslx::InStreamFunctions::bdexStreamIn: generic BDEX deserialization ===
143-
# Free function template; `InStreamFunctions` is a namespace, so `type` is empty.
144-
# Object outputs are modeled in implementations/Bslx.qll, where their type
145-
# can be checked to exclude scalar outputs.
138+
# bslx::InStreamFunctions::bdexStreamIn
139+
- ["BloombergLP::bslx::InStreamFunctions", "", false, "bdexStreamIn", "", "", "Argument[*0]", "Argument[*1]", "taint", "manual"]
146140
- ["BloombergLP::bslx::InStreamFunctions", "", false, "bdexStreamIn", "", "", "Argument[*0]", "ReturnValue[*]", "taint", "manual"]

cpp/ql/lib/semmle/code/cpp/models/Models.qll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
private import implementations.Allocation
2-
private import implementations.Bslx
32
private import implementations.Deallocation
43
private import implementations.Fopen
54
private import implementations.Fread

cpp/ql/lib/semmle/code/cpp/models/implementations/Bslx.qll

Lines changed: 0 additions & 16 deletions
This file was deleted.

cpp/ql/test/library-tests/dataflow/external-models/bslx.cpp

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ namespace bsl {
2323

2424
// BDE wraps every package-group namespace in `BloombergLP`; this stub reproduces that.
2525
namespace BloombergLP {
26+
namespace bslstl {
27+
template <class CHAR_TYPE> class StringRefImp {};
28+
typedef StringRefImp<char> StringRef;
29+
}
2630
namespace bsls {
2731
// `bsls::Types` provides the fixed-width integer aliases used by the stream API.
2832
struct Types {
@@ -35,7 +39,9 @@ namespace bslx {
3539
public:
3640
ByteInStream();
3741
ByteInStream(const char *buffer, std::size_t numBytes);
42+
void reset();
3843
void reset(const char *buffer, std::size_t numBytes);
44+
void reset(const bslstl::StringRef &srcData);
3945
ByteInStream &getLength(int &variable);
4046
ByteInStream &getVersion(int &variable);
4147
ByteInStream &getInt8(char &variable);
@@ -211,9 +217,11 @@ void test_bdexStreamIn() {
211217
sink(*obj.data()); // $ ir
212218
}
213219

214-
// --- coverage: call every modeled getter so steps.ql verifies each row is consumed ---
220+
// --- coverage: verify flow through every modeled getter in a fluent chain ---
215221

216-
void coverage_ByteInStream(BloombergLP::bslx::ByteInStream &stream) {
222+
void coverage_ByteInStream() {
223+
std::string data = std::string(source());
224+
BloombergLP::bslx::ByteInStream stream(data.data(), data.size());
217225
int i = 0;
218226
unsigned int ui = 0;
219227
char c = 0;
@@ -235,10 +243,15 @@ void coverage_ByteInStream(BloombergLP::bslx::ByteInStream &stream) {
235243
BloombergLP::bsls::Types::Uint64 ullbuf[16];
236244
float fbuf[16];
237245
double dbuf[16];
238-
stream.getLength(i).getVersion(i).getInt8(c).getUint8(uc).getInt16(s).getUint16(us).getInt24(i).getUint24(ui).getInt32(i).getUint32(ui).getInt40(ll).getUint40(ull).getInt48(ll).getUint48(ull).getInt56(ll).getUint56(ull).getInt64(ll).getUint64(ull).getFloat32(f).getFloat64(d).getString(str).getArrayInt8(cbuf, 16).getArrayUint8(ucbuf, 16).getArrayInt16(sbuf, 16).getArrayUint16(usbuf, 16).getArrayInt24(ibuf, 16).getArrayUint24(uibuf, 16).getArrayInt32(ibuf, 16).getArrayUint32(uibuf, 16).getArrayInt40(llbuf, 16).getArrayUint40(ullbuf, 16).getArrayInt48(llbuf, 16).getArrayUint48(ullbuf, 16).getArrayInt56(llbuf, 16).getArrayUint56(ullbuf, 16).getArrayInt64(llbuf, 16).getArrayUint64(ullbuf, 16).getArrayFloat32(fbuf, 16).getArrayFloat64(dbuf, 16);
246+
bsl::string out;
247+
stream.getLength(i).getVersion(i).getInt8(c).getUint8(uc).getInt16(s).getUint16(us).getInt24(i).getUint24(ui).getInt32(i).getUint32(ui).getInt40(ll).getUint40(ull).getInt48(ll).getUint48(ull).getInt56(ll).getUint56(ull).getInt64(ll).getUint64(ull).getFloat32(f).getFloat64(d).getString(str).getArrayInt8(cbuf, 16).getArrayUint8(ucbuf, 16).getArrayInt16(sbuf, 16).getArrayUint16(usbuf, 16).getArrayInt24(ibuf, 16).getArrayUint24(uibuf, 16).getArrayInt32(ibuf, 16).getArrayUint32(uibuf, 16).getArrayInt40(llbuf, 16).getArrayUint40(ullbuf, 16).getArrayInt48(llbuf, 16).getArrayUint48(ullbuf, 16).getArrayInt56(llbuf, 16).getArrayUint56(ullbuf, 16).getArrayInt64(llbuf, 16).getArrayUint64(ullbuf, 16).getArrayFloat32(fbuf, 16).getArrayFloat64(dbuf, 16).getString(out);
248+
sink(*out.data()); // $ ir
239249
}
240250

241-
void coverage_GenericInStream(BloombergLP::bslx::GenericInStream<MyStreamBuf> &stream) {
251+
void coverage_GenericInStream() {
252+
std::string data = std::string(source());
253+
MyStreamBuf *sb = (MyStreamBuf *)data.data();
254+
BloombergLP::bslx::GenericInStream<MyStreamBuf> stream(sb);
242255
int i = 0;
243256
unsigned int ui = 0;
244257
char c = 0;
@@ -260,17 +273,19 @@ void coverage_GenericInStream(BloombergLP::bslx::GenericInStream<MyStreamBuf> &s
260273
BloombergLP::bsls::Types::Uint64 ullbuf[16];
261274
float fbuf[16];
262275
double dbuf[16];
263-
stream.getLength(i).getVersion(i).getInt8(c).getUint8(uc).getInt16(s).getUint16(us).getInt24(i).getUint24(ui).getInt32(i).getUint32(ui).getInt40(ll).getUint40(ull).getInt48(ll).getUint48(ull).getInt56(ll).getUint56(ull).getInt64(ll).getUint64(ull).getFloat32(f).getFloat64(d).getString(str).getArrayInt8(cbuf, 16).getArrayUint8(ucbuf, 16).getArrayInt16(sbuf, 16).getArrayUint16(usbuf, 16).getArrayInt24(ibuf, 16).getArrayUint24(uibuf, 16).getArrayInt32(ibuf, 16).getArrayUint32(uibuf, 16).getArrayInt40(llbuf, 16).getArrayUint40(ullbuf, 16).getArrayInt48(llbuf, 16).getArrayUint48(ullbuf, 16).getArrayInt56(llbuf, 16).getArrayUint56(ullbuf, 16).getArrayInt64(llbuf, 16).getArrayUint64(ullbuf, 16).getArrayFloat32(fbuf, 16).getArrayFloat64(dbuf, 16);
276+
bsl::string out;
277+
stream.getLength(i).getVersion(i).getInt8(c).getUint8(uc).getInt16(s).getUint16(us).getInt24(i).getUint24(ui).getInt32(i).getUint32(ui).getInt40(ll).getUint40(ull).getInt48(ll).getUint48(ull).getInt56(ll).getUint56(ull).getInt64(ll).getUint64(ull).getFloat32(f).getFloat64(d).getString(str).getArrayInt8(cbuf, 16).getArrayUint8(ucbuf, 16).getArrayInt16(sbuf, 16).getArrayUint16(usbuf, 16).getArrayInt24(ibuf, 16).getArrayUint24(uibuf, 16).getArrayInt32(ibuf, 16).getArrayUint32(uibuf, 16).getArrayInt40(llbuf, 16).getArrayUint40(ullbuf, 16).getArrayInt48(llbuf, 16).getArrayUint48(ullbuf, 16).getArrayInt56(llbuf, 16).getArrayUint56(ullbuf, 16).getArrayInt64(llbuf, 16).getArrayUint64(ullbuf, 16).getArrayFloat32(fbuf, 16).getArrayFloat64(dbuf, 16).getString(out);
278+
sink(*out.data()); // $ ir
264279
}
265280

266-
void test_bdexStreamIn_integer_no_flow() {
281+
void test_bdexStreamIn_integer() {
267282
std::string data = std::string(source());
268283
BloombergLP::bslx::ByteInStream stream(data.data(), data.size());
269284
int x = 0;
270285
BloombergLP::bslx::InStreamFunctions::bdexStreamIn(stream, x);
271-
sink(x); // no flow: scalar outputs are deliberately not modeled
286+
sink(x); // $ ir
272287
BloombergLP::bslx::InStreamFunctions::bdexStreamIn(stream, x, 0);
273-
sink(x); // no flow: the versioned overload must also exclude scalar outputs
288+
sink(x); // $ ir
274289
bsl::string out;
275290
BloombergLP::bslx::InStreamFunctions::bdexStreamIn(stream, x, 0).getString(out);
276291
sink(*out.data()); // $ ir
@@ -297,3 +312,46 @@ void test_bdexStreamIn_object() {
297312
BloombergLP::bslx::InStreamFunctions::bdexStreamIn(stream, out, 1);
298313
sink(out); // $ ir
299314
}
315+
316+
namespace StringRefTest {
317+
BloombergLP::bslstl::StringRef source();
318+
}
319+
320+
void test_ByteInStream_reset_stringref() {
321+
BloombergLP::bslx::ByteInStream stream;
322+
BloombergLP::bslstl::StringRef data = StringRefTest::source();
323+
stream.reset(data);
324+
bsl::string out;
325+
stream.getString(out);
326+
sink(*out.data()); // $ ir
327+
}
328+
329+
void test_ByteInStream_reset_rewind() {
330+
std::string data = std::string(source());
331+
BloombergLP::bslx::ByteInStream stream(data.data(), data.size());
332+
stream.reset();
333+
bsl::string out;
334+
stream.getString(out);
335+
sink(*out.data()); // $ ir
336+
}
337+
338+
void test_ByteInStream_reset_clean_buffer() {
339+
BloombergLP::bslx::ByteInStream stream;
340+
const char data[] = "clean";
341+
stream.reset(data, *source());
342+
stream.reset();
343+
bsl::string out;
344+
stream.getString(out);
345+
sink(*out.data()); // no flow: the tainted length does not taint the buffer
346+
}
347+
348+
void test_ByteInStream_reset_replaces_buffer() {
349+
std::string data = std::string(source());
350+
BloombergLP::bslx::ByteInStream stream(data.data(), data.size());
351+
const char clean[] = "clean";
352+
stream.reset(clean, sizeof(clean));
353+
bsl::string out;
354+
stream.getString(out);
355+
// Known false positive: this summary does not kill taint from the old buffer.
356+
sink(*out.data()); // $ SPURIOUS: ir
357+
}

0 commit comments

Comments
 (0)