aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-06-14 14:38:07 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2023-06-14 14:38:07 -0300
commitf623b969325be736297bc1dff48e763c08778243 (patch)
tree2ada29703862532b09b7465c9fc7ee2bc09e45eb
parent9be74ccc214eb6f4d9d0b9496fd973542c7377d9 (diff)
downloadlua-f623b969325be736297bc1dff48e763c08778243.tar.gz
lua-f623b969325be736297bc1dff48e763c08778243.tar.bz2
lua-f623b969325be736297bc1dff48e763c08778243.zip
Bug: read overflow in 'l_strcmp'
Equality according to 'strcoll' does not imply that strings have the same length.
-rw-r--r--lvm.c38
1 files changed, 20 insertions, 18 deletions
diff --git a/lvm.c b/lvm.c
index 4c300a87..2b437bdf 100644
--- a/lvm.c
+++ b/lvm.c
@@ -366,30 +366,32 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
366 366
367 367
368/* 368/*
369** Compare two strings 'ls' x 'rs', returning an integer less-equal- 369** Compare two strings 'ts1' x 'ts2', returning an integer less-equal-
370** -greater than zero if 'ls' is less-equal-greater than 'rs'. 370** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
371** The code is a little tricky because it allows '\0' in the strings 371** The code is a little tricky because it allows '\0' in the strings
372** and it uses 'strcoll' (to respect locales) for each segments 372** and it uses 'strcoll' (to respect locales) for each segment
373** of the strings. 373** of the strings. Note that segments can compare equal but still
374** have different lengths.
374*/ 375*/
375static int l_strcmp (const TString *ls, const TString *rs) { 376static int l_strcmp (const TString *ts1, const TString *ts2) {
376 const char *l = getstr(ls); 377 const char *s1 = getstr(ts1);
377 size_t ll = tsslen(ls); 378 size_t rl1 = tsslen(ts1); /* real length */
378 const char *r = getstr(rs); 379 const char *s2 = getstr(ts2);
379 size_t lr = tsslen(rs); 380 size_t rl2 = tsslen(ts2);
380 for (;;) { /* for each segment */ 381 for (;;) { /* for each segment */
381 int temp = strcoll(l, r); 382 int temp = strcoll(s1, s2);
382 if (temp != 0) /* not equal? */ 383 if (temp != 0) /* not equal? */
383 return temp; /* done */ 384 return temp; /* done */
384 else { /* strings are equal up to a '\0' */ 385 else { /* strings are equal up to a '\0' */
385 size_t len = strlen(l); /* index of first '\0' in both strings */ 386 size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */
386 if (len == lr) /* 'rs' is finished? */ 387 size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */
387 return (len == ll) ? 0 : 1; /* check 'ls' */ 388 if (zl2 == rl2) /* 's2' is finished? */
388 else if (len == ll) /* 'ls' is finished? */ 389 return (zl1 == rl1) ? 0 : 1; /* check 's1' */
389 return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ 390 else if (zl1 == rl1) /* 's1' is finished? */
390 /* both strings longer than 'len'; go on comparing after the '\0' */ 391 return -1; /* 's1' is less than 's2' ('s2' is not finished) */
391 len++; 392 /* both strings longer than 'zl'; go on comparing after the '\0' */
392 l += len; ll -= len; r += len; lr -= len; 393 zl1++; zl2++;
394 s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2;
393 } 395 }
394 } 396 }
395} 397}