Skip to content

Commit dc4232e

Browse files
committed
Fixed heap-buffer-overflow in String.prototype.lastIndexOf().
Previously, the issue occurred when the searchValue is shorter in character length than "this" string, but longer in byte length.
1 parent 72ff5c2 commit dc4232e

File tree

2 files changed

+73
-69
lines changed

2 files changed

+73
-69
lines changed

src/njs_string.c

Lines changed: 48 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -2230,114 +2230,94 @@ njs_string_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args,
22302230
njs_uint_t nargs, njs_index_t unused)
22312231
{
22322232
double pos;
2233-
ssize_t index, start, length, search_length;
2233+
int64_t index, start, length, search_length;
22342234
njs_int_t ret;
2235-
njs_value_t *value, *search_string, lvalue;
2235+
njs_value_t *this, *search, search_lvalue;
22362236
const u_char *p, *end;
2237-
njs_string_prop_t string, search;
2238-
2239-
ret = njs_string_object_validate(vm, njs_arg(args, nargs, 0));
2240-
if (njs_slow_path(ret != NJS_OK)) {
2241-
return ret;
2242-
}
2243-
2244-
index = -1;
2237+
njs_string_prop_t string, s;
22452238

2246-
length = njs_string_prop(&string, njs_argument(args, 0));
2239+
this = njs_argument(args, 0);
22472240

2248-
search_string = njs_lvalue_arg(&lvalue, args, nargs, 1);
2241+
if (njs_slow_path(njs_is_null_or_undefined(this))) {
2242+
njs_type_error(vm, "cannot convert \"%s\"to object",
2243+
njs_type_string(this->type));
2244+
return NJS_ERROR;
2245+
}
22492246

2250-
if (njs_slow_path(!njs_is_string(search_string))) {
2251-
ret = njs_value_to_string(vm, search_string, search_string);
2252-
if (njs_slow_path(ret != NJS_OK)) {
2253-
return ret;
2254-
}
2247+
ret = njs_value_to_string(vm, this, this);
2248+
if (njs_slow_path(ret != NJS_OK)) {
2249+
return NJS_ERROR;
22552250
}
22562251

2257-
search_length = njs_string_prop(&search, search_string);
2252+
search = njs_lvalue_arg(&search_lvalue, args, nargs, 1);
2253+
ret = njs_value_to_string(vm, search, search);
2254+
if (njs_slow_path(ret != NJS_OK)) {
2255+
return ret;
2256+
}
22582257

2259-
if (length < search_length) {
2260-
goto done;
2258+
ret = njs_value_to_number(vm, njs_arg(args, nargs, 2), &pos);
2259+
if (njs_slow_path(ret != NJS_OK)) {
2260+
return ret;
22612261
}
22622262

2263-
value = njs_arg(args, nargs, 2);
2264-
2265-
if (njs_slow_path(!njs_is_number(value))) {
2266-
ret = njs_value_to_number(vm, value, &pos);
2267-
if (njs_slow_path(ret != NJS_OK)) {
2268-
return ret;
2269-
}
2263+
if (!isnan(pos)) {
2264+
start = njs_number_to_integer(pos);
22702265

22712266
} else {
2272-
pos = njs_number(value);
2267+
start = INT64_MAX;
22732268
}
22742269

2275-
if (isnan(pos)) {
2276-
index = NJS_STRING_MAX_LENGTH;
2270+
length = njs_string_prop(&string, this);
22772271

2278-
} else {
2279-
index = njs_number_to_integer(pos);
2272+
start = njs_min(njs_max(start, 0), length);
22802273

2281-
if (index < 0) {
2282-
index = 0;
2283-
}
2284-
}
2274+
search_length = njs_string_prop(&s, search);
22852275

2286-
if (search_length == 0) {
2287-
index = njs_min(index, length);
2288-
goto done;
2289-
}
2276+
index = length - search_length;
22902277

2291-
if (index >= length) {
2292-
index = length - 1;
2278+
if (index > start) {
2279+
index = start;
22932280
}
22942281

2282+
end = string.start + string.size;
2283+
22952284
if (string.size == (size_t) length) {
22962285
/* Byte or ASCII string. */
22972286

2298-
start = length - search.size;
2287+
p = &string.start[index];
22992288

2300-
if (index > start) {
2301-
index = start;
2289+
if (p > end - s.size) {
2290+
p = end - s.size;
23022291
}
23032292

2304-
p = string.start + index;
2305-
2306-
do {
2307-
if (memcmp(p, search.start, search.size) == 0) {
2293+
for (; p >= string.start; p--) {
2294+
if (memcmp(p, s.start, s.size) == 0) {
2295+
index = p - string.start;
23082296
goto done;
23092297
}
2298+
}
23102299

2311-
index--;
2312-
p--;
2313-
2314-
} while (p >= string.start);
2300+
index = -1;
23152301

23162302
} else {
23172303
/* UTF-8 string. */
23182304

2319-
end = string.start + string.size;
2320-
p = njs_string_offset(string.start, end, index);
2321-
end -= search.size;
2322-
2323-
while (p > end) {
2324-
index--;
2325-
p = njs_utf8_prev(p);
2305+
if (index < 0 || index == length) {
2306+
index = (search_length == 0) ? index : -1;
2307+
goto done;
23262308
}
23272309

2328-
for ( ;; ) {
2329-
if (memcmp(p, search.start, search.size) == 0) {
2310+
p = njs_string_offset(string.start, end, index);
2311+
2312+
for (; p >= string.start; p = njs_utf8_prev(p)) {
2313+
if ((p + s.size) <= end && memcmp(p, s.start, s.size) == 0) {
23302314
goto done;
23312315
}
23322316

23332317
index--;
2334-
2335-
if (p <= string.start) {
2336-
break;
2337-
}
2338-
2339-
p = njs_utf8_prev(p);
23402318
}
2319+
2320+
index = -1;
23412321
}
23422322

23432323
done:

src/test/njs_unit_test.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8008,7 +8008,28 @@ static njs_unit_test_t njs_test[] =
80088008
{ njs_str("'a a'.toUTF8().indexOf('a', 1)"),
80098009
njs_str("2") },
80108010

8011-
{ njs_str("'abc'.lastIndexOf('abcdef')"),
8011+
{ njs_str("'aaa'.lastIndexOf()"),
8012+
njs_str("-1") },
8013+
8014+
{ njs_str("'aaa'.lastIndexOf('')"),
8015+
njs_str("3") },
8016+
8017+
{ njs_str("'aaa'.lastIndexOf('a')"),
8018+
njs_str("2") },
8019+
8020+
{ njs_str("'aaa'.lastIndexOf('aa')"),
8021+
njs_str("1") },
8022+
8023+
{ njs_str("'aaa'.lastIndexOf('aaa')"),
8024+
njs_str("0") },
8025+
8026+
{ njs_str("'aaa'.lastIndexOf('aaaa')"),
8027+
njs_str("-1") },
8028+
8029+
{ njs_str("'a'.repeat(16).lastIndexOf(String.fromCodePoint(65533).repeat(15))"),
8030+
njs_str("-1") },
8031+
8032+
{ njs_str("('α'+'a'.repeat(15)).lastIndexOf(String.fromCodePoint(65533).repeat(15))"),
80128033
njs_str("-1") },
80138034

80148035
{ njs_str("'abc abc abc abc'.lastIndexOf('abc')"),
@@ -8077,6 +8098,9 @@ static njs_unit_test_t njs_test[] =
80778098
{ njs_str("'β'.repeat(32).lastIndexOf('β')"),
80788099
njs_str("31") },
80798100

8101+
{ njs_str("'β'.repeat(32).lastIndexOf('β'.repeat(32))"),
8102+
njs_str("0") },
8103+
80808104
{ njs_str("'β'.repeat(32).lastIndexOf``"),
80818105
njs_str("32") },
80828106

0 commit comments

Comments
 (0)