ffi: reject unsafe integers as length or offset - #66216
christianaurichzm wants to merge 1 commit into
Conversation
|
Review requested:
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #66216 +/- ##
==========================================
- Coverage 90.29% 90.28% -0.01%
==========================================
Files 790 789 -1
Lines 272883 272879 -4
Branches 52118 52112 -6
==========================================
- Hits 246387 246370 -17
- Misses 16943 16966 +23
+ Partials 9553 9543 -10
🚀 New features to boost your workflow:
|
|
My personal feeling is that we should be rejecting unsafe integers here entirely, there is no circumstance in which we should be allowing reads/writes from offsets that are being rounded. I can't imagine a world in which someone is referencing a contiguous buffer that is more than 9 petabytes in size. |
GetValidatedSize() checks the value against static_cast<double>(SIZE_MAX), which rounds up to 2^64 on 64-bit platforms. A length or offset of 2 ** 64 gets through, and the cast to size_t after it is undefined behavior. With GCC on x64 it gives 0, so ffi.setUint8(ptr, 2 ** 64, 42) writes to ptr instead of throwing. Anything above Number.MAX_SAFE_INTEGER may already have been rounded by the time it gets here, so reject those values too. The export*() helpers already cap their length there, and so does setInt64() for number values. SIZE_MAX is still the limit on 32-bit platforms. When buffer.constants.MAX_LENGTH is Number.MAX_SAFE_INTEGER, as on 64-bit builds without the V8 sandbox, toBuffer() and toArrayBuffer() now throw ERR_OUT_OF_RANGE for MAX_LENGTH + 1 instead of ERR_BUFFER_TOO_LARGE. Signed-off-by: Christian Aurich Zanettini Martins <christian.aurichzm@gmail.com>
e9409c4 to
0558424
Compare
|
Makes sense, agreed. It now rejects anything above |
GetValidatedSize()checks lengths and offsets againststatic_cast<double>(SIZE_MAX), which rounds up to2^64on 64-bit platforms. So2 ** 64gets through, and thestatic_cast<size_t>()after it is undefined behavior. With GCC 13.3 on x64 it gives0:The limit is now
Number.MAX_SAFE_INTEGERinstead of just below2 ** 64. Anything larger may already have been rounded before it gets here (2 ** 53 + 1 === 2 ** 53), so it can't be trusted as an offset. Theexport*()helpers already cap their length at that value, and so doessetInt64()for number values.SIZE_MAXis still the limit on 32-bit.This changes one error code: when
buffer.constants.MAX_LENGTHisNumber.MAX_SAFE_INTEGER(64-bit without the V8 sandbox),toBuffer()/toArrayBuffer()withMAX_LENGTH + 1now throwERR_OUT_OF_RANGEinstead ofERR_BUFFER_TOO_LARGE. The existing assertions for that case now only run whereMAX_LENGTHis smaller, and the new test covers the other case.On
mainthe new test segfaults (getUint8(ptr, 2 ** 53)reads 8 PiB past the pointer). With this changetest/ffipasses,parallelandsequentialshow no new failures, andmake lintis clean.