Skip to content

Segmentation Fault on Single-Byte UTF-16 BOM Input #10

Description

@newwin01

Segmentation Fault on Single-Byte UTF-16 BOM Input

Summary

The ezxml library crashes with a segmentation fault when parsing XML files containing a single byte 0xFE. This occurs due to incomplete UTF-16 BOM (Byte Order Mark) validation that violates the XML standard.

Environment

  • Library: ezxml v0.8.5
  • Platform: x86_64-linux-gnu
  • Compiler: GCC

Steps to Reproduce

  1. Create a file with a single byte 0xFE:

    printf '\xfe' > crash.xml
  2. Parse the file with ezxmltest:

    ./ezxmltest crash.xml
  3. Observe the crash:

    Segmentation fault (core dumped)
    

Expected Behavior

The library should either:

  • Treat the incomplete BOM as invalid and return an error
  • Fall back to UTF-8 encoding (default per XML standard)
  • Provide a clear error message instead of crashing

Actual Behavior

The program crashes with a segmentation fault due to NULL pointer dereference at ezxml.c:481.

Root Cause Analysis

GDB Backtrace

#0  ezxml_parse_str (s=0x0, len=0) at ezxml.c:481
#1  ezxml_parse_fd (fd=3) at ezxml.c:641
#2  ezxml_parse_file (file=0x7fffffffdf7c "crash.xml") at ezxml.c:659
#3  main (argc=2, argv=0x7fffffffdc08) at ezxml.c:1008

Technical Details

The XML standard specifies that:

  • UTF-16 Big Endian BOM: 0xFE 0xFF (2 bytes)
  • UTF-16 Little Endian BOM: 0xFF 0xFE (2 bytes)
  • Files without a complete BOM should be treated as UTF-8

However, the ezxml_str2utf8() function (line 427) only checks the first byte:

int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;

Crash Mechanism

  1. ezxml_str2utf8() misidentifies single byte 0xFE as UTF-16 BE BOM
  2. Sets be = 1 (UTF-16 Big Endian mode)
  3. The conversion loop for (sl = 2; sl < *len - 1; sl += 2) never executes because *len = 1
  4. Returns realloc(u, *len = 0) which returns NULL on many systems
  5. ezxml_parse_str() receives s = NULL, len = 0 but doesn't validate
  6. Line 481: e = s[len - 1] attempts s[-1] access → Segmentation Fault

Proposed Fix

Option 1: Complete BOM Validation (Recommended)

char *ezxml_str2utf8(char **s, size_t *len)
{
    char *u;
    size_t l = 0, sl, max = *len;
    long c, d;
    int b, be = -1;
    
    // UTF-16 BOM requires at least 2 bytes
    if (*len >= 2) {
        if ((*s)[0] == '\xFE' && (*s)[1] == '\xFF') {
            be = 1; // UTF-16 Big Endian
        }
        else if ((*s)[0] == '\xFF' && (*s)[1] == '\xFE') {
            be = 0; // UTF-16 Little Endian
        }
    }

    if (be == -1) return NULL; // not UTF-16
   
}

Option 2: Add NULL Check in Parser

ezxml_t ezxml_parse_str(char *s, size_t len)
{
    ezxml_root_t root = (ezxml_root_t)ezxml_new(NULL);
    // ...
    
    root->m = s;
    if (! len) return ezxml_err(root, NULL, "root tag missing");
    
    root->u = ezxml_str2utf8(&s, &len);
    
    // Add NULL check
    if (!s) {
        return ezxml_err(root, NULL, "invalid or incomplete UTF-16 BOM");
    }
    
    root->e = (root->s = s) + len;
    
    e = s[len - 1]; // now safe
    // ...
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions