Project

General

Profile

Actions

Bug #8238

open

Unsigned integer underflow in quoted-printable decoder with small input chunks

Added by Vasil Medvedev 6 days ago. Updated 5 days ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
Affected Versions:
Effort:
Difficulty:
Label:

Description

When state->bvr_len > 0 and the buffered data starts with '=', the code attempts to complete a quoted-printable escape sequence and then adjusts the input counters using the following logic:

offset = 3 - state->bvr_len;
remaining -= offset;

Both offset and remaining are unsigned integers.
If the current input buffer is smaller than the required number of bytes to complete the escape sequence (for example, when the next chunk is only 1 byte long), offset may become larger than remaining. In this case, the subtraction:

remaining -= offset;

causes an unsigned integer underflow, resulting in remaining wrapping to a very large value.

FIX:

Index: suricata-7.0.14/src/util-decode-mime.c
===================================================================
--- suricata-7.0.14.orig/src/util-decode-mime.c
+++ suricata-7.0.14/src/util-decode-mime.c
@@ -1474,6 +1474,11 @@ static int ProcessQuotedPrintableBodyLin
                 state->data_chunk[state->data_chunk_len] = val;
                 state->data_chunk_len++;
                 offset = 3 - state->bvr_len;
+                if (remaining < offset) {
+                    memcpy(state->bvremain + state->bvr_len, buf, remaining);
+                    state->bvr_len += remaining;
+                    return MIME_DEC_OK;
+                }
                 remaining -= offset;
                 /* If buffer full, then invoke callback */
                 if (DATA_CHUNK_SIZE - state->data_chunk_len < EOL_LEN + 1) {

also attach the PCAP traffic.

root@vpp-bez-nazvaniya-adc6f139-9d89-4fa9-b820-d3e50b541bc8 ~]# suricata --build-info
This is Suricata version 7.0.13 RELEASE
Features: NFQ PCAP_SET_BUFF HAVE_PACKET_FANOUT LIBCAP_NG LIBNET1.1 HAVE_HTP_URI_NORMALIZE_HOOK PCRE_JIT HAVE_NSS HTTP2_DECOMPRESSION HAVE_JA3 HAVE_JA4 HAVE_LIBJANSSON TLS TLS_C11 MAGIC RUST POPCNT64 
SIMD support: SSE_2 
Atomic intrinsics: 1 2 4 8 byte(s)
64-bits, Little-endian architecture
GCC version 14.2.1 20250110 (Red Hat 14.2.1-7), C version 201112
L1 cache line size (CLS)=64
thread local storage method: _Thread_local
compiled with LibHTP v0.5.52, linked against LibHTP v0.5.52

Suricata Configuration:
  AF_PACKET support:                       no
  AF_XDP support:                          no
  DPDK support:                            no
  eBPF support:                            no
  XDP support:                             no
  PF_RING support:                         no
  NFQueue support:                         yes
  NFLOG support:                           no
  IPFW support:                            no
  Netmap support:                          no 
  DAG enabled:                             no
  Napatech enabled:                        no
  WinDivert enabled:                       no

  Unix socket enabled:                     yes
  Detection enabled:                       yes

  Libmagic support:                        yes
  libjansson support:                      yes
  hiredis support:                         no
  hiredis async with libevent:             no
  PCRE jit:                                yes
  LUA support:                             no
  libluajit:                               no
  GeoIP2 support:                          yes
  JA3 support:                             yes
  JA4 support:                             yes
  Non-bundled htp:                         no
  Hyperscan support:                       yes
  Libnet support:                          yes
  liblz4 support:                          yes
  Landlock support:                        yes

  Rust support:                            yes
  Rust strict mode:                        no
  Rust compiler path:                      /usr/bin/rustc
  Rust compiler version:                   rustc 1.84.0 (9fc6b4312 2025-01-07) (Fedora 1.84.0-3.fc41)
  Cargo path:                              /usr/bin/cargo
  Cargo version:                           cargo 1.84.0 (66221abde 2024-11-19)

  Python support:                          no
  Python path:                             not set
  Install suricatactl:                     requires python
  Install suricatasc:                      requires python
  Install suricata-update:                 no, not bundled

  Profiling enabled:                       no
  Profiling locks enabled:                 no
  Profiling rules enabled:                 no

  Plugin support (experimental):           yes
  DPDK Bond PMD:                           no

Development settings:
  Coccinelle / spatch:                     no
  Unit tests enabled:                      no
  Debug output enabled:                    no
  Debug validation enabled:                no
  Fuzz targets enabled:                    no

Generic build parameters:
  Installation prefix:                     /usr
  Configuration directory:                 /etc/suricata/
  Log directory:                           /var/log/suricata/

  --prefix                                 /usr
  --sysconfdir                             /etc
  --localstatedir                          /var
  --datarootdir                            /usr/share

  Host:                                    x86_64-redhat-linux-gnu
  Compiler:                                gcc (exec name) / g++ (real)
  GCC Protect enabled:                     yes
  GCC march native enabled:                no
  GCC Profile enabled:                     no
  Position Independent Executable enabled: no
  CFLAGS                                   -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64 -march=x86-64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -mtls-dialect=gnu2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer  -fPIC -std=c11 -I${srcdir}/../rust/gen -I${srcdir}/../rust/dist
  PCAP_CFLAGS                               -I/usr/include
  SECCFLAGS                                -fstack-protector -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security


Files

test.pcap (80.1 KB) test.pcap Vasil Medvedev, 01/20/2026 04:22 PM
test2.pcap (264 Bytes) test2.pcap Vasil Medvedev, 01/20/2026 04:36 PM
Actions #1

Updated by Vasil Medvedev 6 days ago

  • File deleted (rx.pcap)
Actions #2

Updated by Vasil Medvedev 6 days ago

Actions #3

Updated by Vasil Medvedev 6 days ago

Actions #4

Updated by Philippe Antoine 5 days ago

Thanks for the interesting report.

I do not understand the pcaps : these are POP3 traffic but suricata 7 does not support pop3...

Suricata 7 only gets to this part of the code with SMTP

My analysis is that

With

offset = 3 - state->bvr_len;
remaining -= offset;

The only way to get the underflow (having state->bvr_len>0 as a condition tested in the code path) is to have remaining = 1, and offset=2 (with state->bvr_len=1)

But in this case we have

h2 = *(buf + offset + 1);
res = DecodeQPChar(h2);
if (res < 0) {

As the line only has one char, h2 is the linefeed character, and therefore res<0 fails and we do not get to the code that would overflow

Do you see otherwise ?

Actions

Also available in: Atom PDF