You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
67 lines
2.7 KiB
67 lines
2.7 KiB
2 months ago
|
From f623b969325be736297bc1dff48e763c08778243 Mon Sep 17 00:00:00 2001
|
||
|
From: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
|
||
|
Date: Wed, 14 Jun 2023 14:38:07 -0300
|
||
|
Subject: [PATCH] Bug: read overflow in 'l_strcmp'
|
||
|
|
||
|
Equality according to 'strcoll' does not imply that strings have
|
||
|
the same length.
|
||
|
---
|
||
|
lvm.c | 38 ++++++++++++++++++++------------------
|
||
|
1 file changed, 20 insertions(+), 18 deletions(-)
|
||
|
|
||
|
diff --git a/src/lvm.c b/src/lvm.c
|
||
|
index 4c300a87a..2b437bdfd 100644
|
||
|
--- a/src/lvm.c
|
||
|
+++ b/src/lvm.c
|
||
|
@@ -366,30 +366,32 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
|
||
|
|
||
|
|
||
|
/*
|
||
|
-** Compare two strings 'ls' x 'rs', returning an integer less-equal-
|
||
|
-** -greater than zero if 'ls' is less-equal-greater than 'rs'.
|
||
|
+** Compare two strings 'ts1' x 'ts2', returning an integer less-equal-
|
||
|
+** -greater than zero if 'ts1' is less-equal-greater than 'ts2'.
|
||
|
** The code is a little tricky because it allows '\0' in the strings
|
||
|
-** and it uses 'strcoll' (to respect locales) for each segments
|
||
|
-** of the strings.
|
||
|
+** and it uses 'strcoll' (to respect locales) for each segment
|
||
|
+** of the strings. Note that segments can compare equal but still
|
||
|
+** have different lengths.
|
||
|
*/
|
||
|
-static int l_strcmp (const TString *ls, const TString *rs) {
|
||
|
- const char *l = getstr(ls);
|
||
|
- size_t ll = tsslen(ls);
|
||
|
- const char *r = getstr(rs);
|
||
|
- size_t lr = tsslen(rs);
|
||
|
+static int l_strcmp (const TString *ts1, const TString *ts2) {
|
||
|
+ const char *s1 = getstr(ts1);
|
||
|
+ size_t rl1 = tsslen(ts1); /* real length */
|
||
|
+ const char *s2 = getstr(ts2);
|
||
|
+ size_t rl2 = tsslen(ts2);
|
||
|
for (;;) { /* for each segment */
|
||
|
- int temp = strcoll(l, r);
|
||
|
+ int temp = strcoll(s1, s2);
|
||
|
if (temp != 0) /* not equal? */
|
||
|
return temp; /* done */
|
||
|
else { /* strings are equal up to a '\0' */
|
||
|
- size_t len = strlen(l); /* index of first '\0' in both strings */
|
||
|
- if (len == lr) /* 'rs' is finished? */
|
||
|
- return (len == ll) ? 0 : 1; /* check 'ls' */
|
||
|
- else if (len == ll) /* 'ls' is finished? */
|
||
|
- return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */
|
||
|
- /* both strings longer than 'len'; go on comparing after the '\0' */
|
||
|
- len++;
|
||
|
- l += len; ll -= len; r += len; lr -= len;
|
||
|
+ size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */
|
||
|
+ size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */
|
||
|
+ if (zl2 == rl2) /* 's2' is finished? */
|
||
|
+ return (zl1 == rl1) ? 0 : 1; /* check 's1' */
|
||
|
+ else if (zl1 == rl1) /* 's1' is finished? */
|
||
|
+ return -1; /* 's1' is less than 's2' ('s2' is not finished) */
|
||
|
+ /* both strings longer than 'zl'; go on comparing after the '\0' */
|
||
|
+ zl1++; zl2++;
|
||
|
+ s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2;
|
||
|
}
|
||
|
}
|
||
|
}
|