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 | |
| 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 '')
| -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 | } |
