https://bugs.kde.org/show_bug.cgi?id=524551

            Bug ID: 524551
           Summary: [SECURITY] Integer overflow to heap out-of-bounds
                    write
    Classification: Applications
           Product: okular
      Version First unspecified
       Reported In:
          Platform: Other
                OS: Other
            Status: REPORTED
          Severity: grave
          Priority: NOR
         Component: DVI backend
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

### Summary

Okular's DVI generator plugin (`generators/dvi`) is vulnerable to a heap-based
buffer overflow (CWE-190 leading to CWE-787). An integer overflow during the
processing of a DVI `\special` command allows a 32-bit length field `a` to wrap
to a 0-byte allocation during `new char[a + 1]`. The subsequent unregulated
`strncpy` operation copies up to 4 GiB of attacker-controlled file data into
the minimal heap allocation, causing a deliberate and severe out-of-bounds
write. Recommended severity: **High**.

### Details

When a DVI file is loaded, `dviRenderer::setFile` processes document contents
by scanning the file for specials via `prescan`. Specifically, the code inside
`dviRenderer_prescan.cpp` explicitly handles opcodes `XXX1` through `XXX4` (239
through 242) starting at line 795:

```cpp
case XXX4: {
    quint8 *beginningOfSpecialCommand = command_pointer - 1;
    quint32 a = readUINT(ch - XXX1 + 1);
    if (a > 0) {
        char *cmd = new char[a + 1];  // Wraps to 0 when a == 0xFFFFFFFF
        strncpy(cmd, reinterpret_cast<char *>(command_pointer), a);
        command_pointer += a;
        cmd[a] = '\0';
``` 

`bigEndianByteReader::readUINT` reads the designated length bytes directly from
the file buffer without upper-bound validation against the `end_pointer` or
structural thresholds.

The `a` variable is declared as `quint32`. If the 4-byte read returns
`0xFFFFFFFF` (4,294,967,295), standard arithmetic causes `a + 1` to wrap to
exactly `0` when allocating memory via `new char[0]`.
However, the `strncpy` and assignment logic blindly passes the pre-wrapped
32-bit `a` parameter to transfer bytes off the `command_pointer`. This causes a
catastrophic copy of practically unbounded length across the heap boundary. 

Additionally, because `command_pointer + a` is never checked against
`end_pointer`, any large value of `a` can easily trigger out-of-bounds
sequential heap *reads* that bleed file-mapping internals to potential
PostScript rendering or hyperlinking consumers (which process the `cmd` data
array downstream). 

This identical pattern is duplicated independently during the drawing phase in
`dviRenderer_draw.cpp:508-514`, making the vulnerability reachable multiple
times.

### PoC

1. Save a minimal trigger byte sequence indicating the `XXX4` opcode (hex
`F2`), followed by an unmanageably large length `FF FF FF FF`, inside a valid
`.dvi` body block.
2. Example hex representation snippet: 
   `... F2 FF FF FF FF <attacker_raw_payload_bytes> ...`
3. Load the resulting `.dvi` file in Okular. 
4. The process aborts instantly (Denial of Service/Heap Corruption). Under
Address Sanitizer (ASAN), it registers an immediate `heap-buffer-overflow WRITE
of size 1` generated during the unbounded `strncpy` executed over the 0-byte
chunk.

### Impact

This constitutes an uncontrolled heap out-of-bounds write of remote,
unauthenticated file content. Given that `strncpy` NUL-pads to `n`, it cannot
be cleanly truncated with an early `\0` in the payload, forcing the write to
storm through the process's allocated heaps until it sequentially hits an
unmapped border (inevitably crashing as a Denial of Service). 

Full remote code execution (RCE) is plausible if an attacker successfully
grooms the system heap prior through other rendering primitives to hijack
corrupted adjacent C++ object metadata, albeit very complex due to the
uncontrolled continuous bounds. 

To resolve the vulnerability, switch arithmetic to use `size_t` correctly on
64-bit systems and employ `qMin<qint64>(a, end_pointer - command_pointer)` to
strictly limit interactions within bounds.

-- 
You are receiving this mail because:
You are watching all bug changes.

Reply via email to