]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
lib/fuzzing: add fuzz_strncasecmp_ldb
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>
Sun, 12 May 2024 22:39:44 +0000 (10:39 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 22 May 2024 23:12:32 +0000 (23:12 +0000)
As well as checking for the usual overflows, this asserts that
strncasecmp_ldb is always transitive, by splitting the input into 3
pieces and comparing all pairs.

Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
lib/fuzzing/fuzz_strncasecmp_ldb.c [new file with mode: 0644]
lib/fuzzing/wscript_build

diff --git a/lib/fuzzing/fuzz_strncasecmp_ldb.c b/lib/fuzzing/fuzz_strncasecmp_ldb.c
new file mode 100644 (file)
index 0000000..0f785b5
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+   Fuzzing ldb_comparison_fold()
+   Copyright (C) Catalyst IT 2020
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "includes.h"
+#include "fuzzing/fuzzing.h"
+#include "charset.h"
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+       return 0;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
+{
+       struct ldb_val v[3] = {{},{},{}};
+       size_t i, j, k;
+       int results[9], ab, ac, bc;
+
+       if (len < 3) {
+               return 0;
+       }
+
+       j = 0;
+       k = 0;
+       v[j].data = discard_const(input);
+
+       /*
+        * We split the input into 3 ldb_vals, on the byte '*' (42), chosen
+        * because it is *not* special with regard to termination, utf-8, or
+        * casefolding.
+        *
+        * if there are not 2 '*' bytes, the last value[s] will be empty, with
+        * a NULL pointer and zero length.
+        */
+
+       for (i = 0; i < len; i++) {
+               if (input[i] != '*') {
+                       continue;
+               }
+               v[j].length = i - k;
+               i++;
+               j++;
+               if (j > 2 || i == len) {
+                       break;
+               }
+               k = i;
+               v[j].data = discard_const(input + k);
+       }
+
+       for (i = 0; i < 3; i++) {
+               char *s1 = (char*)v[i].data;
+               size_t len1 = v[i].length;
+               for (j = 0; j < 3; j++) {
+                       char *s2 = (char*)v[j].data;
+                       size_t len2 = v[j].length;
+                       int r = strncasecmp_ldb(s1, len1, s2, len2);
+                       if (abs(r) > 1) {
+                               abort();
+                       }
+                       results[i * 3 + j] = r;
+               }
+       }
+
+       /*
+        * There are nine comparisons we make.
+        *
+        *    A B C
+        *  A = x x
+        *  B - = x
+        *  C - - =
+        *
+        * The diagonal should be all zeros (A == A, etc)
+        * The upper and lower triangles should complement each other
+        * (A > B implies B < A; A == B implies B == A).
+        *
+        * So we check for those identities first.
+        */
+
+       if ((results[0] != 0) ||
+           (results[4] != 0) ||
+           (results[8] != 0)) {
+               abort();
+       }
+
+       ab = results[3];
+       ac = results[6];
+       bc = results[7];
+
+       if (ab != -results[1] ||
+           ac != -results[2] ||
+           bc != -results[5]) {
+               abort();
+       }
+
+        /*
+        * Then there are 27 states within the three comparisons of one
+        * triangle, because each of AB, AC, and BC can be in 3 states.
+        *
+        *  0    (A < B) (A < C) (B < C)   A < B < C
+        *  1    (A < B) (A < C) (B = C)   A < (B|C)
+        *  2    (A < B) (A < C) (B > C)   A < C < B
+        *  3    (A < B) (A = C) (B < C)    invalid
+        *  4    (A < B) (A = C) (B = C)    invalid
+        *  5    (A < B) (A = C) (B > C)   (A|C) < B
+        *  6    (A < B) (A > C) (B < C)    invalid
+        *  7    (A < B) (A > C) (B = C)    invalid
+        *  8    (A < B) (A > C) (B > C)   C < A < B
+        *  9    (A = B) (A < C) (B < C)   (A|B) < C
+        * 10    (A = B) (A < C) (B = C)    invalid
+        * 11    (A = B) (A < C) (B > C)    invalid
+        * 12    (A = B) (A = C) (B < C)    invalid
+        * 13    (A = B) (A = C) (B = C)   A = B = C
+        * 14    (A = B) (A = C) (B > C)    invalid
+        * 15    (A = B) (A > C) (B < C)    invalid
+        * 16    (A = B) (A > C) (B = C)    invalid
+        * 17    (A = B) (A > C) (B > C)   C < (A|B)
+        * 18    (A > B) (A < C) (B < C)   B < C < A
+        * 19    (A > B) (A < C) (B = C)    invalid
+        * 20    (A > B) (A < C) (B > C)    invalid
+        * 21    (A > B) (A = C) (B < C)   B < (A|C)
+        * 22    (A > B) (A = C) (B = C)    invalid
+        * 23    (A > B) (A = C) (B > C)    invalid
+        * 24    (A > B) (A > C) (B < C)   B < C < A
+        * 25    (A > B) (A > C) (B = C)   (B|C) < A
+        * 26    (A > B) (A > C) (B > C)   C < B < A
+        *
+        * It actually turns out to be quite simple:
+        */
+
+       if (ab == 0) {
+               if (ac != bc) {
+                       abort();
+               }
+       } else if (ab < 0) {
+               if (ac >= 0 && bc <= 0) {
+                       abort();
+               }
+       } else {
+               if (ac <= 0 && bc >= 0) {
+                       abort();
+               }
+       }
+
+       return 0;
+}
index 897a114ca7e91701e576f5a3bac3e12ae460937f..ce2684580ce6e200cb0e167eb33b3a9b8fa6a0b8 100644 (file)
@@ -169,6 +169,11 @@ bld.SAMBA_BINARY('fuzz_security_token_vs_descriptor_ds',
                  deps='fuzzing samba-security afl-fuzz-main',
                  fuzzer=True)
 
+bld.SAMBA_BINARY('fuzz_strncasecmp_ldb',
+                 source='fuzz_strncasecmp_ldb.c',
+                 deps='fuzzing samba-util afl-fuzz-main',
+                 fuzzer=True)
+
 
 # The fuzz_type and fuzz_function parameters make the built
 # fuzzer take the same input as ndrdump and so the same that