diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-06-14 14:38:07 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2023-06-14 14:38:07 -0300 |
commit | f623b969325be736297bc1dff48e763c08778243 (patch) | |
tree | 2ada29703862532b09b7465c9fc7ee2bc09e45eb /lvm.c | |
parent | 9be74ccc214eb6f4d9d0b9496fd973542c7377d9 (diff) | |
download | lua-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.
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 38 |
1 files changed, 20 insertions, 18 deletions
@@ -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 | */ |
375 | static int l_strcmp (const TString *ls, const TString *rs) { | 376 | static 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 | } |