Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ PHP NEWS
. Fixed bug GH-21689 (version_compare() incorrectly handles versions ending
with a dot). (timwolla)

- URI:
. Fixed CVE-2026-44927 (In uriparser before 1.0.2, there is pointer
difference truncation to int in various places). (CVE-2026-44927)
(Sebastian Pipping)
. Fixed CVE-2026-44928 (In uriparser before 1.0.2, the function family
EqualsUri can misclassify two unequal URIs as equal). (CVE-2026-44928)
(Sebastian Pipping)

07 May 2026, PHP 8.5.6

- Core:
Expand Down
2 changes: 1 addition & 1 deletion ext/uri/uriparser/include/uriparser/Uri.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* 53c1cb9f2f728652fe001dc72fa0fa7a0e9fa0b8baaaa9e37561c6cdf88ac4df (1.0.1+)
/* c9d94656d067288e474df19a062d487c736b0fa8517d2ef7bbeb8dcd5a70c05b (1.0.2+)
*
* uriparser - RFC 3986 URI parsing library
*
Expand Down
2 changes: 1 addition & 1 deletion ext/uri/uriparser/include/uriparser/UriBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
/* Version */
# define URI_VER_MAJOR 1
# define URI_VER_MINOR 0
# define URI_VER_RELEASE 1
# define URI_VER_RELEASE 2
# define URI_VER_SUFFIX_ANSI ""
# define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI)

Expand Down
40 changes: 15 additions & 25 deletions ext/uri/uriparser/src/UriCommon.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@

# include <assert.h>
# include <stddef.h>
# include <stdint.h> // SIZE_MAX

/*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X");
/*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT(".");
Expand Down Expand Up @@ -105,46 +106,35 @@ int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
}

/* Compares two text ranges for equal text content */
int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) {
int diff;
ptrdiff_t lenA;
ptrdiff_t lenB;

bool URI_FUNC(RangeEquals)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) {
/* NOTE: Both NULL means equal! */
if ((a == NULL) || (b == NULL)) {
return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1);
return a == b;
}

/* NOTE: Both NULL means equal! */
if ((a->first == NULL) || (b->first == NULL)) {
return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1);
}

lenA = a->afterLast - a->first;
lenB = b->afterLast - b->first;

if (lenA > lenB) {
return 1;
} else if (lenA < lenB) {
return -1;
return a->first == b->first;
}

diff = URI_STRNCMP(a->first, b->first, (size_t)lenA);
const size_t lenA = a->afterLast - a->first;
const size_t lenB = b->afterLast - b->first;

if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
if (lenA != lenB) {
return false;
}

return diff;
return URI_STRNCMP(a->first, b->first, lenA) == 0;
}

UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
const URI_TYPE(TextRange) * sourceRange,
UriMemoryManager * memory) {
const int lenInChars = (int)(sourceRange->afterLast - sourceRange->first);
const int lenInBytes = lenInChars * sizeof(URI_CHAR);
const size_t lenInChars = sourceRange->afterLast - sourceRange->first;
if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) { // detect integer overflow
return URI_FALSE;
}
const size_t lenInBytes = lenInChars * sizeof(URI_CHAR);
URI_CHAR * dup = memory->malloc(memory, lenInBytes);
if (dup == NULL) {
return URI_FALSE;
Expand Down Expand Up @@ -183,7 +173,7 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative,
walker->reserved = NULL; /* Prev pointer */
do {
UriBool removeSegment = URI_FALSE;
int len = (int)(walker->text.afterLast - walker->text.first);
const size_t len = walker->text.afterLast - walker->text.first;
switch (len) {
case 1:
if ((walker->text.first)[0] == _UT('.')) {
Expand Down
4 changes: 3 additions & 1 deletion ext/uri/uriparser/src/UriCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@
# include <uriparser/UriDefsUnicode.h>
# endif

# include <stdbool.h>

/* Used to point to from empty path segments.
* X.first and X.afterLast must be the same non-NULL value then. */
extern const URI_CHAR * const URI_FUNC(SafeToPointTo);
Expand All @@ -77,7 +79,7 @@ void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri);

int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory);

int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b);
bool URI_FUNC(RangeEquals)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b);

UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
const URI_TYPE(TextRange) * sourceRange,
Expand Down
20 changes: 10 additions & 10 deletions ext/uri/uriparser/src/UriCompare.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,17 @@ UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
}

/* scheme */
if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) {
if (!URI_FUNC(RangeEquals)(&(a->scheme), &(b->scheme))) {
return URI_FALSE;
}

/* absolutePath */
if ((a->scheme.first == NULL) && (a->absolutePath != b->absolutePath)) {
/* absolutePath -- not meaningful for URIs with a host set! */
if (!URI_FUNC(HasHost)(a) && (a->absolutePath != b->absolutePath)) {
return URI_FALSE;
}

/* userInfo */
if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) {
if (!URI_FUNC(RangeEquals)(&(a->userInfo), &(b->userInfo))) {
return URI_FALSE;
}

Expand All @@ -107,20 +107,20 @@ UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
}

if (a->hostData.ipFuture.first != NULL) {
if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) {
if (!URI_FUNC(RangeEquals)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) {
return URI_FALSE;
}
}

if ((a->hostData.ip4 == NULL) && (a->hostData.ip6 == NULL)
&& (a->hostData.ipFuture.first == NULL)) {
if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) {
if (!URI_FUNC(RangeEquals)(&(a->hostText), &(b->hostText))) {
return URI_FALSE;
}
}

/* portText */
if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) {
if (!URI_FUNC(RangeEquals)(&(a->portText), &(b->portText))) {
return URI_FALSE;
}

Expand All @@ -133,7 +133,7 @@ UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
URI_TYPE(PathSegment) * walkA = a->pathHead;
URI_TYPE(PathSegment) * walkB = b->pathHead;
do {
if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) {
if (!URI_FUNC(RangeEquals)(&(walkA->text), &(walkB->text))) {
return URI_FALSE;
}
if ((walkA->next == NULL) != (walkB->next == NULL)) {
Expand All @@ -145,12 +145,12 @@ UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
}

/* query */
if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) {
if (!URI_FUNC(RangeEquals)(&(a->query), &(b->query))) {
return URI_FALSE;
}

/* fragment */
if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) {
if (!URI_FUNC(RangeEquals)(&(a->fragment), &(b->fragment))) {
return URI_FALSE;
}

Expand Down
6 changes: 6 additions & 0 deletions ext/uri/uriparser/src/UriCopy.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri
if (URI_FUNC(CopyRangeAsNeeded)(&destWalker->text, &sourceWalker->text,
memory)
== URI_FALSE) {
// Unless wired to `destUri` above, `destWalker` may be hanging
// in the air now
if (destUri->pathHead != destWalker) {
memory->free(memory, destWalker);
}

URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
return URI_ERROR_MALLOC;
}
Expand Down
16 changes: 14 additions & 2 deletions ext/uri/uriparser/src/UriFile.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@
# include <uriparser/Uri.h>
# endif

# include <stdlib.h> /* for size_t, avoiding stddef.h for older MSVCs */
# include <stddef.h> // size_t
# include <stdint.h> // SIZE_MAX

static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename,
URI_CHAR * uriString,
Expand All @@ -90,6 +91,11 @@ static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename,
: _UT("file:///");
const size_t prefixLen = URI_STRLEN(prefix);

// Detect and avoid integer overflow
if (prefixLen > SIZE_MAX / sizeof(URI_CHAR)) {
return URI_ERROR_OUTPUT_TOO_LARGE;
}

/* Copy prefix */
memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR));
output += prefixLen;
Expand All @@ -103,7 +109,13 @@ static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename,
if (lastSep + 1 < input) {
if (!fromUnix && absolute && (firstSegment == URI_TRUE)) {
/* Quick hack to not convert "C:" to "C%3A" */
const int charsToCopy = (int)(input - (lastSep + 1));
const size_t charsToCopy = input - (lastSep + 1);

// Detect and avoid integer overflow
if (charsToCopy > SIZE_MAX / sizeof(URI_CHAR)) {
return URI_ERROR_OUTPUT_TOO_LARGE;
}

memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR));
output += charsToCopy;
} else {
Expand Down
23 changes: 14 additions & 9 deletions ext/uri/uriparser/src/UriNormalize.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
# endif

# include <assert.h>
# include <stdint.h> // SIZE_MAX

static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask,
unsigned int * outMask,
Expand Down Expand Up @@ -254,20 +255,22 @@ URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first,
static URI_INLINE UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
const URI_CHAR ** afterLast,
UriMemoryManager * memory) {
int lenInChars;
const int lowerUpperDiff = (_UT('a') - _UT('A'));
URI_CHAR * buffer;
int i = 0;
size_t i = 0;

if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
|| (*afterLast == NULL)) {
return URI_FALSE;
}

lenInChars = (int)(*afterLast - *first);
const size_t lenInChars = *afterLast - *first;
if (lenInChars == 0) {
return URI_TRUE;
} else if (lenInChars < 0) {
}

// Detect and avoid integer overflow
if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) {
return URI_FALSE;
}

Expand Down Expand Up @@ -295,8 +298,8 @@ URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst, const URI_CHAR * in
const URI_CHAR * outFirst,
const URI_CHAR ** outAfterLast) {
URI_CHAR * write = (URI_CHAR *)outFirst;
const int lenInChars = (int)(inAfterLast - inFirst);
int i = 0;
const size_t lenInChars = inAfterLast - inFirst;
size_t i = 0;

/* All but last two */
for (; i + 2 < lenInChars; i++) {
Expand Down Expand Up @@ -350,7 +353,6 @@ static URI_INLINE void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * firs
static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
const URI_CHAR ** afterLast,
UriMemoryManager * memory) {
int lenInChars;
URI_CHAR * buffer;

/* Death checks */
Expand All @@ -360,10 +362,13 @@ static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** f
}

/* Old text length */
lenInChars = (int)(*afterLast - *first);
const size_t lenInChars = *afterLast - *first;
if (lenInChars == 0) {
return URI_TRUE;
} else if (lenInChars < 0) {
}

// Detect and avoid integer overflow
if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) {
return URI_FALSE;
}

Expand Down
29 changes: 26 additions & 3 deletions ext/uri/uriparser/src/UriQuery.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@

# include <limits.h>
# include <stddef.h> /* size_t */
# include <stdint.h> // SIZE_MAX

static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
const URI_TYPE(QueryList) * queryList,
Expand Down Expand Up @@ -254,7 +255,14 @@ int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, const URI_TYPE(QueryList) * qu
if (dest != NULL) {
write[0] = _UT('\0');
if (charsWritten != NULL) {
*charsWritten = (int)(write - dest) + 1; /* .. for terminator */
const size_t lenInChars = write - dest;

// Detect and avoid integer overflow
if (lenInChars > INT_MAX - 1) {
return URI_ERROR_OUTPUT_TOO_LARGE;
}

*charsWritten = (int)(lenInChars + 1); /* .. for terminator */
}
}

Expand All @@ -267,8 +275,8 @@ UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) * *prevNext, int * itemCou
const URI_CHAR * valueAfter, UriBool plusToSpace,
UriBreakConversion breakConversion,
UriMemoryManager * memory) {
const int keyLen = (int)(keyAfter - keyFirst);
const int valueLen = (int)(valueAfter - valueFirst);
const size_t keyLen = keyAfter - keyFirst;
const size_t valueLen = valueAfter - valueFirst;
URI_CHAR * key;
URI_CHAR * value;

Expand All @@ -285,6 +293,13 @@ UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) * *prevNext, int * itemCou
}
(*prevNext)->next = NULL;

// Detect integer overflow
if ((keyLen > SIZE_MAX - 1) || (keyLen + 1 > SIZE_MAX / sizeof(URI_CHAR))) {
memory->free(memory, *prevNext);
*prevNext = NULL;
return URI_FALSE; // Raises malloc error
}

/* Fill key */
key = memory->malloc(memory, (keyLen + 1) * sizeof(URI_CHAR));
if (key == NULL) {
Expand All @@ -305,6 +320,14 @@ UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) * *prevNext, int * itemCou

/* Fill value */
if (valueFirst != NULL) {
// Detect integer overflow
if ((valueLen > SIZE_MAX - 1) || (valueLen + 1 > SIZE_MAX / sizeof(URI_CHAR))) {
memory->free(memory, key);
memory->free(memory, *prevNext);
*prevNext = NULL;
return URI_FALSE; // Raises malloc error
}

value = memory->malloc(memory, (valueLen + 1) * sizeof(URI_CHAR));
if (value == NULL) {
memory->free(memory, key);
Expand Down
Loading
Loading