-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: Internal Code
-
Labels:None
-
Storage Execution
-
ALL
BSONIteratorSorted::BSONIteratorSorted() calls BSONObj::nFields() and allocates an array that size to hold the fields to be sorted. It then iterates over the fields using BSONObjIterator::more() to terminate the loop, whereas BSONObj::nFields() counts the fields by iterating using BSONObjIterator::moreWithEOO() and BSONElement::eoo() to terminate the loop. The net result is that if the object is invalid or damaged - for example, it has 0s where data is expected - nFields() can see a smaller number of elements than BSONIteratorSorted(), causing a buffer overrun in the _fields buffer in BSONIteratorSorted().
To reproduce on 2.4.10, start with a fresh db, insert an object, damage it, then try to update it:
killall mongod rm -rf db db.log mkdir -p db mongod --dbpath db --smallfiles --oplogSize 50 --logpath db.log --fork mongo test --eval 'db.dropDatabase()' mongo test --eval 'db.c.insert({x:0, y:0, z:0}); db.getLastError()' mongo admin --eval 'db.shutdownServer()' dd if=/dev/zero of=db/test.0 bs=1 seek=$((0x20e0)) count=4 conv=notrunc # 2.4.10 mongod --dbpath db --smallfiles --oplogSize 50 --logpath db.log --fork mongo --eval 'db.c.update({}, {$set: {y:0}}); db.getLastError()' grep Assertion db.log
This should trigger the verify( x == _nfields ) assertion at jsobj.cpp:1291 as a result of the buffer overrun.
This test case did not reproduce the issue on 2.6.1 (even after adjusting the offset of the dd above to account for the different extent layout), but the code in BSONIteratorSorted() and nFields() has not changed, so apparently still has the same issue, even if not triggered by this test case.