CVE-2025-54481,CVE-2025-54480,CVE-2025-54488,CVE-2025-54494,CVE-2025-54490,CVE-2025-54487,CVE-2025-54493,CVE-2025-54483,CVE-2025-54482,CVE-2025-54484,CVE-2025-54486,CVE-2025-54492,CVE-2025-54485,CVE-2025-54491,CVE-2025-54489
A stack-based buffer overflow vulnerability exists in the MFER parsing functionality of The Biosig Project libbiosig 3.9.0 and Master Branch (35a819fa). A specially crafted MFER file can lead to arbitrary code execution. An attacker can provide a malicious file to trigger this vulnerability.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
The Biosig Project libbiosig 3.9.0
The Biosig Project libbiosig Master Branch (35a819fa)
libbiosig - https://biosig.sourceforge.net/index.html
9.8 - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE-121 - Stack-based Buffer Overflow
Libbiosig is an open source library designed to process various types of medical signal data (EKG, EEG, etc) within a vast variety of different file formats. Libbiosig is also at the core of biosig APIs in Octave and Matlab, sigviewer, and other scientific software utilized for interpreting biomedical signal data.
Within libbiosig, the sopen_extended
function is the common entry point for file parsing, regardless of the specific file type:
HDRTYPE* sopen_extended(const char* FileName, const char* MODE, HDRTYPE* hdr, biosig_options_type *biosig_options) {
/*
MODE="r"
reads file and returns HDR
MODE="w"
writes HDR into file
*/
The general flow of sopen_extended
is as one might expect: initialize generic structures, determine the relevant file type, parse the file, and finally populate the generic structures that can be utilized by whatever is calling sopen_extended
. To determine the file type, sopen_extended
calls getfiletype
, which attempts to fingerprint the file based on the presence of various magic bytes within the header. Libbiosig also allows for these heuristics to be bypassed by setting the file type manually, but that approach is more applicable when writing data to a file; this vulnerability concerns the code path taken when reading from a file.
The file type used to exercise this vulnerability is the Medical waveform Format Encoding Rules (MFER), a file format for encoding medical waveforms from various different kinds of medical devices, such as ECG and EEG. The MFER standard aims to abstract away the encoding of the waveform data itself, independent of the specifics of the recording device.
To determine if the input file is valid MFER, getfiletype
runs the following check:
else if (!memcmp(Header1,"@ MFER ",8))
hdr->TYPE = MFER;
else if (!memcmp(Header1,"@ MFR ",6))
hdr->TYPE = MFER;
Put simply, libbiosig classifies an input file as MFER if the first few bytes match one of two magic byte sequences and stores the file classification in the struct member hdr->TYPE
.
Further along in sopen_extended
, after getfiletype
has returned, hdr->TYPE
is checked again and, if it’s MFER, processing unique to the format is then performed. This code block starts by defining some temporary variables that will be used for parsing the MFER file, including a statically-sized 128-byte stack-allocated buffer named buf
[1] which will become important later. From there, the bulk of the file processing is done inside a while loop [2] that continues so long as there are remaining bytes to be read from the input file, which hdr
is a handle to:
uint8_t buf[128]; // [1]
void* ptrbuf = buf;
uint8_t gdftyp = 3; // default: int16
uint8_t UnitCode=0;
double Cal = 1.0, Off = 0.0;
char SWAP = ( __BYTE_ORDER == __LITTLE_ENDIAN); // default of MFER is BigEndian
hdr->FILE.LittleEndian = 0;
hdr->SampleRate = 1000; // default sampling rate is 1000 Hz
hdr->NS = 1; // default number of channels is 1
/* TAG */
uint8_t tag = hdr->AS.Header[0];
ifseek(hdr,1,SEEK_SET);
int curPos = 1;
size_t N_EVENT=0; // number of events, memory is allocated for in the event table.
while (!ifeof(hdr)) { // [2]
uint32_t len, val32=0;
int32_t chan=-1;
uint8_t tmplen;
if (tag==255)
break;
else if (tag==63) {
/* CONTEXT */
curPos += ifread(buf,1,1,hdr);
chan = buf[0] & 0x7f;
while (buf[0] & 0x80) {
curPos += ifread(buf,1,1,hdr);
chan = (chan<<7) + (buf[0] & 0x7f);
}
}
/* LENGTH */
curPos += ifread(&tmplen,1,1,hdr);
char FlagInfiniteLength = 0;
if ((tag==63) && (tmplen==0x80)) { // [3]
FlagInfiniteLength = -1; //Infinite Length
len = 0;
}
else if (tmplen & 0x80) { // [5]
tmplen &= 0x7f;
curPos += ifread(&buf,1,tmplen,hdr); // [8]
len = 0;
k = 0;
while (k<tmplen)
len = (len<<8) + buf[k++];
}
else
len = tmplen; // [4]
The encoding rules for MFER, as described in ISO-22066-1-2022, specify data should be structured in the form Tag, Data Length, Value, or TLV. Broadly speaking, the Tag portion classifies the data, the Data Length portion encodes the length of the data in octets (bytes), and the Value portion encodes the actual payload. Of particular interest to these vulnerabiities is the Length portion, which the MFER specification allows to be encoded in one of three ways.
tmplen
) and checking it against 0x80 [3].len
) equal to the value of the first octet read (tmplen
) [4].buf
equal to the value of the first octet read (tmplen
), interpreting this sequence of bytes as an integer, and storing the result in len
[5].Although libbiosig’s handling of the length encoding superficially adheres to the MFER specification, the bulk of the MFER parsing code implicitly assumes that the data length is at most 127 bytes. In fact, there are many locations within the source code where len
bytes are read from the input file and written to a stack buffer without ensuring that the destination buffer is large enough to hold len
bytes, and every discovered vulnerability matching this pattern is outlined under its own heading in this report. For this general analysis, the specific vulnerability exercised by the attached POC will be used, which occurs when the Tag is 0:
if (tag==0) {
if (len!=1) fprintf(stderr,"Warning MFER tag0 incorrect length %i!=1\n",len); // [6]
curPos += ifread(buf,1,len,hdr); // [7]
}
Based on the warning message [6], it appears that Tag 0 is a special case where the length should always be 1. Despite this, libbiosig will continue processing using whatever length was read from the input file, and will attempt to read that many bytes from the file into buf
via a call to ifread
(which is simply a wrapper for fread
) [7]. Although libbiosig will usually output an error message when the length for a particular frame doesn’t match what is expected based on its Tag, these length checks do not impact the flow of execution and thus remain legitimate attack vectors.
As mentioned previously, buf
is a statically-sized 128-byte stack-allocated buffer. This becomes problematic in cases where len
is greater than 128 bytes, which is explicitly allowed in cases where the length is encoded using multiple octets. In our testing, a maliciously crafted input file was supplied to libbiosig, where the first octet of one of frames’ Data Length portion was 0xD9, which libbiosig correctly decoded to mean a length field that is 0x59 (89) octets long. This was confirmed by stepping into the ifread
call used to read the full length field into buf
[8] and inspecting the third argument:
0x00007ffff72c6bdc in ifread (ptr=0x7ffff2e0b4f0, size=1, nmemb=89, hdr=0x519000001980) at biosig.c:558
558 return(fread(ptr, size, nmemb, hdr->FILE.FID));
────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────
In file: /home/mbereza/Projects/BioSig/biosig-code/biosig4c++/biosig.c:558
553 #ifdef ZLIB_H
554 if (hdr->FILE.COMPRESSION>0)
555 return(gzread(hdr->FILE.gzFID, ptr, size * nmemb)/size);
556 else
557 #endif
► 558 return(fread(ptr, size, nmemb, hdr->FILE.FID));
559 }
560
561 size_t ifwrite(void* ptr, size_t size, size_t nmemb, HDRTYPE* hdr) {
562 #ifdef ZLIB_H
563 if (hdr->FILE.COMPRESSION)
──────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
► 0 0x7ffff72c6bdc ifread+12
1 0x7ffff732b725 sopen_extended+178229
2 0x5555555554c8 main+511
3 0x7ffff6a2a1ca __libc_start_call_main+122
4 0x7ffff6a2a28b __libc_start_main+139
5 0x555555555205 _start+37
While the full 89-byte length would not fit in len
(as it is a 32-bit integer), libbiosig still attempted to interpret these bytes as the length, resulting in a computed length of 538976288, which was confirmed via the warning message [6] for Tag 0 lengths that aren’t 1:
Run till exit from #0 fprintf (__fmt=0x7ffff752f1e0 "Warning MFER tag0 incorrect length %i!=1\n", __stream=<optimized out>)
at /usr/include/x86_64-linux-gnu/bits/stdio2.h:79
Warning MFER tag0 incorrect length 538976288!=1
From there, the program attempts to read that many bytes into buf
via a call to ifread
[7]:
Breakpoint 4, ifread (ptr=0x7ffff2e0b4f0, size=1, nmemb=538976288, hdr=0x519000001980) at biosig.c:552
552 size_t ifread(void* ptr, size_t size, size_t nmemb, HDRTYPE* hdr) {
────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────
In file: /home/mbereza/Projects/BioSig/biosig-code/biosig4c++/biosig.c:552
547 else
548 #endif
549 return(fflush(hdr->FILE.FID));
550 }
551
► 552 size_t ifread(void* ptr, size_t size, size_t nmemb, HDRTYPE* hdr) {
553 #ifdef ZLIB_H
554 if (hdr->FILE.COMPRESSION>0)
555 return(gzread(hdr->FILE.gzFID, ptr, size * nmemb)/size);
556 else
557 #endif
──────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
► 0 0x7ffff72c6bd0 ifread
1 0x7ffff732b6ef sopen_extended+178175
2 0x5555555554c8 main+511
3 0x7ffff6a2a1ca __libc_start_call_main+122
4 0x7ffff6a2a28b __libc_start_main+139
5 0x555555555205 _start+37
This results in a stack-based buffer overflow that clobbers much of the stack, corrupting the backtrace. Attempting to step out of this function via GDB has execution pick up further along in sopen_extended
, on line 9101 of biosig.c:
9101 curPos += ifread(buf,1,len,hdr);
────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────
In file: /home/mbereza/Projects/BioSig/biosig-code/biosig4c++/biosig.c:9101
9096 }
9097 else if (tag==65) //0x41: patient event
9098 {
9099 // event table
9100
► 9101 curPos += ifread(buf,1,len,hdr);
9102 if (len>2) {
9103 size_t N = hdr->EVENT.N;
9104 #ifdef CURRENTLY_NOT_AVAILABLE
9105 // FIXME: biosig_set_number_of_events is currently part of biosig2 interface
9106 if (N_EVENT <= N) {
──────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
► 0 0x7ffff732b6cd sopen_extended+178141
1 0x5555555554c8 main+511
2 0x7ffff6a2a1ca __libc_start_call_main+122
3 0x7ffff6a2a28b __libc_start_main+139
4 0x555555555205 _start+37
Execution has put us in the branch that handles Tag 65 despite the Tag being read as 0 earlier, right before another call to ifread
. Attempting to return from this second call to ifread
trips AddressSanitizer, confirming a stack-based buffer overflow condition:
==225922==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffff2e0b570 at pc 0x7ffff787ed7f bp 0x7fffffffa820 sp 0x7fffffff9fc8
WRITE of size 3936 at 0x7ffff2e0b570 thread T0
#0 0x7ffff787ed7e in fread ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:996
#1 0x7ffff732b6ee in sopen_extended /home/mbereza/Projects/BioSig/biosig-code/biosig4c++/biosig.c:9101
#2 0x5555555554c7 in main harness.cpp:38
#3 0x7ffff6a2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#4 0x7ffff6a2a28a in __libc_start_main_impl ../csu/libc-start.c:360
#5 0x555555555204 in _start (/home/mbereza/Projects/BioSig/repro_master/harness+0x1204) (BuildId: 3972e4805659faea250601a1b5068af2cb2a1ca5)
Address 0x7ffff2e0b570 is located in stack of thread T0 at offset 9584 in frame
#0 0x7ffff72ffeff in sopen_extended /home/mbereza/Projects/BioSig/biosig-code/biosig4c++/biosig.c:3714
This frame has 123 object(s):
[32, 33) 'gdftyp' (line 8666)
...
[9456, 9584) 'buf' (line 8664)
[9616, 9872) 'tmp' (line 7385) <== Memory access at offset 9584 partially underflows this variable
[9936, 10192) 'tmp' (line 9089) <== Memory access at offset 9584 partially underflows this variable
[10256, 10512) 'tmp' (line 11054) <== Memory access at offset 9584 partially underflows this variable
[10576, 10832) 'cmd' (line 12168) <== Memory access at offset 9584 partially underflows this variable
[10896, 11153) 'buf' (line 8882) <== Memory access at offset 9584 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:996 in fread
Shadow bytes around the buggy address:
0x7ffff2e0b280: 00 00 00 00 00 00 00 00 01 f2 f2 f2 f2 f2 00 00
0x7ffff2e0b300: 00 00 00 00 00 00 00 00 01 f2 f2 f2 f2 f2 00 00
0x7ffff2e0b380: 00 00 00 00 00 00 00 00 01 f2 f2 f2 f2 f2 00 00
0x7ffff2e0b400: 00 00 00 00 00 00 00 00 01 f2 f2 f2 f2 f2 00 00
0x7ffff2e0b480: 00 00 00 00 00 00 00 00 01 f2 f2 f2 f2 f2 00 00
=>0x7ffff2e0b500: 00 00 00 00 00 00 00 00 00 00 00 00 00 00[f2]f2
0x7ffff2e0b580: f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7ffff2e0b600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x7ffff2e0b680: 00 00 f2 f2 f2 f2 f2 f2 f2 f2 f8 f8 f8 f8 f8 f8
0x7ffff2e0b700: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f8
0x7ffff2e0b780: f8 f8 f8 f8 f8 f8 f8 f8 f8 f8 f2 f2 f2 f2 f2 f2
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
==225922==ABORTING
[Inferior 1 (process 225922) exited with code 01]
Since the data written past the end of this buffer is read from hdr
, which itself is populated using data from the input file, this data is attacker-controlled. The end result is a set of vulnerabilities where an attacker can write arbitrary data past the end of a stack-allocated buffer, potentially resulting in arbitrary code execution.
This vulnerability manifests on line 8719 of biosig.c on the current master branch (35a819fa), when the Tag is 0:
if (tag==0) {
if (len!=1) fprintf(stderr,"Warning MFER tag0 incorrect length %i!=1\n",len);
curPos += ifread(buf,1,len,hdr);
}
Warning MFER tag0 incorrect length 0!=1
...
Warning MFER tag0 incorrect length 0!=1
Warning MFER tag0 incorrect length 100!=1
Warning MFER tag0 incorrect length 538976288!=1
*** stack smashing detected ***: terminated
Program received signal SIGABRT, Aborted.
__pthread_kill_implementation (no_tid=0, signo=6, threadid=<optimized out>) at ./nptl/pthread_kill.c:44
warning: 44 ./nptl/pthread_kill.c: No such file or directory
LEGEND: STACK | HEAP | CODE | DATA | WX | RODATA
─────────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]──────────────────────────────────────────────
RAX 0
RBX 0x333fb
RCX 0x7ffff769eb2c (pthread_kill+284) ◂— mov r14d, eax
RDX 6
RDI 0x333fb
RSI 0x333fb
R8 0
R9 0x7ffff7ffb440 (tunable_list) ◂— 'glibc.malloc.mxfast'
R10 8
R11 0x246
R12 6
R13 0x7fffffffccb0 ◂— 0
R14 0x16
R15 0x7fffffffccb0 ◂— 0
RBP 0x7fffffffcb60 —▸ 0x7fffffffcb80 —▸ 0x7fffffffcc40 —▸ 0x7fffffffcd60 —▸ 0x7fffffffcd70 ◂— ...
RSP 0x7fffffffcb20 ◂— 0
RIP 0x7ffff769eb2c (pthread_kill+284) ◂— mov r14d, eax
──────────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]───────────────────────────────────────────────────────
► 0x7ffff769eb2c <pthread_kill+284> mov r14d, eax R14D => 0
0x7ffff769eb2f <pthread_kill+287> neg r14d
0x7ffff769eb32 <pthread_kill+290> cmp eax, 0xfffff000 0x0 - 0xfffff000 EFLAGS => 0x207 [ CF PF af zf sf IF df of ]
0x7ffff769eb37 <pthread_kill+295> mov eax, 0 EAX => 0
0x7ffff769eb3c <pthread_kill+300> cmovbe r14d, eax
0x7ffff769eb40 <pthread_kill+304> jmp pthread_kill+176 <pthread_kill+176>
↓
0x7ffff769eac0 <pthread_kill+176> mov rax, qword ptr [rbp - 0x38] RAX, [0x7fffffffcb28] => 0xf51039677f56b400
0x7ffff769eac4 <pthread_kill+180> sub rax, qword ptr fs:[0x28] RAX => 0 (0xf51039677f56b400 - 0xf51039677f56b400)
0x7ffff769eacd <pthread_kill+189> jne pthread_kill+341 <pthread_kill+341>
0x7ffff769ead3 <pthread_kill+195> add rsp, 0x18 RSP => 0x7fffffffcb38 (0x7fffffffcb20 + 0x18)
0x7ffff769ead7 <pthread_kill+199> mov eax, r14d EAX => 0
────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────
00:0000│ rsp 0x7fffffffcb20 ◂— 0
01:0008│-038 0x7fffffffcb28 ◂— 0xf51039677f56b400
02:0010│-030 0x7fffffffcb30 ◂— 0x45000000006b0000
03:0018│-028 0x7fffffffcb38 ◂— 6
04:0020│-020 0x7fffffffcb40 —▸ 0x7ffff7c95740 ◂— 0x7ffff7c95740
05:0028│-018 0x7fffffffcb48 —▸ 0x7fffffffccb0 ◂— 0
... ↓ 2 skipped
──────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
► 0 0x7ffff769eb2c pthread_kill+284
1 0x7ffff769eb2c pthread_kill+284
2 0x7ffff769eb2c pthread_kill+284
3 0x7ffff764527e raise+30
4 0x7ffff76288ff abort+223
5 0x7ffff76297b6 _IO_peekc_locked.cold
6 0x7ffff7736c19 None
7 0x7ffff7737ea4 None
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
This vulnerability manifests on line 8744 of biosig.c on the current master branch (35a819fa), when the Tag is 3:
else if (tag==3) {
// character code
char v[17]; // [1]
if (len>16) fprintf(stderr,"Warning MFER tag2 incorrect length %i>16\n",len);
curPos += ifread(&v,1,len,hdr);
v[len] = 0;
In this case, the overflowed buffer is the newly-declared v
[1] instead of buf
. Since v
is only 17 bytes large, much smaller values of len
(even those encoded using a single octet) can trigger an overflow in this code path.
This vulnerability manifests on line 8751 of biosig.c on the current master branch (35a819fa), when the Tag is 4:
else if (tag==4) {
// SPR
if (len>4) fprintf(stderr,"Warning MFER tag4 incorrect length %i>4\n",len);
curPos += ifread(buf,1,len,hdr);
This vulnerability manifests on line 8759 of biosig.c on the current master branch (35a819fa), when the Tag is 5:
else if (tag==5) //0x05: number of channels
{
uint16_t oldNS=hdr->NS;
if (len>4) fprintf(stderr,"Warning MFER tag5 incorrect length %i>4\n",len);
curPos += ifread(buf,1,len,hdr);
This vulnerability manifests on line 8779 of biosig.c on the current master branch (35a819fa), when the Tag is 6:
else if (tag==6) // 0x06 "number of sequences"
{
// NRec
if (len>4) fprintf(stderr,"Warning MFER tag6 incorrect length %i>4\n",len);
curPos += ifread(buf,1,len,hdr);
This vulnerability manifests on line 8785 of biosig.c on the current master branch (35a819fa), when the Tag is 8:
else if (tag==8) {
if (len>2) fprintf(stderr,"Warning MFER tag8 incorrect length %i>2\n",len);
curPos += ifread(buf,1,len,hdr);
This vulnerability manifests on line 8824 of biosig.c on the current master branch (35a819fa), when the Tag is 11:
else if (tag==11) //0x0B
{
// Fs
if (len>6) fprintf(stderr,"Warning MFER tag11 incorrect length %i>6\n",len);
double fval;
curPos += ifread(buf,1,len,hdr);
This vulnerability manifests on line 8842 of biosig.c on the current master branch (35a819fa), when the Tag is 12:
else if (tag==12) //0x0C
{
// sampling resolution
if (len>6) fprintf(stderr,"Warning MFER tag12 incorrect length %i>6\n",len);
val32 = 0;
int8_t v8;
curPos += ifread(&UnitCode,1,1,hdr);
curPos += ifread(&v8,1,1,hdr);
curPos += ifread(buf,1,len-2,hdr);
In addition to values of len
greater than 130 triggering a buffer overflow, a value of len
smaller than 2 will also trigger a buffer overflow due to an integer underflow when computing len-2
in this code path.
This vulnerability manifests on line 8850 of biosig.c on the current master branch (35a819fa), when the Tag is 13:
else if (tag==13) {
if (len>8) fprintf(stderr,"Warning MFER tag13 incorrect length %i>8\n",len);
curPos += ifread(&buf,1,len,hdr);
This vulnerability manifests on line 8970 of biosig.c on the current master branch (35a819fa), when the Tag is 63:
else if (tag==63) {
uint8_t tag2=255, len2=255;
count = 0;
while ((count<len) && !(FlagInfiniteLength && len2==0 && tag2==0)){
curPos += ifread(&tag2,1,1,hdr);
curPos += ifread(&len2,1,1,hdr);
if (VERBOSE_LEVEL==9)
fprintf(stdout,"MFER: tag=%3i chan=%2i len=%-4i tag2=%3i len2=%3i curPos=%i %li count=%4i\n",tag,chan,len,tag2,len2,curPos,iftell(hdr),(int)count);
if (FlagInfiniteLength && len2==0 && tag2==0) break;
count += (2+len2);
curPos += ifread(&buf,1,len2,hdr);
Here, the number of bytes read is not the Data Length decoded from the current frame in the file (len
) but rather is a new length contained in a single octet read from the same input file (len2
). Despite this, a stack-based buffer overflow condition can still occur, as the destination buffer is still buf
, which has a size of only 128 bytes, while len2
can be as large as 255.
This vulnerability manifests on line 9090 of biosig.c on the current master branch (35a819fa), when the Tag is 64:
else if (tag==64) //0x40
{
// preamble
char tmp[256]; // [1]
curPos += ifread(tmp,1,len,hdr);
In this case, the overflowed buffer is the newly-declared tmp
[1] instead of buf
. While tmp
is larger than buf
, having a size of 256 bytes, a stack overflow can still occur in cases where len
is encoded using multiple octets and is greater than 256.
This vulnerability manifests on line 9191 of biosig.c on the current master branch (35a819fa), when the Tag is 65:
else if (tag==65) //0x41: patient event
{
// event table
curPos += ifread(buf,1,len,hdr);
This vulnerability manifests on line 9141 of biosig.c on the current master branch (35a819fa), when the Tag is 67:
else if (tag==67) //0x43: Sample skew
{
int skew=0; // [1]
curPos += ifread(&skew, 1, len,hdr);
In this case, the address of the newly-defined integer skew
[1] is overflowed instead of buf
. This means a stack overflow can occur using much smaller values of len
in this code path.
This vulnerability manifests on line 9184 of biosig.c on the current master branch (35a819fa), when the Tag is 131:
else if (tag==131) //0x83
{
// Patient Age
if (len!=7) fprintf(stderr,"Warning MFER tag131 incorrect length %i!=7\n",len);
curPos += ifread(buf,1,len,hdr);
This vulnerability manifests on line 9205 of biosig.c on the current master branch (35a819fa), when the Tag is 133:
else if (tag==133) //0x85
{
curPos += ifread(buf,1,len,hdr);
2025-08-06 - Vendor Disclosure
2025-08-24 - Vendor Patch Release
2025-08-25 - Public Release
Discovered by Mark Bereza and Lilith >_> of Cisco Talos.