summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorLouis Williams <louis.williams@mongodb.com>2019-10-21 22:21:40 +0000
committerevergreen <evergreen@mongodb.com>2019-10-21 22:21:40 +0000
commit5b749ef0105d92a2a3318c01d622f25201cd7bb8 (patch)
treeed6cacc295d32fc0f0ea2c969e18d448d00a7f26 /src/mongo
parentc1405c9ec65d1e57b5c9a1ee3d3c8d7f97f06a28 (diff)
downloadmongo-5b749ef0105d92a2a3318c01d622f25201cd7bb8.tar.gz
SERVER-44111 Assert BSONObj size is valid while copying
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/bson/bsonobj.cpp30
1 files changed, 28 insertions, 2 deletions
diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp
index 0e44b7d398d..15e08aefca6 100644
--- a/src/mongo/bson/bsonobj.cpp
+++ b/src/mongo/bson/bsonobj.cpp
@@ -99,8 +99,34 @@ void BSONObj::_assertInvalid(int maxSize) const {
}
BSONObj BSONObj::copy() const {
- auto storage = SharedBuffer::allocate(objsize());
- memcpy(storage.get(), objdata(), objsize());
+ // The undefined behavior checks in this function are best-effort and attempt to detect
+ // undefined behavior as early as possible. We cannot make any guarantees about detection
+ // because we are observing undefined state, and we assume the compiler does not make either
+ // of the following optimizations: a) optimizing away the call to objsize() on freed memory, and
+ // b) optimizing away the two sequential calls to objsize() as one.
+ // The behavior of this function must degrade as gracefully as possible under violation of
+ // those assumptions, and preserving any currently observed behavior does not form an argument
+ // against the later application of such optimizations.
+ int size = objsize();
+ if (!isOwned() && (size < kMinBSONLength || size > BufferMaxSize)) {
+ // Only for unowned objects, the size is validated in the constructor, so it is an error for
+ // the size to ever be invalid. This means that the unowned memory we are reading has
+ // changed, and we must exit immediately to avoid further undefined behavior.
+ severe() << "BSONObj::copy() - size " << size
+ << " of unowned BSONObj is invalid and differs from previously validated size.";
+ fassertFailed(31322);
+ }
+ auto storage = SharedBuffer::allocate(size);
+
+ // If the call to objsize() changes between this call and the previous one, this indicates that
+ // that the memory we are reading has changed, and we must exit immediately to avoid further
+ // undefined behavior.
+ if (int sizeAfter = objsize(); sizeAfter != size) {
+ severe() << "BSONObj::copy() - size " << sizeAfter
+ << " differs from previously observed size " << size;
+ fassertFailed(31323);
+ }
+ memcpy(storage.get(), objdata(), size);
return BSONObj(std::move(storage));
}