(CVE-2025-6196) New Security Issue

Original reporter: Security Vulnerability Report: Integer Overflow in libgepub EPUB Parser

Area: Platform component (libraries, tools)

Message

Summary

A critical integer overflow vulnerability has been identified in libgepub's EPUB archive handling code. When processing specially crafted EPUB files, the gepub_archive_read_entry() function mishandles file size values, resulting in integer overflows that lead to massive memory allocation attempts and application crashes. This represents a potential denial of service vulnerability.

Vulnerability Details

Vulnerability Type: Integer Overflow / Type Mismatch Affected Component: gepub-archive.c in libgepub Severity: High Exploitability: Medium

The vulnerability stems from a type mismatch between the 64-bit value returned by archive_entry_size() and the 32-bit gint variable used to store it in gepub_archive_read_entry(). When processing large or malformed EPUB files, this mismatch can cause the size value to be truncated and potentially become negative. When this negative value is passed to g_malloc0(), it's interpreted as a massive positive value due to signed-to-unsigned conversion, resulting in allocation failures and application crashes.

Technical Analysis

Vulnerable Code

The vulnerability is in gepub_archive_read_entry() in gepub-archive.c:

GBytes *
gepub_archive_read_entry (GepubArchive *archive,
                          const gchar *path)
{
    struct archive_entry *entry;
    guchar *buffer;
    gint size;  // 32-bit integer
    const gchar *_path;

    //

    size = archive_entry_size (entry);  // Returns 64-bit integer
    buffer = g_malloc0 (size);  // Treats size as unsigned
    archive_read_data (archive->archive, buffer, size);

    gepub_archive_close (archive);
    return g_bytes_new_take (buffer, size);
}

The function archive_entry_size() is defined in libarchive's archive_entry.h as:

__LA_DECL la_int64_t archive_entry_size(struct archive_entry *);

And implemented in libarchive as:

la_int64_t
archive_entry_size(struct archive_entry *entry)
{
    return (entry->ae_stat.aest_size);
}

Crash Analysis

When a specially crafted EPUB file is processed, the following crash occurs:

DEBUG: Starting with file: findings_backup/slave05/crashes/id:000001,sig:05,src:000043,time:20841593,execs:31927516,op:havoc,rep:64
DEBUG: About to call gepub_doc_new
==1122360==WARNING: AddressSanitizer failed to allocate 0xfffffffff3ff0117 bytes

(process:1122360): GLib-ERROR **: 04:18:52.636: ../../../glib/gmem.c:139: failed to allocate 18446744073508159767 bytes

The AddressSanitizer output shows an attempt to allocate 0xfffffffff3ff0117 bytes (approximately 18.4 quintillion bytes), which fails as expected.

Stack Trace

The GDB backtrace reveals the exact sequence leading to the crash:

#0  g_log_structured_array [...]
#1  0x00007ffff77193cc in g_log_default_handler [...]
#2  0x00007ffff7719670 in g_logv [...]
#3  0x00007ffff7719953 in g_log [...]
#4  0x00007ffff771a7d5 in g_malloc0 (n_bytes=18446744073508159767) at ../../../glib/gmem.c:138
#5  0x00007ffff7fa69e2 in gepub_archive_read_entry
    (archive=0x504000021c50, path=0x7ffff7fad00d "META-INF/container.xml") at ../libgepub/gepub-archive.c:157
        entry = 0x51a000000080
        buffer = 0x508000002020 "2402"
        size = -201391849
        _path = 0x7ffff7fad00d "META-INF/container.xml"
#6  0x00007ffff7fa6a8f in gepub_archive_get_root_file (archive=0x504000021c50) at ../libgepub/gepub-archive.c:176
        doc = 0x0
        root_element = 0x0
        root_node = 0x0
        bytes = 0x50b000000ca0
        buffer = 0x508000002020 "2402"
        bufsize = 140737488346704
#7  0x00007ffff7fa7351 in gepub_doc_initable_init [...] at ../libgepub/gepub-doc.c:211
#8  0x00007ffff71c58bc in g_initable_new_valist [...]
#9  0x00007ffff71c59ab in g_initable_new [...]
#10 0x00007ffff7fa756a in gepub_doc_new [...]
#11 0x00005555555565f4 in main (argc=2, argv=0x7fffffffe1e8) at simple_debug_fuzzer.c:39

The key issue is visible in frame Teams/Releng/security#5, where size = -201391849. This negative value occurs due to the truncation of a 64-bit value to 32 bits. When passed to g_malloc0(), this negative value is treated as an unsigned value, resulting in an attempt to allocate approximately 18.4 quintillion bytes.

Reproduction

The vulnerability can be reproduced using the following steps:

  1. Obtain the crash file: findings_backup/slave05/crashes/id:000001,sig:05,src:000043,time:20841593,execs:31927516,op:havoc,rep:64
  2. Build a debug version of gepub with Address Sanitizer enabled
  3. Run: ./simple_debug_fuzzer_asan

Impact

This vulnerability can be exploited to cause denial of service by crafting EPUB files that trigger excessive memory allocation attempts. When such files are opened by applications using libgepub, they will crash due to memory allocation failures.

Additionally, in certain contexts, integer overflows can sometimes lead to more severe vulnerabilities such as buffer overflows or heap corruption if the allocation succeeds with a truncated size.

Remediation

The recommended fix is to:

  1. Change the type of size in gepub_archive_read_entry() from gint to gint64 or goffset to properly handle 64-bit values
  2. Add validation to ensure the size is reasonable before allocation:
gint64 size;  // Instead of gint size
size = archive_entry_size(entry);

// Validate size
if (size  G_MAXSIZE) {
    gepub_archive_close(archive);
    return NULL;
}

// Allocate buffer with additional error handling
buffer = g_malloc0(size);
if (!buffer) {
    gepub_archive_close(archive);
    return NULL;
}

Conclusion

This vulnerability highlights the importance of proper type handling and input validation when processing potentially malicious files. Integer overflow vulnerabilities can be subtle but have significant security implications. All applications using libgepub should be updated once a fix is available.

Assignee Loading
Time tracking Loading