]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
stack: fix searching when the stack isn't sorted.
authorPauli <pauli@openssl.org>
Thu, 20 Apr 2023 06:04:10 +0000 (16:04 +1000)
committerTomas Mraz <tomas@openssl.org>
Fri, 28 Apr 2023 07:24:06 +0000 (09:24 +0200)
More specifically, don't sort the stack when searching when it isn't sorted.
This avoids a race condition.

Fixes #20135

Reviewed-by: Tim Hudson <tjh@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20782)

crypto/stack/stack.c

index 601664ebe3db74a1cd2538866f614ae0f9a460c9..1e7f30072300902dda49e00a8d139294ad05e5a2 100644 (file)
@@ -315,39 +315,54 @@ void *OPENSSL_sk_delete(OPENSSL_STACK *st, int loc)
 }
 
 static int internal_find(OPENSSL_STACK *st, const void *data,
-                         int ret_val_options, int *pnum)
+                         int ret_val_options, int *pnum_matched)
 {
     const void *r;
-    int i;
+    int i, count = 0;
+    int *pnum = pnum_matched;
 
     if (st == NULL || st->num == 0)
         return -1;
 
+    if (pnum == NULL)
+        pnum = &count;
+
     if (st->comp == NULL) {
         for (i = 0; i < st->num; i++)
             if (st->data[i] == data) {
-                if (pnum != NULL)
-                    *pnum = 1;
+                *pnum = 1;
                 return i;
             }
-        if (pnum != NULL)
-            *pnum = 0;
+        *pnum = 0;
         return -1;
     }
 
-    if (!st->sorted) {
-        if (st->num > 1)
-            qsort(st->data, st->num, sizeof(void *), st->comp);
-        st->sorted = 1; /* empty or single-element stack is considered sorted */
-    }
     if (data == NULL)
         return -1;
-    if (pnum != NULL)
+
+    if (!st->sorted) {
+        int res = -1;
+
+        for (i = 0; i < st->num; i++)
+            if (st->comp(&data, st->data + i) == 0) {
+                if (res == -1)
+                    res = i;
+                ++*pnum;
+                /* Check if only one result is wanted and exit if so */
+                if (pnum_matched == NULL)
+                    return i;
+            }
+        if (res == -1)
+            *pnum = 0;
+        return res;
+    }
+
+    if (pnum_matched != NULL)
         ret_val_options |= OSSL_BSEARCH_FIRST_VALUE_ON_MATCH;
     r = ossl_bsearch(&data, st->data, st->num, sizeof(void *), st->comp,
                      ret_val_options);
 
-    if (pnum != NULL) {
+    if (pnum_matched != NULL) {
         *pnum = 0;
         if (r != NULL) {
             const void **p = (const void **)r;