Skip to content

Commit bb73942

Browse files
authored
uri: Update to uriparser-1.0.2 (#22070)
This fixes CVE-2026-44927 and CVE-2026-44928.
1 parent ea8487d commit bb73942

13 files changed

Lines changed: 257 additions & 86 deletions

File tree

NEWS

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@ PHP NEWS
2323
. Fixed bug GH-21689 (version_compare() incorrectly handles versions ending
2424
with a dot). (timwolla)
2525

26+
- URI:
27+
. Fixed CVE-2026-44927 (In uriparser before 1.0.2, there is pointer
28+
difference truncation to int in various places). (CVE-2026-44927)
29+
(Sebastian Pipping)
30+
. Fixed CVE-2026-44928 (In uriparser before 1.0.2, the function family
31+
EqualsUri can misclassify two unequal URIs as equal). (CVE-2026-44928)
32+
(Sebastian Pipping)
33+
2634
07 May 2026, PHP 8.5.6
2735

2836
- Core:

ext/uri/uriparser/include/uriparser/Uri.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* 53c1cb9f2f728652fe001dc72fa0fa7a0e9fa0b8baaaa9e37561c6cdf88ac4df (1.0.1+)
1+
/* c9d94656d067288e474df19a062d487c736b0fa8517d2ef7bbeb8dcd5a70c05b (1.0.2+)
22
*
33
* uriparser - RFC 3986 URI parsing library
44
*

ext/uri/uriparser/include/uriparser/UriBase.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
/* Version */
5353
# define URI_VER_MAJOR 1
5454
# define URI_VER_MINOR 0
55-
# define URI_VER_RELEASE 1
55+
# define URI_VER_RELEASE 2
5656
# define URI_VER_SUFFIX_ANSI ""
5757
# define URI_VER_SUFFIX_UNICODE URI_ANSI_TO_UNICODE(URI_VER_SUFFIX_ANSI)
5858

ext/uri/uriparser/src/UriCommon.c

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767

6868
# include <assert.h>
6969
# include <stddef.h>
70+
# include <stdint.h> // SIZE_MAX
7071

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

107108
/* Compares two text ranges for equal text content */
108-
int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) {
109-
int diff;
110-
ptrdiff_t lenA;
111-
ptrdiff_t lenB;
112-
109+
bool URI_FUNC(RangeEquals)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) {
113110
/* NOTE: Both NULL means equal! */
114111
if ((a == NULL) || (b == NULL)) {
115-
return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1);
112+
return a == b;
116113
}
117114

118115
/* NOTE: Both NULL means equal! */
119116
if ((a->first == NULL) || (b->first == NULL)) {
120-
return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1);
121-
}
122-
123-
lenA = a->afterLast - a->first;
124-
lenB = b->afterLast - b->first;
125-
126-
if (lenA > lenB) {
127-
return 1;
128-
} else if (lenA < lenB) {
129-
return -1;
117+
return a->first == b->first;
130118
}
131119

132-
diff = URI_STRNCMP(a->first, b->first, (size_t)lenA);
120+
const size_t lenA = a->afterLast - a->first;
121+
const size_t lenB = b->afterLast - b->first;
133122

134-
if (diff > 0) {
135-
return 1;
136-
} else if (diff < 0) {
137-
return -1;
123+
if (lenA != lenB) {
124+
return false;
138125
}
139126

140-
return diff;
127+
return URI_STRNCMP(a->first, b->first, lenA) == 0;
141128
}
142129

143130
UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
144131
const URI_TYPE(TextRange) * sourceRange,
145132
UriMemoryManager * memory) {
146-
const int lenInChars = (int)(sourceRange->afterLast - sourceRange->first);
147-
const int lenInBytes = lenInChars * sizeof(URI_CHAR);
133+
const size_t lenInChars = sourceRange->afterLast - sourceRange->first;
134+
if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) { // detect integer overflow
135+
return URI_FALSE;
136+
}
137+
const size_t lenInBytes = lenInChars * sizeof(URI_CHAR);
148138
URI_CHAR * dup = memory->malloc(memory, lenInBytes);
149139
if (dup == NULL) {
150140
return URI_FALSE;
@@ -183,7 +173,7 @@ UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative,
183173
walker->reserved = NULL; /* Prev pointer */
184174
do {
185175
UriBool removeSegment = URI_FALSE;
186-
int len = (int)(walker->text.afterLast - walker->text.first);
176+
const size_t len = walker->text.afterLast - walker->text.first;
187177
switch (len) {
188178
case 1:
189179
if ((walker->text.first)[0] == _UT('.')) {

ext/uri/uriparser/src/UriCommon.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
# include <uriparser/UriDefsUnicode.h>
6868
# endif
6969

70+
# include <stdbool.h>
71+
7072
/* Used to point to from empty path segments.
7173
* X.first and X.afterLast must be the same non-NULL value then. */
7274
extern const URI_CHAR * const URI_FUNC(SafeToPointTo);
@@ -77,7 +79,7 @@ void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri);
7779

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

80-
int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b);
82+
bool URI_FUNC(RangeEquals)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b);
8183

8284
UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
8385
const URI_TYPE(TextRange) * sourceRange,

ext/uri/uriparser/src/UriCompare.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,17 @@ UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
7272
}
7373

7474
/* scheme */
75-
if (URI_FUNC(CompareRange)(&(a->scheme), &(b->scheme))) {
75+
if (!URI_FUNC(RangeEquals)(&(a->scheme), &(b->scheme))) {
7676
return URI_FALSE;
7777
}
7878

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

8484
/* userInfo */
85-
if (URI_FUNC(CompareRange)(&(a->userInfo), &(b->userInfo))) {
85+
if (!URI_FUNC(RangeEquals)(&(a->userInfo), &(b->userInfo))) {
8686
return URI_FALSE;
8787
}
8888

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

109109
if (a->hostData.ipFuture.first != NULL) {
110-
if (URI_FUNC(CompareRange)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) {
110+
if (!URI_FUNC(RangeEquals)(&(a->hostData.ipFuture), &(b->hostData.ipFuture))) {
111111
return URI_FALSE;
112112
}
113113
}
114114

115115
if ((a->hostData.ip4 == NULL) && (a->hostData.ip6 == NULL)
116116
&& (a->hostData.ipFuture.first == NULL)) {
117-
if (URI_FUNC(CompareRange)(&(a->hostText), &(b->hostText))) {
117+
if (!URI_FUNC(RangeEquals)(&(a->hostText), &(b->hostText))) {
118118
return URI_FALSE;
119119
}
120120
}
121121

122122
/* portText */
123-
if (URI_FUNC(CompareRange)(&(a->portText), &(b->portText))) {
123+
if (!URI_FUNC(RangeEquals)(&(a->portText), &(b->portText))) {
124124
return URI_FALSE;
125125
}
126126

@@ -133,7 +133,7 @@ UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
133133
URI_TYPE(PathSegment) * walkA = a->pathHead;
134134
URI_TYPE(PathSegment) * walkB = b->pathHead;
135135
do {
136-
if (URI_FUNC(CompareRange)(&(walkA->text), &(walkB->text))) {
136+
if (!URI_FUNC(RangeEquals)(&(walkA->text), &(walkB->text))) {
137137
return URI_FALSE;
138138
}
139139
if ((walkA->next == NULL) != (walkB->next == NULL)) {
@@ -145,12 +145,12 @@ UriBool URI_FUNC(EqualsUri)(const URI_TYPE(Uri) * a, const URI_TYPE(Uri) * b) {
145145
}
146146

147147
/* query */
148-
if (URI_FUNC(CompareRange)(&(a->query), &(b->query))) {
148+
if (!URI_FUNC(RangeEquals)(&(a->query), &(b->query))) {
149149
return URI_FALSE;
150150
}
151151

152152
/* fragment */
153-
if (URI_FUNC(CompareRange)(&(a->fragment), &(b->fragment))) {
153+
if (!URI_FUNC(RangeEquals)(&(a->fragment), &(b->fragment))) {
154154
return URI_FALSE;
155155
}
156156

ext/uri/uriparser/src/UriCopy.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ int URI_FUNC(CopyUriMm)(URI_TYPE(Uri) * destUri, const URI_TYPE(Uri) * sourceUri
199199
if (URI_FUNC(CopyRangeAsNeeded)(&destWalker->text, &sourceWalker->text,
200200
memory)
201201
== URI_FALSE) {
202+
// Unless wired to `destUri` above, `destWalker` may be hanging
203+
// in the air now
204+
if (destUri->pathHead != destWalker) {
205+
memory->free(memory, destWalker);
206+
}
207+
202208
URI_FUNC(PreventLeakageAfterCopy)(destUri, revertMask, memory);
203209
return URI_ERROR_MALLOC;
204210
}

ext/uri/uriparser/src/UriFile.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363
# include <uriparser/Uri.h>
6464
# endif
6565

66-
# include <stdlib.h> /* for size_t, avoiding stddef.h for older MSVCs */
66+
# include <stddef.h> // size_t
67+
# include <stdint.h> // SIZE_MAX
6768

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

94+
// Detect and avoid integer overflow
95+
if (prefixLen > SIZE_MAX / sizeof(URI_CHAR)) {
96+
return URI_ERROR_OUTPUT_TOO_LARGE;
97+
}
98+
9399
/* Copy prefix */
94100
memcpy(uriString, prefix, prefixLen * sizeof(URI_CHAR));
95101
output += prefixLen;
@@ -103,7 +109,13 @@ static URI_INLINE int URI_FUNC(FilenameToUriString)(const URI_CHAR * filename,
103109
if (lastSep + 1 < input) {
104110
if (!fromUnix && absolute && (firstSegment == URI_TRUE)) {
105111
/* Quick hack to not convert "C:" to "C%3A" */
106-
const int charsToCopy = (int)(input - (lastSep + 1));
112+
const size_t charsToCopy = input - (lastSep + 1);
113+
114+
// Detect and avoid integer overflow
115+
if (charsToCopy > SIZE_MAX / sizeof(URI_CHAR)) {
116+
return URI_ERROR_OUTPUT_TOO_LARGE;
117+
}
118+
107119
memcpy(output, lastSep + 1, charsToCopy * sizeof(URI_CHAR));
108120
output += charsToCopy;
109121
} else {

ext/uri/uriparser/src/UriNormalize.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
# endif
7474

7575
# include <assert.h>
76+
# include <stdint.h> // SIZE_MAX
7677

7778
static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask,
7879
unsigned int * outMask,
@@ -254,20 +255,22 @@ URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first,
254255
static URI_INLINE UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
255256
const URI_CHAR ** afterLast,
256257
UriMemoryManager * memory) {
257-
int lenInChars;
258258
const int lowerUpperDiff = (_UT('a') - _UT('A'));
259259
URI_CHAR * buffer;
260-
int i = 0;
260+
size_t i = 0;
261261

262262
if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
263263
|| (*afterLast == NULL)) {
264264
return URI_FALSE;
265265
}
266266

267-
lenInChars = (int)(*afterLast - *first);
267+
const size_t lenInChars = *afterLast - *first;
268268
if (lenInChars == 0) {
269269
return URI_TRUE;
270-
} else if (lenInChars < 0) {
270+
}
271+
272+
// Detect and avoid integer overflow
273+
if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) {
271274
return URI_FALSE;
272275
}
273276

@@ -295,8 +298,8 @@ URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst, const URI_CHAR * in
295298
const URI_CHAR * outFirst,
296299
const URI_CHAR ** outAfterLast) {
297300
URI_CHAR * write = (URI_CHAR *)outFirst;
298-
const int lenInChars = (int)(inAfterLast - inFirst);
299-
int i = 0;
301+
const size_t lenInChars = inAfterLast - inFirst;
302+
size_t i = 0;
300303

301304
/* All but last two */
302305
for (; i + 2 < lenInChars; i++) {
@@ -350,7 +353,6 @@ static URI_INLINE void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * firs
350353
static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
351354
const URI_CHAR ** afterLast,
352355
UriMemoryManager * memory) {
353-
int lenInChars;
354356
URI_CHAR * buffer;
355357

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

362364
/* Old text length */
363-
lenInChars = (int)(*afterLast - *first);
365+
const size_t lenInChars = *afterLast - *first;
364366
if (lenInChars == 0) {
365367
return URI_TRUE;
366-
} else if (lenInChars < 0) {
368+
}
369+
370+
// Detect and avoid integer overflow
371+
if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) {
367372
return URI_FALSE;
368373
}
369374

ext/uri/uriparser/src/UriQuery.c

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767

6868
# include <limits.h>
6969
# include <stddef.h> /* size_t */
70+
# include <stdint.h> // SIZE_MAX
7071

7172
static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
7273
const URI_TYPE(QueryList) * queryList,
@@ -254,7 +255,14 @@ int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, const URI_TYPE(QueryList) * qu
254255
if (dest != NULL) {
255256
write[0] = _UT('\0');
256257
if (charsWritten != NULL) {
257-
*charsWritten = (int)(write - dest) + 1; /* .. for terminator */
258+
const size_t lenInChars = write - dest;
259+
260+
// Detect and avoid integer overflow
261+
if (lenInChars > INT_MAX - 1) {
262+
return URI_ERROR_OUTPUT_TOO_LARGE;
263+
}
264+
265+
*charsWritten = (int)(lenInChars + 1); /* .. for terminator */
258266
}
259267
}
260268

@@ -267,8 +275,8 @@ UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) * *prevNext, int * itemCou
267275
const URI_CHAR * valueAfter, UriBool plusToSpace,
268276
UriBreakConversion breakConversion,
269277
UriMemoryManager * memory) {
270-
const int keyLen = (int)(keyAfter - keyFirst);
271-
const int valueLen = (int)(valueAfter - valueFirst);
278+
const size_t keyLen = keyAfter - keyFirst;
279+
const size_t valueLen = valueAfter - valueFirst;
272280
URI_CHAR * key;
273281
URI_CHAR * value;
274282

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

296+
// Detect integer overflow
297+
if ((keyLen > SIZE_MAX - 1) || (keyLen + 1 > SIZE_MAX / sizeof(URI_CHAR))) {
298+
memory->free(memory, *prevNext);
299+
*prevNext = NULL;
300+
return URI_FALSE; // Raises malloc error
301+
}
302+
288303
/* Fill key */
289304
key = memory->malloc(memory, (keyLen + 1) * sizeof(URI_CHAR));
290305
if (key == NULL) {
@@ -305,6 +320,14 @@ UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) * *prevNext, int * itemCou
305320

306321
/* Fill value */
307322
if (valueFirst != NULL) {
323+
// Detect integer overflow
324+
if ((valueLen > SIZE_MAX - 1) || (valueLen + 1 > SIZE_MAX / sizeof(URI_CHAR))) {
325+
memory->free(memory, key);
326+
memory->free(memory, *prevNext);
327+
*prevNext = NULL;
328+
return URI_FALSE; // Raises malloc error
329+
}
330+
308331
value = memory->malloc(memory, (valueLen + 1) * sizeof(URI_CHAR));
309332
if (value == NULL) {
310333
memory->free(memory, key);

0 commit comments

Comments
 (0)