Source: minidlna
Version: 1.3.3+dfsg-1.1
Severity: important
Tags: security upstream patch

Hi,

CVE-2026-29508 is listed as undetermined and has no Debian bug. It does
affect Debian, and I found no upstream fix: the upstream repository's
latest commit is from 2023, and tagutils/tagutils-dff.c last changed in
2020. A patch is attached.

_get_dfffileinfo() in tagutils/tagutils-dff.c takes the 64-bit PROP chunk
size from the file and declares a stack array of that size, with no bound:

propckDataSize = GET_DFF_INT64(ckbuf + 4);
unsigned char propckData[propckDataSize];

The sub-chunk parsing that follows also reads and advances using sizes from
the file without checking them against the chunk. The file is identical in
1.3.3+dfsg-1.1 and 1.3.0+dfsg-2.2+deb12u1. Per the CVE description, a
crafted .dff file in a scanned directory is enough to reach it.

The patch rejects PROP sizes outside 4..4096 bytes, since the PROP chunks
in the files I generated are well under that. It also checks that each
sub-chunk read stays inside the chunk.

What I checked: the patch applies to both versions. I compiled the parser
on its own before and after the patch under ASan/UBSan, against each
version's tagutils.h, with small stand-ins for logging. Four valid DFF
files that I generated (1, 2 and 6 channels, with and without the optional
ABSS and LSCO chunks) gave identical sample rate, channels, bitrate and
length before and after, with no sanitizer reports.

What I did not test: I did not reproduce the overflow or run oversized or
malformed files through the patched code. I also did not do a full package
build, or test real-world DFF files, which is the main risk of the
4096-byte limit. Please adjust it if you know of files with larger PROP
chunks.

Separately, and not addressed by this patch: the DST branch divides by a
frame rate taken from the file, without a zero check.

Regards,
Sumit Verma
Description: Bound the DFF PROP chunk before allocating it on the stack
 _get_dfffileinfo() declared a variable-length stack array from the 64-bit
 PROP chunk size in the file. Reject sizes outside 4..4096 bytes, and check
 that each sub-chunk read stays inside the chunk.
Author: Sumit Verma <[email protected]>
Bug-Debian-Security: CVE-2026-29508
Forwarded: no
Last-Update: 2026-11-08
---
--- a/tagutils/tagutils-dff.c
+++ b/tagutils/tagutils-dff.c
@@ -36,6 +36,9 @@
 #define GET_DFF_INT16(p) ((((uint16_t)((p)[0])) << 8) |   \
 			  (((uint16_t)((p)[1]))))
 
+/* A real PROP chunk is a few hundred bytes at most, and it lives on the stack */
+#define DFF_MAX_PROP_SIZE 4096
+
 static int
 _get_dfffileinfo(char *file, struct song_metadata *psong)
 {
@@ -125,6 +128,12 @@
 		if (strncmp((char*)ckbuf, "PROP", 4) == 0)
 		{
 			propckDataSize = GET_DFF_INT64(ckbuf + 4);
+			if (propckDataSize < 4 || propckDataSize > DFF_MAX_PROP_SIZE)
+			{
+				DPRINTF(E_WARN, L_SCANNER, "Invalid Property chunk size in %s\n", file);
+				fclose(fp);
+				return -1;
+			}
 			totalcount += propckDataSize + 12;
 
 			unsigned char propckData[propckDataSize];
@@ -144,11 +153,13 @@
 			}
 
 			count += 4;
-			while (count < propckDataSize)
+			while (count + 12 <= propckDataSize)
 			{
 				if (strncmp((char*)propckData + count, "FS  ", 4) == 0)
 				{
 					//Sample Rate Chunk
+					if (count + 16 > propckDataSize)
+						break;
 					count += 12;
 					samplerate = GET_DFF_INT32(propckData + count);
 					psong->samplerate = samplerate;
@@ -159,6 +170,8 @@
 				else if (strncmp((char*)propckData + count, "CHNL", 4) == 0)
 				{
 					//Channels Chunk
+					if (count + 14 > propckDataSize)
+						break;
 					count += 12;
 					channels = GET_DFF_INT16(propckData + count);
 					psong->channels = channels;
@@ -169,8 +182,12 @@
 				else if (strncmp((char*)propckData + count, "CMPR", 4) == 0)
 				{
 					//Compression Type Chunk
+					if (count + 16 > propckDataSize)
+						break;
 					count += 4;
 					cmprckDataSize = GET_DFF_INT64(propckData + count);
+					if (cmprckDataSize > propckDataSize)
+						break;
 					count += 8;
 					memcpy(compressionType, propckData + count, 4);
 					count += cmprckDataSize;
@@ -180,6 +197,8 @@
 					//Absolute Start Time Chunk
 					count += 4;
 					abssckDataSize = GET_DFF_INT64(propckData + count);
+					if (abssckDataSize > propckDataSize)
+						break;
 					count += abssckDataSize + 8;
 				}
 				else if (strncmp((char*)propckData + count, "LSCO", 4) == 0)
@@ -187,6 +206,8 @@
 					//Loudsperaker Configuration Chunk
 					count += 4;
 					lscockDataSize = GET_DFF_INT64(propckData + count);
+					if (lscockDataSize > propckDataSize)
+						break;
 					count += lscockDataSize + 8;
 				}
 				else

Reply via email to