Skip to content

Commit 24c86c0

Browse files
authored
Merge pull request eclipse-openj9#20504 from tajila/jfr2
JFR: Prevent chunk buffer overflows
2 parents 2f6110e + 2ed9d35 commit 24c86c0

4 files changed

+176
-91
lines changed

runtime/vm/BufferWriter.hpp

+104-61
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ class VM_BufferWriter {
3434
U_8 *_buffer;
3535
U_8 *_cursor;
3636
UDATA _size;
37-
37+
U_8 *_bufferEnd;
3838
U_8 *_maxCursor;
39+
bool _overflow;
3940

4041
#if defined(J9VM_ENV_LITTLE_ENDIAN)
4142
static const bool _isLE = true;
@@ -94,8 +95,26 @@ class VM_BufferWriter {
9495
: _buffer(buffer)
9596
, _cursor(buffer)
9697
, _size(size)
98+
, _bufferEnd(buffer + size)
9799
, _maxCursor(NULL)
100+
, _overflow(false)
101+
{
102+
}
103+
104+
bool
105+
checkBounds(UDATA size)
106+
{
107+
if ((_cursor + size) >= _bufferEnd) {
108+
_overflow = true;
109+
}
110+
111+
return !_overflow;
112+
}
113+
114+
bool
115+
overflowOccurred()
98116
{
117+
return _overflow;
99118
}
100119

101120
U_64
@@ -123,50 +142,66 @@ class VM_BufferWriter {
123142
}
124143

125144
void
126-
writeU8(U_8 val)
145+
writeU8NoCheck(U_8 val)
127146
{
128147
*_cursor = val;
129148
_cursor += sizeof(U_8);
130149
}
131150

151+
void
152+
writeU8(U_8 val)
153+
{
154+
if (checkBounds(sizeof(U_8))) {
155+
writeU8NoCheck(val);
156+
}
157+
}
158+
132159
void
133160
writeU16(U_16 val)
134161
{
135-
U_16 newVal = val;
136-
if (_isLE) {
137-
newVal = byteSwap(val);
162+
if (checkBounds(sizeof(U_16))) {
163+
U_16 newVal = val;
164+
if (_isLE) {
165+
newVal = byteSwap(val);
166+
}
167+
*(U_16 *)_cursor = newVal;
168+
_cursor += sizeof(U_16);
138169
}
139-
*(U_16 *)_cursor = newVal;
140-
_cursor += sizeof(U_16);
141170
}
142171

143172
void
144173
writeU32(U_32 val)
145174
{
146-
U_32 newVal = val;
147-
if (_isLE) {
148-
newVal = byteSwap(val);
175+
if (checkBounds(sizeof(U_32))) {
176+
U_32 newVal = val;
177+
if (_isLE) {
178+
newVal = byteSwap(val);
179+
}
180+
*(U_32 *)_cursor = newVal;
181+
_cursor += sizeof(U_32);
149182
}
150-
*(U_32 *)_cursor = newVal;
151-
_cursor += sizeof(U_32);
152183
}
153184

154185
void
155186
writeU64(U_64 val)
156187
{
157-
U_64 newVal = val;
158-
if (_isLE) {
159-
newVal = byteSwap(val);
188+
if (checkBounds(sizeof(U_64))) {
189+
U_64 newVal = val;
190+
if (_isLE) {
191+
newVal = byteSwap(val);
192+
}
193+
*(U_64 *)_cursor = newVal;
194+
_cursor += sizeof(U_64);
160195
}
161-
*(U_64 *)_cursor = newVal;
162-
_cursor += sizeof(U_64);
163196
}
164197

165198
void
166199
writeData(U_8 *data, UDATA size)
167200
{
168-
memcpy(_cursor, data, size);
169-
_cursor += size;
201+
if (checkBounds(size)) {
202+
memcpy(_cursor, data, size);
203+
_cursor += size;
204+
}
170205
}
171206

172207
U_8 *
@@ -203,19 +238,21 @@ class VM_BufferWriter {
203238
void
204239
writeLEB128(U_64 val)
205240
{
206-
U_64 newVal = val;
207-
if (!_isLE) {
208-
newVal = byteSwap(val);
209-
}
210-
do {
211-
U_8 byte = newVal & 0x7F;
212-
newVal >>= 7;
213-
214-
if (newVal > 0) {
215-
byte |= 0x80;
241+
if (checkBounds(9)) {
242+
U_64 newVal = val;
243+
if (!_isLE) {
244+
newVal = byteSwap(val);
216245
}
217-
writeU8(byte);
218-
} while (newVal > 0);
246+
do {
247+
U_8 byte = newVal & 0x7F;
248+
newVal >>= 7;
249+
250+
if (newVal > 0) {
251+
byte |= 0x80;
252+
}
253+
writeU8NoCheck(byte);
254+
} while (newVal > 0);
255+
}
219256
}
220257

221258
void
@@ -230,19 +267,21 @@ class VM_BufferWriter {
230267
void
231268
writeLEB128PaddedU72(U_64 val)
232269
{
233-
U_64 newVal = val;
234-
if (!_isLE) {
235-
newVal = byteSwap(val);
270+
if (checkBounds(9)) {
271+
U_64 newVal = val;
272+
if (!_isLE) {
273+
newVal = byteSwap(val);
274+
}
275+
writeU8NoCheck((newVal & 0x7F) | 0x80);
276+
writeU8NoCheck(((newVal >> 7) & 0x7F) | 0x80);
277+
writeU8NoCheck(((newVal >> 14) & 0x7F) | 0x80);
278+
writeU8NoCheck(((newVal >> 21) & 0x7F) | 0x80);
279+
writeU8NoCheck(((newVal >> 28) & 0x7F) | 0x80);
280+
writeU8NoCheck(((newVal >> 35) & 0x7F) | 0x80);
281+
writeU8NoCheck(((newVal >> 42) & 0x7F) | 0x80);
282+
writeU8NoCheck(((newVal >> 49) & 0x7F) | 0x80);
283+
writeU8NoCheck(((newVal >> 56) & 0x7F));
236284
}
237-
writeU8((newVal & 0x7F) | 0x80);
238-
writeU8(((newVal >> 7) & 0x7F) | 0x80);
239-
writeU8(((newVal >> 14) & 0x7F) | 0x80);
240-
writeU8(((newVal >> 21) & 0x7F) | 0x80);
241-
writeU8(((newVal >> 28) & 0x7F) | 0x80);
242-
writeU8(((newVal >> 35) & 0x7F) | 0x80);
243-
writeU8(((newVal >> 42) & 0x7F) | 0x80);
244-
writeU8(((newVal >> 49) & 0x7F) | 0x80);
245-
writeU8(((newVal >> 56) & 0x7F));
246285
}
247286

248287
void
@@ -257,18 +296,20 @@ class VM_BufferWriter {
257296
void
258297
writeLEB128PaddedU64(U_64 val)
259298
{
260-
U_64 newVal = val;
261-
if (!_isLE) {
262-
newVal = byteSwap(val);
299+
if (checkBounds(sizeof(U_64))) {
300+
U_64 newVal = val;
301+
if (!_isLE) {
302+
newVal = byteSwap(val);
303+
}
304+
writeU8NoCheck((newVal & 0x7F) | 0x80);
305+
writeU8NoCheck(((newVal >> 7) & 0x7F) | 0x80);
306+
writeU8NoCheck(((newVal >> 14) & 0x7F) | 0x80);
307+
writeU8NoCheck(((newVal >> 21) & 0x7F) | 0x80);
308+
writeU8NoCheck(((newVal >> 28) & 0x7F) | 0x80);
309+
writeU8NoCheck(((newVal >> 35) & 0x7F) | 0x80);
310+
writeU8NoCheck(((newVal >> 42) & 0x7F) | 0x80);
311+
writeU8NoCheck(((newVal >> 49) & 0x7F));
263312
}
264-
writeU8((newVal & 0x7F) | 0x80);
265-
writeU8(((newVal >> 7) & 0x7F) | 0x80);
266-
writeU8(((newVal >> 14) & 0x7F) | 0x80);
267-
writeU8(((newVal >> 21) & 0x7F) | 0x80);
268-
writeU8(((newVal >> 28) & 0x7F) | 0x80);
269-
writeU8(((newVal >> 35) & 0x7F) | 0x80);
270-
writeU8(((newVal >> 42) & 0x7F) | 0x80);
271-
writeU8(((newVal >> 49) & 0x7F));
272313
}
273314

274315
void
@@ -283,14 +324,16 @@ class VM_BufferWriter {
283324
void
284325
writeLEB128PaddedU32(U_32 val)
285326
{
286-
U_64 newVal = val;
287-
if (!_isLE) {
288-
newVal = byteSwap(val);
327+
if (checkBounds(sizeof(U_32))) {
328+
U_64 newVal = val;
329+
if (!_isLE) {
330+
newVal = byteSwap(val);
331+
}
332+
writeU8NoCheck((newVal & 0x7F) | 0x80);
333+
writeU8NoCheck(((newVal >> 7) & 0x7F) | 0x80);
334+
writeU8NoCheck(((newVal >> 14) & 0x7F) | 0x80);
335+
writeU8NoCheck(((newVal >> 21) & 0x7F));
289336
}
290-
writeU8((newVal & 0x7F) | 0x80);
291-
writeU8(((newVal >> 7) & 0x7F) | 0x80);
292-
writeU8(((newVal >> 14) & 0x7F) | 0x80);
293-
writeU8(((newVal >> 21) & 0x7F));
294337
}
295338

296339
static U_32

runtime/vm/JFRChunkWriter.hpp

+35-25
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ class VM_JFRChunkWriter {
135135
/* conservative sizing for JFR chunk */
136136
static constexpr int STRING_HEADER_LENGTH = sizeof(U_64);
137137
static constexpr int CHECKPOINT_EVENT_HEADER_AND_FOOTER = 68;
138+
static constexpr int STRING_CONSTANT_SIZE = 128;
138139
static constexpr int THREADSTATE_ENTRY_LENGTH = CHECKPOINT_EVENT_HEADER_AND_FOOTER + sizeof(threadStateNames) + (THREADSTATE_COUNT * STRING_HEADER_LENGTH);
139140
static constexpr int CLASS_ENTRY_ENTRY_SIZE = (5 * sizeof(U_64)) + sizeof(U_8);
140141
static constexpr int CLASSLOADER_ENTRY_SIZE = 3 * sizeof(U_64);
@@ -150,6 +151,7 @@ class VM_JFRChunkWriter {
150151
static constexpr int THREAD_START_EVENT_SIZE = (6 * sizeof(U_64)) + sizeof(U_32);
151152
static constexpr int THREAD_END_EVENT_SIZE = (4 * sizeof(U_64)) + sizeof(U_32);
152153
static constexpr int THREAD_SLEEP_EVENT_SIZE = (7 * sizeof(U_64)) + sizeof(U_32);
154+
static constexpr int MONITOR_WAIT_EVENT_SIZE = (9 * sizeof(U_64)) + sizeof(U_32);
153155
static constexpr int JVM_INFORMATION_EVENT_SIZE = 3000;
154156
static constexpr int PHYSICAL_MEMORY_EVENT_SIZE = (4 * sizeof(U_64)) + sizeof(U_32);
155157
static constexpr int VIRTUALIZATION_INFORMATION_EVENT_SIZE = 50;
@@ -343,6 +345,10 @@ class VM_JFRChunkWriter {
343345

344346
writeJFRHeader();
345347

348+
if (_bufferWriter->overflowOccurred()) {
349+
_buildResult = OutOfMemory;
350+
}
351+
346352
if (isResultNotOKay()) {
347353
Trc_VM_jfr_ErrorWritingChunk(_currentThread, _buildResult);
348354
goto freeBuffer;
@@ -592,53 +598,57 @@ class VM_JFRChunkWriter {
592598
UDATA
593599
calculateRequiredBufferSize()
594600
{
595-
UDATA requireBufferSize = _constantPoolTypes.getRequiredBufferSize();
596-
requireBufferSize += JFR_CHUNK_HEADER_SIZE;
601+
UDATA requiredBufferSize = _constantPoolTypes.getRequiredBufferSize();
602+
requiredBufferSize += JFR_CHUNK_HEADER_SIZE;
603+
604+
requiredBufferSize += METADATA_HEADER_SIZE;
605+
606+
requiredBufferSize += _vm->jfrState.metaDataBlobFileSize;
597607

598-
requireBufferSize += METADATA_HEADER_SIZE;
608+
requiredBufferSize += THREADSTATE_ENTRY_LENGTH;
599609

600-
requireBufferSize += _vm->jfrState.metaDataBlobFileSize;
610+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getClassCount() * CLASS_ENTRY_ENTRY_SIZE));
601611

602-
requireBufferSize += THREADSTATE_ENTRY_LENGTH;
612+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getClassloaderCount() * CLASSLOADER_ENTRY_SIZE));
603613

604-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getClassCount() * CLASS_ENTRY_ENTRY_SIZE);
614+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + ((_constantPoolTypes.getPackageCount() + _constantPoolTypes.getStringUTF8Count()) * STRING_CONSTANT_SIZE));
605615

606-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getClassloaderCount() * CLASSLOADER_ENTRY_SIZE);
616+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getPackageCount() * PACKAGE_ENTRY_SIZE));
607617

608-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getPackageCount() * PACKAGE_ENTRY_SIZE);
618+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getMethodCount() * METHOD_ENTRY_SIZE));
609619

610-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getMethodCount() * METHOD_ENTRY_SIZE);
620+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getThreadCount() * THREAD_ENTRY_SIZE));
611621

612-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getThreadCount() * THREAD_ENTRY_SIZE);
622+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getThreadGroupCount() * THREADGROUP_ENTRY_SIZE));
613623

614-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getThreadGroupCount() * THREADGROUP_ENTRY_SIZE);
624+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getModuleCount() * MODULE_ENTRY_SIZE));
615625

616-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getModuleCount() * MODULE_ENTRY_SIZE);
626+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getStackTraceCount() * STACKTRACE_ENTRY_SIZE));
617627

618-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getStackTraceCount() * STACKTRACE_ENTRY_SIZE);
628+
requiredBufferSize += (CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getStackFrameCount() * STACKFRAME_ENTRY_SIZE));
619629

620-
requireBufferSize += CHECKPOINT_EVENT_HEADER_AND_FOOTER + (_constantPoolTypes.getStackFrameCount() * STACKFRAME_ENTRY_SIZE);
630+
requiredBufferSize += (_constantPoolTypes.getExecutionSampleCount() * EXECUTION_SAMPLE_EVENT_SIZE);
621631

622-
requireBufferSize += _constantPoolTypes.getExecutionSampleCount() * EXECUTION_SAMPLE_EVENT_SIZE;
632+
requiredBufferSize += (_constantPoolTypes.getThreadStartCount() * THREAD_START_EVENT_SIZE);
623633

624-
requireBufferSize += _constantPoolTypes.getThreadStartCount() * THREAD_START_EVENT_SIZE;
634+
requiredBufferSize += (_constantPoolTypes.getThreadEndCount() * THREAD_END_EVENT_SIZE);
625635

626-
requireBufferSize += _constantPoolTypes.getThreadEndCount() * THREAD_END_EVENT_SIZE;
636+
requiredBufferSize += (_constantPoolTypes.getThreadSleepCount() * THREAD_SLEEP_EVENT_SIZE);
627637

628-
requireBufferSize += _constantPoolTypes.getThreadSleepCount() * THREAD_SLEEP_EVENT_SIZE;
638+
requiredBufferSize += (_constantPoolTypes.getMonitorWaitCount() * MONITOR_WAIT_EVENT_SIZE);
629639

630-
requireBufferSize += JVM_INFORMATION_EVENT_SIZE;
640+
requiredBufferSize += JVM_INFORMATION_EVENT_SIZE;
631641

632-
requireBufferSize += OS_INFORMATION_EVENT_SIZE;
642+
requiredBufferSize += OS_INFORMATION_EVENT_SIZE;
633643

634-
requireBufferSize += PHYSICAL_MEMORY_EVENT_SIZE;
644+
requiredBufferSize += PHYSICAL_MEMORY_EVENT_SIZE;
635645

636-
requireBufferSize += VIRTUALIZATION_INFORMATION_EVENT_SIZE;
646+
requiredBufferSize += VIRTUALIZATION_INFORMATION_EVENT_SIZE;
637647

638-
requireBufferSize += CPU_INFORMATION_EVENT_SIZE;
648+
requiredBufferSize += CPU_INFORMATION_EVENT_SIZE;
639649

640-
requireBufferSize += INITIAL_SYSTEM_PROPERTY_EVENT_SIZE;
641-
return requireBufferSize;
650+
requiredBufferSize += INITIAL_SYSTEM_PROPERTY_EVENT_SIZE;
651+
return requiredBufferSize;
642652
}
643653

644654
~VM_JFRChunkWriter()

runtime/vm/JFRConstantPoolTypes.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -1152,5 +1152,31 @@ VM_JFRConstantPoolTypes::freeStackStraceEntries(void *entry, void *userData)
11521152
return FALSE;
11531153
}
11541154

1155+
UDATA
1156+
VM_JFRConstantPoolTypes::freeThreadNameEntries(void *entry, void *userData)
1157+
{
1158+
ThreadEntry *tableEntry = (ThreadEntry *) entry;
1159+
J9VMThread *currentThread = (J9VMThread *)userData;
1160+
PORT_ACCESS_FROM_VMC(currentThread);
1161+
1162+
j9mem_free_memory(tableEntry->javaThreadName);
1163+
tableEntry->javaThreadName = NULL;
1164+
1165+
return FALSE;
1166+
}
1167+
1168+
UDATA
1169+
VM_JFRConstantPoolTypes::freeThreadGroupNameEntries(void *entry, void *userData)
1170+
{
1171+
ThreadGroupEntry *tableEntry = (ThreadGroupEntry *) entry;
1172+
J9VMThread *currentThread = (J9VMThread *)userData;
1173+
PORT_ACCESS_FROM_VMC(currentThread);
1174+
1175+
j9mem_free_memory(tableEntry->name);
1176+
tableEntry->name = NULL;
1177+
1178+
return FALSE;
1179+
}
1180+
11551181

11561182
#endif /* defined(J9VM_OPT_JFR) */

0 commit comments

Comments
 (0)