Skip to content

UB in php_url_decode_ex #21738

@xfourj

Description

@xfourj

Description

Consider the following snippet within php_url_decode_ex at ext/standard/url.c :

else if (*data == '%' && src_len >= 2 && isxdigit((int) *(data + 1))
				 && isxdigit((int) *(data + 2))) {

In environments where char is signed by default—as is a common convention— high-bit bytes sign-extend to negative integers when being passed to isxdigit. That violates the ISO C standard's requirement for isxdigit in <ctype.h> to be represenetable as an unsigned char (0 to 255), which leads to UB.

Example (taking \x80 as the byte):

<?php
urldecode("%\x80");
?>

Resulted in this output:

(gdb) p *(data+1)
$1 = -128 '\200'

Note that for libraries that implement isxdigit via maps (similar to glibc), if no proper padding is done then OOB read might occur (.e.g for NetBSD libc, due to "lack" of padding, similar bytes as input trigger OOB read).

PHP Version

PHP 8.4+

Operating System

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions