summaryrefslogtreecommitdiffstats
path: root/lib/fuzzing
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/fuzzing/README.md87
-rw-r--r--lib/fuzzing/afl-fuzz-main.c66
-rwxr-xr-xlib/fuzzing/decode_ndr_X_crash137
-rw-r--r--lib/fuzzing/fuzz_cli_credentials_parse_string.c63
-rw-r--r--lib/fuzzing/fuzz_dcerpc_parse_binding.c76
-rw-r--r--lib/fuzzing/fuzz_ldap_decode.c66
-rw-r--r--lib/fuzzing/fuzz_ldb_dn_explode.c53
-rw-r--r--lib/fuzzing/fuzz_ldb_ldif_read.c56
-rw-r--r--lib/fuzzing/fuzz_ldb_parse_binary_decode.c55
-rw-r--r--lib/fuzzing/fuzz_ldb_parse_control.c55
-rw-r--r--lib/fuzzing/fuzz_ldb_parse_tree.c53
-rw-r--r--lib/fuzzing/fuzz_lzxpress.c35
-rw-r--r--lib/fuzzing/fuzz_lzxpress_compress.c35
-rw-r--r--lib/fuzzing/fuzz_lzxpress_round_trip.c53
-rw-r--r--lib/fuzzing/fuzz_ndr_X.c337
-rw-r--r--lib/fuzzing/fuzz_nmblib_parse_packet.c62
-rw-r--r--lib/fuzzing/fuzz_oLschema2ldif.c71
-rw-r--r--lib/fuzzing/fuzz_parse_lpq_entry.c65
-rw-r--r--lib/fuzzing/fuzz_reg_parse.c46
-rw-r--r--lib/fuzzing/fuzz_regfio.c68
-rw-r--r--lib/fuzzing/fuzz_tiniparser.c51
-rw-r--r--lib/fuzzing/fuzzing.c21
-rw-r--r--lib/fuzzing/fuzzing.h30
-rwxr-xr-xlib/fuzzing/oss-fuzz/build_image.sh7
-rwxr-xr-xlib/fuzzing/oss-fuzz/build_samba.sh25
-rwxr-xr-xlib/fuzzing/oss-fuzz/check_build.sh48
-rwxr-xr-xlib/fuzzing/oss-fuzz/do_build.sh294
-rw-r--r--lib/fuzzing/wscript_build197
28 files changed, 2212 insertions, 0 deletions
diff --git a/lib/fuzzing/README.md b/lib/fuzzing/README.md
new file mode 100644
index 0000000..d3e34bd
--- /dev/null
+++ b/lib/fuzzing/README.md
@@ -0,0 +1,87 @@
+# Fuzzing Samba
+
+See also https://wiki.samba.org/index.php/Fuzzing
+
+Fuzzing supplies valid, invalid, unexpected or random data as input to a piece
+of code. Instrumentation, usually compiler-implemented, is used to monitor for
+exceptions such as crashes, assertions or memory corruption.
+
+See [Wikipedia article on fuzzing](https://en.wikipedia.org/wiki/Fuzzing) for
+more information.
+
+# Honggfuzz
+
+## Configure with fuzzing
+
+Example command line to build binaries for use with
+[honggfuzz](https://github.com/google/honggfuzz/):
+
+```sh
+./configure -C --without-gettext --enable-debug --enable-developer \
+ --address-sanitizer --enable-libfuzzer --abi-check-disable \
+ CC=.../honggfuzz/hfuzz_cc/hfuzz-clang \
+ LINK_CC=.../honggfuzz/hfuzz_cc/hfuzz-clang
+```
+
+
+## Fuzzing tiniparser
+
+Example for fuzzing `tiniparser` using `honggfuzz` (see `--help` for more
+options):
+
+```sh
+make bin/fuzz_tiniparser && \
+.../honggfuzz/honggfuzz --sanitizers --timeout 3 --max_file_size 256 \
+ --rlimit_rss 100 -f .../tiniparser-corpus -- bin/fuzz_tiniparser
+```
+
+# AFL (american fuzzy lop)
+
+## Configure with fuzzing
+
+Example command line to build binaries for use with
+[afl](http://lcamtuf.coredump.cx/afl/)
+
+```sh
+./configure -C --without-gettext --enable-debug --enable-developer \
+ --enable-afl-fuzzer --abi-check-disable \
+ CC=afl-gcc
+```
+
+## Fuzzing tiniparser
+
+Example for fuzzing `tiniparser` using `afl-fuzz` (see `--help` for more
+options):
+
+```sh
+make bin/fuzz_tiniparser build && \
+afl-fuzz -m 200 -i inputdir -o outputdir -- bin/fuzz_tiniparser
+```
+
+# oss-fuzz
+
+Samba can be fuzzed by Google's oss-fuzz system. Assuming you have an
+oss-fuzz checkout from https://github.com/google/oss-fuzz with Samba's
+metadata in projects/samba, the following guides will help:
+
+## Testing locally
+
+https://google.github.io/oss-fuzz/getting-started/new-project-guide/#testing-locally
+
+## Debugging oss-fuzz
+
+See https://google.github.io/oss-fuzz/advanced-topics/debugging/
+
+## Samba-specific hints
+
+A typical debugging workflow is:
+
+oss-fuzz$ python infra/helper.py shell samba
+git fetch $REMOTE $BRANCH
+git checkout FETCH_HEAD
+lib/fuzzing/oss-fuzz/build_image.sh
+compile
+
+This will pull in any new Samba deps and build Samba's fuzzers.
+
+# vim: set sw=8 sts=8 ts=8 tw=79 :
diff --git a/lib/fuzzing/afl-fuzz-main.c b/lib/fuzzing/afl-fuzz-main.c
new file mode 100644
index 0000000..e0a1d26
--- /dev/null
+++ b/lib/fuzzing/afl-fuzz-main.c
@@ -0,0 +1,66 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ Fuzz driver (AFL style)
+
+ Copyright (C) Andrew Bartlett 2019
+
+ 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 "lib/util/samba_util.h"
+#include "fuzzing.h"
+
+int main(int argc, char *argv[]) {
+ int ret;
+ size_t size = 0;
+ int i;
+
+ ret = LLVMFuzzerInitialize(&argc, &argv);
+ if (ret != 0) {
+ printf("LLVMFuzzerInitialize returned %d\n", ret);
+ return ret;
+ }
+
+
+#ifdef __AFL_LOOP
+ while (__AFL_LOOP(1000))
+#else
+ for (i = 1; i < argc; i++) {
+ uint8_t *buf = (uint8_t *)file_load(argv[i],
+ &size,
+ 0,
+ NULL);
+ ret = LLVMFuzzerTestOneInput(buf, size);
+ TALLOC_FREE(buf);
+ if (ret != 0) {
+ printf("LLVMFuzzerTestOneInput returned %d on argument %d\n",
+ ret, i);
+ return ret;
+ }
+ }
+ if (i == 1)
+#endif
+ {
+ uint8_t *buf = (uint8_t *)fd_load(0, &size, 0, NULL);
+ if (buf == NULL) {
+ exit(1);
+ }
+
+ ret = LLVMFuzzerTestOneInput(buf, size);
+ TALLOC_FREE(buf);
+ }
+ return ret;
+}
diff --git a/lib/fuzzing/decode_ndr_X_crash b/lib/fuzzing/decode_ndr_X_crash
new file mode 100755
index 0000000..63c3cd7
--- /dev/null
+++ b/lib/fuzzing/decode_ndr_X_crash
@@ -0,0 +1,137 @@
+#!/usr/bin/env python3
+#
+# Interpret a file that crashes an fuzz_ndr_X binary.
+#
+# Copyright (C) Catalyst IT Ltd. 2019
+
+
+import sys
+import os
+from base64 import b64encode
+import struct
+import argparse
+import re
+
+TYPE_MASK = 3
+TYPES = ['struct', 'in', 'out']
+
+FLAGS = [
+ (4, 'ndr64', '--ndr64'),
+]
+
+
+def print_if_verbose(*args, **kwargs):
+ if verbose:
+ print(*args, **kwargs)
+
+
+def process_one_file(f):
+ print_if_verbose(f.name)
+ print_if_verbose('-' * len(f.name))
+
+ b = f.read()
+ flags, function = struct.unpack('<HH', b[:4])
+ if opnum is not None and opnum != function:
+ return
+
+ t = TYPES[flags & TYPE_MASK]
+ if ndr_type and ndr_type != t:
+ return
+
+ payload = b[4:]
+ data64 = b64encode(payload).decode('utf-8')
+
+ cmd = ['bin/ndrdump',
+ pipe,
+ str(function),
+ t,
+ '--base64-input',
+ '--input', data64,
+ ]
+
+ for flag, name, option in FLAGS:
+ if flags & flag:
+ print_if_verbose("flag: %s" % name)
+ cmd.append(option)
+
+ print_if_verbose("length: %d\n" % len(payload))
+ print(' '.join(cmd))
+ print_if_verbose()
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-p', '--pipe', default='$PIPE',
+ help='pipe name (for output command line)')
+ parser.add_argument('-t', '--type', default=None, choices=TYPES,
+ help='restrict to this type')
+ parser.add_argument('-o', '--opnum', default=None, type=int,
+ help='restrict to this function/struct number')
+ parser.add_argument('FILES', nargs='*', default=(),
+ help="read from these files")
+ parser.add_argument('-k', '--ignore-errors', action='store_true',
+ help='do not stop on errors')
+ parser.add_argument('-v', '--verbose', action='store_true',
+ help='say more')
+ parser.add_argument('-H', '--honggfuzz-file',
+ help="extract crashes from this honggfuzz report")
+ parser.add_argument('-f', '--crash-filter',
+ help="only print crashes matching this rexexp")
+
+ args = parser.parse_args()
+
+ global pipe, opnum, ndr_type, verbose
+ pipe = args.pipe
+ opnum = args.opnum
+ ndr_type = args.type
+ verbose = args.verbose
+
+ if not args.FILES and not args.honggfuzz_file:
+ parser.print_usage()
+ sys.exit(1)
+
+ for fn in args.FILES:
+ if args.crash_filter is not None:
+ if not re.search(args.crash_filter, fn):
+ print_if_verbose(f"skipping {fn}")
+ continue
+ try:
+ if fn == '-':
+ process_one_file(sys.stdin)
+ else:
+ with open(fn, 'rb') as f:
+ process_one_file(f)
+ except Exception:
+ print_if_verbose("Error processing %s\n" % fn)
+ if args.ignore_errors:
+ continue
+ raise
+
+ if args.honggfuzz_file:
+ print_if_verbose(f"looking at {args.honggfuzz_file}")
+ with open(args.honggfuzz_file) as f:
+ pipe = None
+ crash = None
+ for line in f:
+ m = re.match(r'^\s*fuzzTarget\s*:\s*bin/fuzz_ndr_(\w+)\s*$', line)
+ if m:
+ pipe = m.group(1).split('_TYPE_', 1)[0]
+ print_if_verbose(f"found pipe {pipe}")
+ m = re.match(r'^FUZZ_FNAME: (\S+)$', line)
+ if m:
+ crash = m.group(1)
+ if args.crash_filter is not None:
+ if not re.search(args.crash_filter, crash):
+ print_if_verbose(f"skipping {crash}")
+ pipe = None
+ crash = None
+ continue
+ print_if_verbose(f"found crash {crash}")
+ if pipe is not None and crash is not None:
+ with open(crash, 'rb') as f:
+ process_one_file(f)
+ pipe = None
+ crash = None
+
+
+main()
diff --git a/lib/fuzzing/fuzz_cli_credentials_parse_string.c b/lib/fuzzing/fuzz_cli_credentials_parse_string.c
new file mode 100644
index 0000000..b71ef35
--- /dev/null
+++ b/lib/fuzzing/fuzz_cli_credentials_parse_string.c
@@ -0,0 +1,63 @@
+/*
+ Fuzz cli_credentials_parse_string
+ 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 "auth/credentials/credentials.h"
+#include "fuzzing/fuzzing.h"
+
+#define MAX_LENGTH (1024 * 10)
+char buf[MAX_LENGTH + 1];
+
+const enum credentials_obtained obtained = CRED_UNINITIALISED;
+
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct cli_credentials *credentials = NULL;
+ bool anon;
+ const char *username;
+ const char *domain;
+
+ if (len > MAX_LENGTH) {
+ return 0;
+ }
+
+ memcpy(buf, input, len);
+ buf[len] = '\0';
+
+ mem_ctx = talloc_new(NULL);
+ credentials = cli_credentials_init(mem_ctx);
+
+ cli_credentials_parse_string(credentials, buf, obtained);
+
+ anon = cli_credentials_is_anonymous(credentials);
+
+ cli_credentials_get_ntlm_username_domain(credentials,
+ mem_ctx,
+ &username,
+ &domain);
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_dcerpc_parse_binding.c b/lib/fuzzing/fuzz_dcerpc_parse_binding.c
new file mode 100644
index 0000000..6eb3c15
--- /dev/null
+++ b/lib/fuzzing/fuzz_dcerpc_parse_binding.c
@@ -0,0 +1,76 @@
+/*
+ Fuzz dcerpc_parse_binding
+ 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 "librpc/gen_ndr/ndr_epmapper.h"
+#include "librpc/rpc/dcerpc.h"
+#include "fuzzing/fuzzing.h"
+
+#define MAX_LENGTH (1024 * 10)
+char buf[MAX_LENGTH + 1];
+
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = NULL;
+ struct dcerpc_binding *binding = NULL;
+ struct dcerpc_binding *dup = NULL;
+ struct epm_tower tower;
+ NTSTATUS status;
+ struct GUID guid;
+
+ if (len > MAX_LENGTH) {
+ return 0;
+ }
+
+ memcpy(buf, input, len);
+ buf[len] = '\0';
+
+ mem_ctx = talloc_new(NULL);
+ status = dcerpc_parse_binding(mem_ctx, buf, &binding);
+
+ if (! NT_STATUS_IS_OK(status)) {
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ /* If the string parses, we try manipulating it a bit */
+
+ dcerpc_binding_string(mem_ctx, binding);
+ dcerpc_binding_get_abstract_syntax(binding);
+ dup = dcerpc_binding_dup(mem_ctx, binding);
+
+ status = dcerpc_binding_build_tower(mem_ctx,
+ binding,
+ &tower);
+ if (NT_STATUS_IS_OK(status)) {
+ status = dcerpc_binding_from_tower(mem_ctx,
+ &tower,
+ &dup);
+ }
+
+ guid = dcerpc_binding_get_object(binding);
+
+ talloc_free(mem_ctx);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldap_decode.c b/lib/fuzzing/fuzz_ldap_decode.c
new file mode 100644
index 0000000..e3bcf7b
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldap_decode.c
@@ -0,0 +1,66 @@
+/*
+ Fuzzing for ldap_decode.
+ Copyright (C) Michael Hanselmann 2019
+
+ 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 "lib/util/asn1.h"
+#include "libcli/ldap/ldap_message.h"
+#include "libcli/ldap/ldap_proto.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
+ struct asn1_data *asn1;
+ struct ldap_message *ldap_msg;
+ struct ldap_request_limits limits = {
+ /*
+ * The default size is currently 256000 bytes
+ */
+ .max_search_size = 256000
+ };
+ NTSTATUS status;
+
+ /*
+ * Need to limit the max parse tree depth to 250 to prevent
+ * ASAN detecting stack overflows.
+ */
+ asn1 = asn1_init(mem_ctx, 250);
+ if (!asn1) {
+ goto out;
+ }
+
+ asn1_load_nocopy(asn1, buf, len);
+
+ ldap_msg = talloc(mem_ctx, struct ldap_message);
+ if (!ldap_msg) {
+ goto out;
+ }
+
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
+
+out:
+ talloc_free(mem_ctx);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_dn_explode.c b/lib/fuzzing/fuzz_ldb_dn_explode.c
new file mode 100644
index 0000000..e024212
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_dn_explode.c
@@ -0,0 +1,53 @@
+/*
+ Fuzzing ldb_dn_explode
+ 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 "ldb.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ struct ldb_dn *dn = NULL;
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ return 0;
+ }
+ /*
+ * We copy the buffer in order to NUL-terminate, because running off
+ * the end of the string would be an uninteresting crash.
+ */
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+
+ dn = ldb_dn_new(ldb, ldb, buf);
+ ldb_dn_validate(dn);
+ TALLOC_FREE(ldb);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_ldif_read.c b/lib/fuzzing/fuzz_ldb_ldif_read.c
new file mode 100644
index 0000000..f44e1ea
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_ldif_read.c
@@ -0,0 +1,56 @@
+/*
+ Fuzzing ldb_ldif_read_string
+ 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 "ldb_private.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ struct ldb_ldif *ldif = NULL;
+ const char *s = NULL;
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ return 0;
+ }
+
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+ s = buf;
+
+ ldif = ldb_ldif_read_string(ldb, &s);
+
+ if(ldif != NULL) {
+ ldb_ldif_write_string(ldb, ldb, ldif);
+ ldb_ldif_write_redacted_trace_string(ldb, ldb, ldif);
+ }
+ TALLOC_FREE(ldb);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_parse_binary_decode.c b/lib/fuzzing/fuzz_ldb_parse_binary_decode.c
new file mode 100644
index 0000000..feb26e2
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_parse_binary_decode.c
@@ -0,0 +1,55 @@
+/*
+ Fuzzing ldb_binary_decode and ldb_binary_encode_string
+ 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 "ldb_private.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+static char * possibly_truncate(uint8_t *input, size_t len)
+{
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+ return buf;
+}
+
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
+ struct ldb_val val = {0};
+ const char *s = possibly_truncate(input, len);
+
+ /* we treat the same string to encoding and decoding, not
+ * round-tripping. */
+ val = ldb_binary_decode(mem_ctx, s);
+ ldb_binary_encode_string(mem_ctx, s);
+ TALLOC_FREE(mem_ctx);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_parse_control.c b/lib/fuzzing/fuzz_ldb_parse_control.c
new file mode 100644
index 0000000..c78222c
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_parse_control.c
@@ -0,0 +1,55 @@
+/*
+ Fuzzing ldb_parse_control_from_string
+ 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 "ldb_private.h"
+
+
+#define MAX_LENGTH (2 * 1024 * 1024 - 1)
+char buf[MAX_LENGTH + 1] = {0};
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ struct ldb_control *control = NULL;
+ struct ldb_context *ldb = ldb_init(NULL, NULL);
+ if (ldb == NULL) {
+ return 0;
+ }
+ /*
+ * We copy the buffer in order to NUL-terminate, because running off
+ * the end of the string would be an uninteresting crash.
+ */
+ if (len > MAX_LENGTH) {
+ len = MAX_LENGTH;
+ }
+ memcpy(buf, input, len);
+ buf[len] = 0;
+
+ control = ldb_parse_control_from_string(ldb, ldb, buf);
+ if (control != NULL) {
+ ldb_control_to_string(ldb, control);
+ }
+ TALLOC_FREE(ldb);
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ldb_parse_tree.c b/lib/fuzzing/fuzz_ldb_parse_tree.c
new file mode 100644
index 0000000..e22dd77
--- /dev/null
+++ b/lib/fuzzing/fuzz_ldb_parse_tree.c
@@ -0,0 +1,53 @@
+/*
+ Fuzzing for ldb_parse_tree
+ Copyright (C) Michael Hanselmann 2019
+
+ 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 "ldb.h"
+#include "ldb_module.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
+ struct ldb_parse_tree *tree;
+ char *filter;
+
+ if (len < 1) {
+ goto out;
+ }
+
+ filter = talloc_strndup(mem_ctx, (const char*)buf, len);
+
+ if (filter == NULL) {
+ goto out;
+ }
+
+ tree = ldb_parse_tree(mem_ctx, filter);
+
+ (void)ldb_filter_from_tree(mem_ctx, tree);
+
+out:
+ talloc_free(mem_ctx);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress.c b/lib/fuzzing/fuzz_lzxpress.c
new file mode 100644
index 0000000..61ce9e6
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress.c
@@ -0,0 +1,35 @@
+/*
+ Fuzzing for lzxpress_decompress
+ Copyright (C) Michael Hanselmann 2019
+
+ 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 "lzxpress.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ static uint8_t output[1024 * 1024] = {0};
+
+ lzxpress_decompress(buf, len, output, sizeof(output));
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress_compress.c b/lib/fuzzing/fuzz_lzxpress_compress.c
new file mode 100644
index 0000000..39e909d
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress_compress.c
@@ -0,0 +1,35 @@
+/*
+ Fuzzing for lzxpress_decompress
+ Copyright (C) Michael Hanselmann 2019
+
+ 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 "lzxpress.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ static uint8_t output[1024 * 1024] = {0};
+
+ lzxpress_compress(buf, len, output, sizeof(output));
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_lzxpress_round_trip.c b/lib/fuzzing/fuzz_lzxpress_round_trip.c
new file mode 100644
index 0000000..a6173bb
--- /dev/null
+++ b/lib/fuzzing/fuzz_lzxpress_round_trip.c
@@ -0,0 +1,53 @@
+/*
+ Fuzzing for lzxpress_decompress
+ Copyright (C) Michael Hanselmann 2019
+
+ 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 "lzxpress.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ static uint8_t compressed[1024 * 1024] = {0};
+ static uint8_t decompressed[1024 * 1024] = {0};
+ ssize_t compressed_size;
+ ssize_t decompressed_size;
+
+ if (len > sizeof(decompressed)) {
+ return 0;
+ }
+
+ compressed_size = lzxpress_compress(buf, len,
+ compressed, sizeof(compressed));
+
+ decompressed_size = lzxpress_decompress(compressed, compressed_size,
+ decompressed, sizeof(decompressed));
+
+ if (decompressed_size != len) {
+ abort();
+ }
+ if (memcmp(buf, decompressed, len) != 0) {
+ abort();
+ }
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_ndr_X.c b/lib/fuzzing/fuzz_ndr_X.c
new file mode 100644
index 0000000..a3fb984
--- /dev/null
+++ b/lib/fuzzing/fuzz_ndr_X.c
@@ -0,0 +1,337 @@
+/*
+ Unix SMB/CIFS implementation.
+ Fuzzer for pidl-generated NDR pipes.
+ Copyright (C) Andrew Tridgell 2003
+ Copyright (C) Jelmer Vernooij 2006
+ Copyright (C) Andrew Bartlett 2019
+ Copyright (C) Catalyst.NET Ltd 2019
+
+ 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 "system/filesys.h"
+#include "system/locale.h"
+#include "librpc/ndr/libndr.h"
+#include "librpc/gen_ndr/ndr_dcerpc.h"
+#include "util/byteorder.h"
+#include "fuzzing/fuzzing.h"
+
+extern const struct ndr_interface_table FUZZ_PIPE_TABLE;
+
+#define FLAG_NDR64 4
+
+enum {
+ TYPE_STRUCT = 0,
+ TYPE_IN,
+ TYPE_OUT
+};
+
+/*
+ * header design (little endian):
+ *
+ * struct {
+ * uint16_t flags;
+ * uint16_t function_or_struct_no;
+ * };
+ */
+
+/*
+ * We want an even number here to ensure 4-byte alignment later
+ * not just for efficieny but because the fuzzers are known to guess
+ * that numbers will be 4-byte aligned
+ */
+#define HEADER_SIZE 4
+
+#define INVALID_FLAGS (~(FLAG_NDR64 | 3))
+
+static const struct ndr_interface_call *find_function(
+ const struct ndr_interface_table *p,
+ unsigned int function_no)
+{
+ if (function_no >= p->num_calls) {
+ return NULL;
+ }
+ return &p->calls[function_no];
+}
+
+/*
+ * Get a public structure by number and return it as if it were
+ * a function.
+ */
+static const struct ndr_interface_call *find_struct(
+ const struct ndr_interface_table *p,
+ unsigned int struct_no,
+ struct ndr_interface_call *out_buffer)
+{
+ const struct ndr_interface_public_struct *s = NULL;
+
+ if (struct_no >= p->num_public_structs) {
+ return NULL;
+ }
+
+ s = &p->public_structs[struct_no];
+
+ *out_buffer = (struct ndr_interface_call) {
+ .name = s->name,
+ .struct_size = s->struct_size,
+ .ndr_pull = s->ndr_pull,
+ .ndr_push = s->ndr_push,
+ .ndr_print = s->ndr_print
+ };
+ return out_buffer;
+}
+
+
+static NTSTATUS pull_chunks(struct ndr_pull *ndr_pull,
+ const struct ndr_interface_call_pipes *pipes)
+{
+ enum ndr_err_code ndr_err;
+ uint32_t i;
+
+ for (i=0; i < pipes->num_pipes; i++) {
+ while (true) {
+ void *saved_mem_ctx;
+ uint32_t *count;
+ void *c;
+
+ c = talloc_zero_size(ndr_pull, pipes->pipes[i].chunk_struct_size);
+ if (c == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ /*
+ * Note: the first struct member is always
+ * 'uint32_t count;'
+ */
+ count = (uint32_t *)c;
+
+ saved_mem_ctx = ndr_pull->current_mem_ctx;
+ ndr_pull->current_mem_ctx = c;
+ ndr_err = pipes->pipes[i].ndr_pull(ndr_pull, NDR_SCALARS, c);
+ ndr_pull->current_mem_ctx = saved_mem_ctx;
+
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ talloc_free(c);
+ return ndr_map_error2ntstatus(ndr_err);
+ }
+ if (*count == 0) {
+ talloc_free(c);
+ break;
+ }
+ talloc_free(c);
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void ndr_print_nothing(struct ndr_print *ndr, const char *format, ...)
+{
+ /*
+ * This is here so that we walk the tree but don't output anything.
+ * This helps find buggy ndr_print routines
+ */
+
+ /*
+ * TODO: consider calling snprinf() to find strings without NULL
+ * terminators (for example)
+ */
+}
+
+
+int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
+ uint8_t type;
+ int pull_push_print_flags;
+ uint16_t fuzz_packet_flags, function;
+ TALLOC_CTX *mem_ctx = NULL;
+ uint32_t ndr_flags = 0;
+ struct ndr_push *ndr_push;
+ enum ndr_err_code ndr_err;
+ struct ndr_interface_call f_buffer;
+ const struct ndr_interface_call *f = NULL;
+ NTSTATUS status;
+
+/*
+ * This allows us to build binaries to fuzz just one target function
+ *
+ * In this mode the input becomes the 'stub data', there is no prefix.
+ *
+ * There is no NDR64 support in this mode at this time.
+ */
+#if defined(FUZZ_TYPE) && defined(FUZZ_FUNCTION)
+#undef HEADER_SIZE
+#define HEADER_SIZE 0
+ fuzz_packet_flags = 0;
+ type = FUZZ_TYPE;
+ function = FUZZ_FUNCTION;
+#else
+ if (size < HEADER_SIZE) {
+ /*
+ * the first few bytes decide what is being fuzzed --
+ * if they aren't all there we do nothing.
+ */
+ return 0;
+ }
+
+ fuzz_packet_flags = SVAL(data, 0);
+ if (fuzz_packet_flags & INVALID_FLAGS) {
+ return 0;
+ }
+
+ function = SVAL(data, 2);
+
+ type = fuzz_packet_flags & 3;
+
+#ifdef FUZZ_TYPE
+ /*
+ * Fuzz targets should have as small an interface as possible.
+ * This allows us to create 3 binaries for most pipes,
+ * TYPE_IN, TYPE_OUT and TYPE_STRUCT
+ *
+ * We keep the header format, and just exit early if it does
+ * not match.
+ */
+ if (type != FUZZ_TYPE) {
+ return 0;
+ }
+#endif
+#endif
+
+ switch (type) {
+ case TYPE_STRUCT:
+ pull_push_print_flags = NDR_SCALARS|NDR_BUFFERS;
+ f = find_struct(&FUZZ_PIPE_TABLE, function, &f_buffer);
+ break;
+ case TYPE_IN:
+ pull_push_print_flags = NDR_IN;
+ f = find_function(&FUZZ_PIPE_TABLE, function);
+ break;
+ case TYPE_OUT:
+ pull_push_print_flags = NDR_OUT;
+ f = find_function(&FUZZ_PIPE_TABLE, function);
+ break;
+ default:
+ return 0;
+ }
+
+ if (f == NULL) {
+ return 0;
+ }
+ if (fuzz_packet_flags & FLAG_NDR64) {
+ ndr_flags |= LIBNDR_FLAG_NDR64;
+ }
+
+ mem_ctx = talloc_init("ndrfuzz");
+
+ {
+ /*
+ * f->struct_size is well-controlled, it is essentially
+ * defined in the IDL
+ */
+ uint8_t st[f->struct_size];
+
+ DATA_BLOB blob = data_blob_const(data + HEADER_SIZE,
+ size - HEADER_SIZE);
+ struct ndr_pull *ndr_pull = ndr_pull_init_blob(&blob,
+ mem_ctx);
+
+ if (ndr_pull == NULL) {
+ perror("ndr_pull_init_blob");
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ /*
+ * We must initialise the buffer (even if we would
+ * prefer not to for the sake of eg valgrind) as
+ * otherwise the special handler for 'out pointer with
+ * [size_is()] refers to in value with [ref]' fails to
+ * trigger
+ */
+ memset(st, '\0', sizeof(st));
+
+ ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+ ndr_pull->global_max_recursion = 128;
+
+ if (type == TYPE_OUT) {
+ status = pull_chunks(ndr_pull,
+ &f->out_pipes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+ }
+
+ ndr_err = f->ndr_pull(ndr_pull,
+ pull_push_print_flags,
+ st);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ if (type == TYPE_IN) {
+ status = pull_chunks(ndr_pull,
+ &f->in_pipes);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+ }
+
+ ndr_push = ndr_push_init_ctx(mem_ctx);
+ if (ndr_push == NULL) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ ndr_push->flags |= ndr_flags;
+
+ /*
+ * Now push what was pulled, just in case we generated an
+ * invalid structure in memory, this should notice
+ */
+ ndr_err = f->ndr_push(ndr_push,
+ pull_push_print_flags,
+ st);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ TALLOC_FREE(mem_ctx);
+ return 0;
+ }
+
+ {
+ struct ndr_print *ndr_print = talloc_zero(mem_ctx, struct ndr_print);
+ ndr_print->print = ndr_print_nothing;
+ ndr_print->depth = 1;
+
+ /*
+ * Finally print (to nowhere) the structure, this may also
+ * notice invalid memory
+ */
+ f->ndr_print(ndr_print,
+ f->name,
+ pull_push_print_flags,
+ st);
+ }
+ }
+ TALLOC_FREE(mem_ctx);
+
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_nmblib_parse_packet.c b/lib/fuzzing/fuzz_nmblib_parse_packet.c
new file mode 100644
index 0000000..85dd823
--- /dev/null
+++ b/lib/fuzzing/fuzz_nmblib_parse_packet.c
@@ -0,0 +1,62 @@
+/*
+ Fuzz NMB parse_packet
+ 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 "../../source3/include/includes.h"
+#include "libsmb/libsmb.h"
+#include "libsmb/nmblib.h"
+#include "fuzzing/fuzzing.h"
+
+#define PORT 138
+#define MAX_LENGTH (1024 * 1024)
+char buf[MAX_LENGTH + 1];
+
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ struct packet_struct *p = NULL;
+ struct in_addr ip = {
+ 0x0100007f /* 127.0.0.1 */
+ };
+
+ p = parse_packet((char *)input,
+ len,
+ NMB_PACKET,
+ ip,
+ PORT);
+ /*
+ * We expect NULL (parse failure) most of the time.
+ *
+ * When it is not NULL we want to ensure the parsed packet is
+ * reasonably sound.
+ */
+
+ if (p != NULL) {
+ struct nmb_packet *nmb = &p->packet.nmb;
+ pull_ascii_nstring(buf, MAX_LENGTH,
+ nmb->question.question_name.name);
+ build_packet(buf, MAX_LENGTH, p);
+ free_packet(p);
+ }
+ return 0;
+}
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_oLschema2ldif.c b/lib/fuzzing/fuzz_oLschema2ldif.c
new file mode 100644
index 0000000..873e8f1
--- /dev/null
+++ b/lib/fuzzing/fuzz_oLschema2ldif.c
@@ -0,0 +1,71 @@
+/*
+ Fuzzing for oLschema2ldif
+ Copyright (C) Michael Hanselmann 2019
+
+ 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.h"
+#include "utils/oLschema2ldif/lib.h"
+
+static FILE *devnull;
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ devnull = fopen("/dev/null", "w");
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ TALLOC_CTX *mem_ctx;
+ struct conv_options opt;
+
+ if (len == 0) {
+ /*
+ * Otherwise fmemopen() will return null and set errno
+ * to EINVAL
+ */
+ return 0;
+ }
+
+ mem_ctx = talloc_init(__FUNCTION__);
+ if (mem_ctx == NULL) {
+ return 0;
+ }
+
+ opt.in = fmemopen(buf, len, "r");
+ opt.out = devnull;
+ opt.ldb_ctx = ldb_init(mem_ctx, NULL);
+ if (opt.ldb_ctx == NULL || opt.in == NULL) {
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ opt.basedn = ldb_dn_new(mem_ctx, opt.ldb_ctx, "");
+ if (opt.basedn == NULL) {
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ process_file(mem_ctx, &opt);
+
+ fclose(opt.in);
+
+ talloc_free(mem_ctx);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_parse_lpq_entry.c b/lib/fuzzing/fuzz_parse_lpq_entry.c
new file mode 100644
index 0000000..720cc9b
--- /dev/null
+++ b/lib/fuzzing/fuzz_parse_lpq_entry.c
@@ -0,0 +1,65 @@
+/*
+ Fuzzing parse_lpq_entry
+ Copyright (C) Douglas Bagnall <dbagnall@samba.org> 2021
+
+ 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 "../../source3/include/includes.h"
+#include "printing.h"
+#include "fuzzing/fuzzing.h"
+
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+#define MAX_LENGTH (1024 * 1024)
+char line[MAX_LENGTH + 1];
+
+int LLVMFuzzerTestOneInput(uint8_t *input, size_t len)
+{
+ enum printing_types printing_type;
+ print_queue_struct pq_buf = {0};
+ print_status_struct status = {0};
+ bool first;
+ unsigned x;
+ TALLOC_CTX *frame = NULL;
+
+ if (len < 1 || len > MAX_LENGTH) {
+ return 0;
+ }
+
+ x = input[0];
+ input++;
+ len--;
+
+ /* There are 14 types, default goes to bsd */
+ printing_type = x & 15;
+ first = (x & 16) ? true : false;
+
+ memcpy(line, input, len);
+ line[len] = '\0';
+
+ /* parse_lpq_bsd requires a stackframe */
+ frame = talloc_stackframe();
+
+ parse_lpq_entry(printing_type,
+ line,
+ &pq_buf, /* out */
+ &status, /* out */
+ first);
+ talloc_free(frame);
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_reg_parse.c b/lib/fuzzing/fuzz_reg_parse.c
new file mode 100644
index 0000000..a061cd6
--- /dev/null
+++ b/lib/fuzzing/fuzz_reg_parse.c
@@ -0,0 +1,46 @@
+/*
+ * Fuzzing for reg_parse
+ * Copyright (C) Michael Hanselmann 2019
+ *
+ * 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 "lib/util/fault.h"
+#include "registry.h"
+#include "registry/reg_parse.h"
+
+static FILE *fp;
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ fp = tmpfile();
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ const reg_parse_callback cb = {0};
+
+ rewind(fp);
+ (void)fwrite(buf, len, 1, fp);
+ (void)fflush(fp);
+ rewind(fp);
+
+ (void)reg_parse_fd(fileno(fp), &cb, "");
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_regfio.c b/lib/fuzzing/fuzz_regfio.c
new file mode 100644
index 0000000..c4ced88
--- /dev/null
+++ b/lib/fuzzing/fuzz_regfio.c
@@ -0,0 +1,68 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Windows NT registry I/O library
+ * Copyright (C) Michael Hanselmann 2019
+ *
+ * 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 "system/filesys.h"
+#include "lib/util/fault.h"
+#include "registry/reg_objects.h"
+#include "registry/regfio.h"
+
+static FILE *fp;
+static char filename[128];
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ fp = tmpfile();
+
+ (void)snprintf(filename, sizeof(filename), "/proc/self/fd/%d", fileno(fp));
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ REGF_FILE* regfile;
+ REGF_NK_REC *nk, *subkey;
+
+ rewind(fp);
+ (void)fwrite(buf, len, 1, fp);
+ (void)fflush(fp);
+
+ regfile = regfio_open(filename, O_RDONLY, 0600);
+ if (!regfile) {
+ goto out;
+ }
+
+ regfile->ignore_checksums = true;
+
+ nk = regfio_rootkey(regfile);
+ if (nk != NULL) {
+ nk->subkey_index = 0;
+ while ((subkey = regfio_fetch_subkey(regfile, nk))) {
+ }
+ }
+
+out:
+ if (regfile != NULL) {
+ regfio_close(regfile);
+ }
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzz_tiniparser.c b/lib/fuzzing/fuzz_tiniparser.c
new file mode 100644
index 0000000..6908f18
--- /dev/null
+++ b/lib/fuzzing/fuzz_tiniparser.c
@@ -0,0 +1,51 @@
+/*
+ Fuzzing for trivial smb.conf parsing code.
+ Copyright (C) Michael Hanselmann 2019
+
+ 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.h"
+#include "lib/util/tiniparser.h"
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
+{
+ FILE *fp = NULL;
+ struct tiniparser_dictionary *d = NULL;
+
+ if (len == 0) {
+ /*
+ * Otherwise fmemopen() will return null and set errno
+ * to EINVAL
+ */
+ return 0;
+ }
+
+ fp = fmemopen(buf, len, "r");
+
+ d = tiniparser_load_stream(fp);
+ if (d != NULL) {
+ tiniparser_freedict(d);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
diff --git a/lib/fuzzing/fuzzing.c b/lib/fuzzing/fuzzing.c
new file mode 100644
index 0000000..f0d7fb4
--- /dev/null
+++ b/lib/fuzzing/fuzzing.c
@@ -0,0 +1,21 @@
+/*
+ Unix SMB/CIFS implementation.
+ Fuzzing utility functions
+ Copyright (C) Michael Hanselmann 2019
+
+ 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"
diff --git a/lib/fuzzing/fuzzing.h b/lib/fuzzing/fuzzing.h
new file mode 100644
index 0000000..67e49c3
--- /dev/null
+++ b/lib/fuzzing/fuzzing.h
@@ -0,0 +1,30 @@
+/*
+ Unix SMB/CIFS implementation.
+ Fuzzing utility functions
+ Copyright (C) Michael Hanselmann 2019
+
+ 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/>.
+*/
+
+#ifndef _SAMBA_FUZZING_H
+#define _SAMBA_FUZZING_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* Prototypes for fuzzing interface */
+int LLVMFuzzerInitialize(int *argc, char ***argv);
+int LLVMFuzzerTestOneInput(uint8_t * buf, size_t len);
+
+#endif /* _SAMBA_FUZZING_H */
diff --git a/lib/fuzzing/oss-fuzz/build_image.sh b/lib/fuzzing/oss-fuzz/build_image.sh
new file mode 100755
index 0000000..62a626b
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/build_image.sh
@@ -0,0 +1,7 @@
+#!/bin/sh -e
+
+DIST=ubuntu2004
+SCRIPT_DIR=$(dirname $0)
+
+$SCRIPT_DIR/../../../bootstrap/generated-dists/$DIST/bootstrap.sh
+$SCRIPT_DIR/../../../bootstrap/generated-dists/$DIST/locale.sh
diff --git a/lib/fuzzing/oss-fuzz/build_samba.sh b/lib/fuzzing/oss-fuzz/build_samba.sh
new file mode 100755
index 0000000..dc5387d
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/build_samba.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# This is not a general-purpose build script, but instead one specific
+# to the Google oss-fuzz compile environment.
+#
+# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#Requirements
+#
+# https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/README.md#provided-environment-variables
+#
+# This file is run by
+# https://github.com/google/oss-fuzz/blob/master/projects/samba/build.sh
+# which does nothing else.
+#
+# Additional arguments are passed to configure, to allow this to be
+# tested in autobuild.py
+#
+
+# Ensure we give good trace info, fail right away and fail with unset
+# variables
+set -e
+set -x
+set -u
+
+$(dirname $0)/do_build.sh $@
+$(dirname $0)/check_build.sh $OUT
diff --git a/lib/fuzzing/oss-fuzz/check_build.sh b/lib/fuzzing/oss-fuzz/check_build.sh
new file mode 100755
index 0000000..6523bf3
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/check_build.sh
@@ -0,0 +1,48 @@
+#!/bin/sh -eux
+#
+# A very simple check script to confirm we still provide binaries
+# that look like the targets oss-fuzz wants.
+#
+# A much stronger check is availble in oss-fuzz via
+# infra/helper.py check_build samba
+#
+
+# oss-fuzz provides an OUT variable, so for clarity this script
+# uses the same. See build_samba.sh
+OUT=$1
+
+# build_samba.sh will have put a non-zero number of fuzzers here. If
+# there are none, this will fail as it becomes literally fuzz_*
+
+seeds_found=no
+
+for bin in $OUT/fuzz_*; do
+ # we only want to look at the elf files, not the zips
+ if [ ${bin%_seed_corpus.zip} != $bin ]; then
+ continue
+ fi
+ # Confirm that the chrpath was reset to lib/ in the same directory
+ # as the binary. RPATH (not RUNPATH) is critical, otherwise
+ # libraries used by libraries won't be found on the oss-fuzz
+ # target host.
+ chrpath -l $bin | grep 'RPATH=$ORIGIN/lib'
+
+ # Confirm that we link to at least some libraries in this
+ # directory (shows that the libraries were found and copied).
+ ldd $bin | grep "$OUT/lib"
+ num_libs=$(ldd $bin | grep -v ld-linux | grep -v linux-vdso | grep -v "$OUT/lib" | wc -l)
+
+ if [ 0$num_libs -ne 0 ]; then
+ echo "some libraries not linked to $ORIGIN/lib, oss-fuzz will fail!"
+ exit 1
+ fi
+
+ if [ -f ${bin}_seed_corpus.zip ]; then
+ seeds_found=yes
+ fi
+done
+
+if [ $seeds_found = no ]; then
+ echo "no seed zip files were found!"
+ exit 1
+fi
diff --git a/lib/fuzzing/oss-fuzz/do_build.sh b/lib/fuzzing/oss-fuzz/do_build.sh
new file mode 100755
index 0000000..3b2fdd0
--- /dev/null
+++ b/lib/fuzzing/oss-fuzz/do_build.sh
@@ -0,0 +1,294 @@
+#!/bin/sh
+#
+# This is not a general-purpose build script, but instead one specific
+# to the Google oss-fuzz compile environment.
+#
+# https://google.github.io/oss-fuzz/getting-started/new-project-guide/#Requirements
+#
+# https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/README.md#provided-environment-variables
+#
+# This file is run by build_samba.sh, which is run by
+# https://github.com/google/oss-fuzz/blob/master/projects/samba/build.sh
+# which does nothing else.
+#
+# We have to push to oss-fuzz CFLAGS into the waf ADDITIONAL_CFLAGS
+# as otherwise waf's configure fails linking the first test binary
+#
+# CFLAGS are supplied by the caller, eg the oss-fuzz compile command
+#
+# Additional arguments are passed to configure, to allow this to be
+# tested in autobuild.py
+#
+
+# Ensure we give good trace info, fail right away and fail with unset
+# variables
+set -e
+set -x
+set -u
+
+# It is critical that this script, just as the rest of Samba's GitLab
+# CI docker has LANG set to en_US.utf8 (oss-fuzz fails to set this)
+if [ -f /etc/default/locale ]; then
+ . /etc/default/locale
+elif [ -f /etc/locale.conf ]; then
+ . /etc/locale.conf
+fi
+export LANG
+export LC_ALL
+
+ADDITIONAL_CFLAGS="$CFLAGS"
+export ADDITIONAL_CFLAGS
+CFLAGS=""
+export CFLAGS
+LD="$CXX"
+export LD
+
+# Use the system Python, not the OSS-Fuzz provided statically linked
+# and instrumented Python, because we can't statically link.
+
+PYTHON=/usr/bin/python3
+export PYTHON
+
+# $SANITIZER is provided by the oss-fuzz "compile" command
+#
+# We need to add the waf configure option as otherwise when we also
+# get (eg) -fsanitize=address via the CFLAGS we will fail to link
+# correctly
+
+case "$SANITIZER" in
+address)
+ SANITIZER_ARG='--address-sanitizer'
+ ;;
+undefined)
+ SANITIZER_ARG='--undefined-sanitizer'
+ ;;
+coverage)
+ # Thankfully clang operating as ld has no objection to the
+ # cc style options, so we can just set ADDITIONAL_LDFLAGS
+ # to ensure the coverage build is done, despite waf splitting
+ # the compile and link phases.
+ ADDITIONAL_LDFLAGS="${ADDITIONAL_LDFLAGS:-} $COVERAGE_FLAGS"
+ export ADDITIONAL_LDFLAGS
+
+ SANITIZER_ARG=''
+ ;;
+esac
+
+# $LIB_FUZZING_ENGINE is provided by the oss-fuzz "compile" command
+#
+
+# --disable-new-dtags linker flag creates fuzzer binaries with RPATH
+# header instead of RUNPATH header. Modern linkers use RUNPATH by
+# default.
+./configure -C --without-gettext --enable-debug --enable-developer \
+ --enable-libfuzzer \
+ $SANITIZER_ARG \
+ --disable-warnings-as-errors \
+ --abi-check-disable \
+ "--fuzz-target-ldflags=-Wl,--disable-new-dtags $LIB_FUZZING_ENGINE" \
+ --nonshared-binary=ALL \
+ "$@" \
+ LINK_CC="$CXX"
+
+make -j
+
+# Make a directory for the system shared libraries to be copied into
+mkdir -p $OUT/lib
+
+# oss-fuzz would prefer for all the binaries put into $OUT to be
+# statically linked.
+#
+# We can't static link to all the system libs with waf, so copy the
+# libraries we need to $OUT/lib and set the rpath to point there.
+# This is similar to how firefox handles this.
+#
+# NOTE on RPATH vs RUNPATH:
+#
+# RUNPATH appears to be the more modern version, and so modern ld.bfd
+# and ld.gold only set RUNPATH. RUNPATH makes sense on most systems,
+# but not for our hack.
+#
+# If we use RUNPATH, we can get an error like this:
+# Step #6: Error occured while running fuzz_nmblib_parse_packet:
+# Step #6: /workspace/out/coverage/fuzz_nmblib_parse_packet: error while loading shared libraries: libavahi-common.so.3: cannot open shared object file: No such file or directory
+#
+# This is because the full contents of $OUT are copied to yet another
+# host, which otherwise does not have much of linux at all. oss-fuzz
+# prefers a static binary because that will 'just work', but we can't
+# do that, so we need to use linker tricks.
+#
+# If the linker used RUNPATH (eg ld.bfd on Ubuntu 18.04 and later, ld.gold):
+# * bin=fuzz_nmblib_parse_packet
+# * OUT=/tmp/3/b12207/prefix/samba-fuzz
+# * chrpath -r '$ORIGIN/lib' $OUT/$bin'
+# * ldd $OUT/$bin
+# linux-vdso.so.1 (0x00007ffd4b7a5000)
+# libasan.so.5 => /tmp/3/b12207/prefix/samba-fuzz/lib/libasan.so.5 (0x00007ff25bdd0000)
+# libldap_r-2.4.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libldap_r-2.4.so.2 (0x00007ff25bd7a000)
+# liblber-2.4.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/liblber-2.4.so.2 (0x00007ff25bd69000)
+# libunwind-x86_64.so.8 => /tmp/3/b12207/prefix/samba-fuzz/lib/libunwind-x86_64.so.8 (0x00007ff25bd47000)
+# libunwind.so.8 => /tmp/3/b12207/prefix/samba-fuzz/lib/libunwind.so.8 (0x00007ff25bd2a000)
+# libgnutls.so.30 => /tmp/3/b12207/prefix/samba-fuzz/lib/libgnutls.so.30 (0x00007ff25bb54000)
+# libdl.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libdl.so.2 (0x00007ff25bb4c000)
+# libz.so.1 => /tmp/3/b12207/prefix/samba-fuzz/lib/libz.so.1 (0x00007ff25bb30000)
+# libjansson.so.4 => /tmp/3/b12207/prefix/samba-fuzz/lib/libjansson.so.4 (0x00007ff25bb21000)
+# libresolv.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libresolv.so.2 (0x00007ff25bb05000)
+# libsystemd.so.0 => /tmp/3/b12207/prefix/samba-fuzz/lib/libsystemd.so.0 (0x00007ff25ba58000)
+# libpthread.so.0 => /tmp/3/b12207/prefix/samba-fuzz/lib/libpthread.so.0 (0x00007ff25ba35000)
+# libicuuc.so.66 => /tmp/3/b12207/prefix/samba-fuzz/lib/libicuuc.so.66 (0x00007ff25b84d000)
+# libicui18n.so.66 => /tmp/3/b12207/prefix/samba-fuzz/lib/libicui18n.so.66 (0x00007ff25b54e000)
+# libcap.so.2 => /tmp/3/b12207/prefix/samba-fuzz/lib/libcap.so.2 (0x00007ff25b545000)
+# libbsd.so.0 => /tmp/3/b12207/prefix/samba-fuzz/lib/libbsd.so.0 (0x00007ff25b52b000)
+# libnsl.so.1 => /tmp/3/b12207/prefix/samba-fuzz/lib/libnsl.so.1 (0x00007ff25b50e000)
+# libc.so.6 => /tmp/3/b12207/prefix/samba-fuzz/lib/libc.so.6 (0x00007ff25b31c000)
+# librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff25b2f2000)
+# libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff25b1a3000)
+# libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff25b188000)
+# libsasl2.so.2 => /usr/lib/x86_64-linux-gnu/libsasl2.so.2 (0x00007ff25b16b000)
+# libgssapi.so.3 => /usr/lib/x86_64-linux-gnu/libgssapi.so.3 (0x00007ff25b126000)
+# liblzma.so.5 => /lib/x86_64-linux-gnu/liblzma.so.5 (0x00007ff25b0fd000)
+# /lib64/ld-linux-x86-64.so.2 (0x00007ff25ea0c000)
+# libp11-kit.so.0 => /usr/lib/x86_64-linux-gnu/libp11-kit.so.0 (0x00007ff25afc5000)
+# libidn2.so.0 => /usr/lib/x86_64-linux-gnu/libidn2.so.0 (0x00007ff25afa4000)
+# libunistring.so.2 => /usr/lib/x86_64-linux-gnu/libunistring.so.2 (0x00007ff25ae22000)
+# libtasn1.so.6 => /usr/lib/x86_64-linux-gnu/libtasn1.so.6 (0x00007ff25ae0c000)
+# libnettle.so.7 => /usr/lib/x86_64-linux-gnu/libnettle.so.7 (0x00007ff25add2000)
+# libhogweed.so.5 => /usr/lib/x86_64-linux-gnu/libhogweed.so.5 (0x00007ff25ad9a000)
+# libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007ff25ad14000)
+# liblz4.so.1 => /usr/lib/x86_64-linux-gnu/liblz4.so.1 (0x00007ff25acf3000)
+# libgcrypt.so.20 => /usr/lib/x86_64-linux-gnu/libgcrypt.so.20 (0x00007ff25abd5000)
+# libicudata.so.66 => /usr/lib/x86_64-linux-gnu/libicudata.so.66 (0x00007ff259114000)
+# libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff258f33000)
+# libheimntlm.so.0 => /usr/lib/x86_64-linux-gnu/libheimntlm.so.0 (0x00007ff258f25000)
+# libkrb5.so.26 => /usr/lib/x86_64-linux-gnu/libkrb5.so.26 (0x00007ff258e92000)
+# libasn1.so.8 => /usr/lib/x86_64-linux-gnu/libasn1.so.8 (0x00007ff258deb000)
+# libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007ff258de4000)
+# libhcrypto.so.4 => /usr/lib/x86_64-linux-gnu/libhcrypto.so.4 (0x00007ff258dac000)
+# libroken.so.18 => /usr/lib/x86_64-linux-gnu/libroken.so.18 (0x00007ff258d93000)
+# libffi.so.7 => /usr/lib/x86_64-linux-gnu/libffi.so.7 (0x00007ff258d85000)
+# libgpg-error.so.0 => /lib/x86_64-linux-gnu/libgpg-error.so.0 (0x00007ff258d62000)
+# libwind.so.0 => /usr/lib/x86_64-linux-gnu/libwind.so.0 (0x00007ff258d38000)
+# libheimbase.so.1 => /usr/lib/x86_64-linux-gnu/libheimbase.so.1 (0x00007ff258d26000)
+# libhx509.so.5 => /usr/lib/x86_64-linux-gnu/libhx509.so.5 (0x00007ff258cd8000)
+# libsqlite3.so.0 => /usr/lib/x86_64-linux-gnu/libsqlite3.so.0 (0x00007ff258bad000)
+# libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007ff258b72000)
+#
+# Note how all the dependencies of libc and gnutls are not forced to
+# $OUT/lib (via the magic $ORIGIN variable, meaning the directory of
+# the binary). These will not be found on the target system!
+#
+# If the linker used RPATH however
+# * bin=fuzz_nmblib_parse_packet
+# * OUT=/tmp/3/b22/prefix/samba-fuzz
+# * chrpath -r '$ORIGIN/lib' $OUT/$bin'
+# * ldd $OUT/$bin
+# linux-vdso.so.1 => (0x00007ffef85c7000)
+# libasan.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libasan.so.2 (0x00007f3668b4f000)
+# libldap_r-2.4.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libldap_r-2.4.so.2 (0x00007f36688fe000)
+# liblber-2.4.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/liblber-2.4.so.2 (0x00007f36686ef000)
+# libunwind-x86_64.so.8 => /tmp/3/b22/prefix/samba-fuzz/lib/libunwind-x86_64.so.8 (0x00007f36684d0000)
+# libunwind.so.8 => /tmp/3/b22/prefix/samba-fuzz/lib/libunwind.so.8 (0x00007f36682b5000)
+# libgnutls.so.30 => /tmp/3/b22/prefix/samba-fuzz/lib/libgnutls.so.30 (0x00007f3667f85000)
+# libdl.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libdl.so.2 (0x00007f3667d81000)
+# libz.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libz.so.1 (0x00007f3667b67000)
+# libjansson.so.4 => /tmp/3/b22/prefix/samba-fuzz/lib/libjansson.so.4 (0x00007f366795a000)
+# libresolv.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libresolv.so.2 (0x00007f366773f000)
+# libsystemd.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libsystemd.so.0 (0x00007f366be2f000)
+# libpthread.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libpthread.so.0 (0x00007f3667522000)
+# libicuuc.so.55 => /tmp/3/b22/prefix/samba-fuzz/lib/libicuuc.so.55 (0x00007f366718e000)
+# libicui18n.so.55 => /tmp/3/b22/prefix/samba-fuzz/lib/libicui18n.so.55 (0x00007f3666d2c000)
+# libcap.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libcap.so.2 (0x00007f3666b26000)
+# libbsd.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libbsd.so.0 (0x00007f3666911000)
+# libnsl.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libnsl.so.1 (0x00007f36666f8000)
+# libc.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libc.so.6 (0x00007f366632e000)
+# libm.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libm.so.6 (0x00007f3666025000)
+# libgcc_s.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libgcc_s.so.1 (0x00007f3665e0f000)
+# libsasl2.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libsasl2.so.2 (0x00007f3665bf4000)
+# libgssapi.so.3 => /tmp/3/b22/prefix/samba-fuzz/lib/libgssapi.so.3 (0x00007f36659b3000)
+# liblzma.so.5 => /tmp/3/b22/prefix/samba-fuzz/lib/liblzma.so.5 (0x00007f3665791000)
+# /lib64/ld-linux-x86-64.so.2 (0x00007f366bc93000)
+# libp11-kit.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libp11-kit.so.0 (0x00007f366552d000)
+# libidn.so.11 => /tmp/3/b22/prefix/samba-fuzz/lib/libidn.so.11 (0x00007f36652fa000)
+# libtasn1.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libtasn1.so.6 (0x00007f36650e7000)
+# libnettle.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libnettle.so.6 (0x00007f3664eb1000)
+# libhogweed.so.4 => /tmp/3/b22/prefix/samba-fuzz/lib/libhogweed.so.4 (0x00007f3664c7e000)
+# libgmp.so.10 => /tmp/3/b22/prefix/samba-fuzz/lib/libgmp.so.10 (0x00007f36649fe000)
+# libselinux.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libselinux.so.1 (0x00007f36647dc000)
+# librt.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/librt.so.1 (0x00007f36645d4000)
+# libgcrypt.so.20 => /tmp/3/b22/prefix/samba-fuzz/lib/libgcrypt.so.20 (0x00007f36642f3000)
+# libicudata.so.55 => /tmp/3/b22/prefix/samba-fuzz/lib/libicudata.so.55 (0x00007f366283c000)
+# libstdc++.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libstdc++.so.6 (0x00007f36624ba000)
+# libheimntlm.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libheimntlm.so.0 (0x00007f36622b1000)
+# libkrb5.so.26 => /tmp/3/b22/prefix/samba-fuzz/lib/libkrb5.so.26 (0x00007f3662027000)
+# libasn1.so.8 => /tmp/3/b22/prefix/samba-fuzz/lib/libasn1.so.8 (0x00007f3661d85000)
+# libcom_err.so.2 => /tmp/3/b22/prefix/samba-fuzz/lib/libcom_err.so.2 (0x00007f3661b81000)
+# libhcrypto.so.4 => /tmp/3/b22/prefix/samba-fuzz/lib/libhcrypto.so.4 (0x00007f366194e000)
+# libroken.so.18 => /tmp/3/b22/prefix/samba-fuzz/lib/libroken.so.18 (0x00007f3661738000)
+# libffi.so.6 => /tmp/3/b22/prefix/samba-fuzz/lib/libffi.so.6 (0x00007f3661530000)
+# libpcre.so.3 => /tmp/3/b22/prefix/samba-fuzz/lib/libpcre.so.3 (0x00007f36612c0000)
+# libgpg-error.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libgpg-error.so.0 (0x00007f36610ac000)
+# libwind.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libwind.so.0 (0x00007f3660e83000)
+# libheimbase.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libheimbase.so.1 (0x00007f3660c74000)
+# libhx509.so.5 => /tmp/3/b22/prefix/samba-fuzz/lib/libhx509.so.5 (0x00007f3660a29000)
+# libsqlite3.so.0 => /tmp/3/b22/prefix/samba-fuzz/lib/libsqlite3.so.0 (0x00007f3660754000)
+# libcrypt.so.1 => /tmp/3/b22/prefix/samba-fuzz/lib/libcrypt.so.1 (0x00007f366051c000)
+#
+# See how the runtime linker seems to honour the RPATH for
+# dependencies of dependencies in this case. This helps us us lot.
+
+for x in bin/fuzz_*; do
+ # Copy any system libraries needed by this fuzzer to $OUT/lib.
+
+ # We run ldd on $x, the fuzz_binary in bin/ which has not yet had
+ # the RPATH altered. This is clearer for debugging in local
+ # development builds as $OUT is not cleaned between runs.
+ #
+ # Otherwise trying to re-run this can see cp can fail with:
+ # cp: '/out/lib/libgcc_s.so.1' and '/out/lib/libgcc_s.so.1' are the same file
+ # which is really confusing!
+
+ # The cut for ( and ' ' removes the special case references to:
+ # linux-vdso.so.1 => (0x00007ffe8f2b2000)
+ # /lib64/ld-linux-x86-64.so.2 (0x00007fc63ea6f000)
+
+ ldd $x | cut -f 2 -d '>' | cut -f 1 -d \( | cut -f 2 -d ' ' | xargs -i cp \{\} $OUT/lib/
+
+ cp $x $OUT/
+ bin=$(basename $x)
+
+ # This means the copied libraries are found on the runner.
+ #
+ # The binaries should we built with RPATH, not RUNPATH, to allow
+ # libraries used by libraries to be found. This command retains the
+ # RPATH/RUNPATH header and only changes the path. We later verify this
+ # in the check_build.sh script.
+ chrpath -r '$ORIGIN/lib' $OUT/$bin
+
+ # Truncate the original binary to save space
+ echo -n >$x
+
+done
+
+# Strip RUNPATH: or RPATH: entries from shared libraries copied over to $OUT/lib.
+# When those libraries get loaded and have further dependencies, a RUNPATH: header
+# will cause the dynamic linker to search in the runpath, and not in $OUT/lib,
+# and there's no way it will be found in the fuzzing env.
+#
+# So how is the indirect depedency found in $OUT/lib? Well, suppose the fuzzer binary
+# links library A which links library B. During linking, both A and B as listed in the
+# executable file's runtime dependencies (This was pioneered in Fedora 13 in 2010, but
+# is common behavior now). So we have the fuzzer binary with RPATH set to $OUT/lib, and
+# a dependency on library B, and it will therefor find library B in $OUT/lib. On the
+# hand, if we keep the RUNPATH in library A, and load A first, it will try loading
+# library B as a dependency of A from the wrong place.
+chrpath -d $OUT/lib/*
+
+# Grap the seeds dictionary from github and put the seed zips in place
+# beside their executables.
+
+wget https://gitlab.com/samba-team/samba-fuzz-seeds/-/jobs/artifacts/master/download?job=zips \
+ -O seeds.zip
+
+# We might not have unzip, but we do have python
+$PYTHON -mzipfile -e seeds.zip $OUT
+rm -f seeds.zip
diff --git a/lib/fuzzing/wscript_build b/lib/fuzzing/wscript_build
new file mode 100644
index 0000000..9c559b3
--- /dev/null
+++ b/lib/fuzzing/wscript_build
@@ -0,0 +1,197 @@
+#!/usr/bin/env python
+
+from waflib import Build
+
+bld.SAMBA_SUBSYSTEM('fuzzing',
+ source='fuzzing.c',
+ deps='talloc')
+
+bld.SAMBA_SUBSYSTEM('afl-fuzz-main',
+ source='afl-fuzz-main.c',
+ deps='samba-util',
+ enabled=bld.env.enable_afl_fuzzer
+ )
+
+bld.SAMBA_BINARY('fuzz_tiniparser',
+ source='fuzz_tiniparser.c',
+ deps='fuzzing tiniparser talloc afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_parse_lpq_entry',
+ source='fuzz_parse_lpq_entry.c',
+ deps='fuzzing afl-fuzz-main smbd_base PRINTING',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_oLschema2ldif',
+ source='fuzz_oLschema2ldif.c',
+ deps='fuzzing oLschema2ldif-lib afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_reg_parse',
+ source='fuzz_reg_parse.c',
+ deps='fuzzing samba3-util smbconf REGFIO afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_nmblib_parse_packet',
+ source='fuzz_nmblib_parse_packet.c',
+ deps='fuzzing libsmb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_regfio',
+ source='fuzz_regfio.c',
+ deps='fuzzing samba3-util smbconf REGFIO afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress',
+ source='fuzz_lzxpress.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress_compress',
+ source='fuzz_lzxpress_compress.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_lzxpress_round_trip',
+ source='fuzz_lzxpress_round_trip.c',
+ deps='fuzzing LZXPRESS afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldap_decode',
+ source='fuzz_ldap_decode.c',
+ deps='fuzzing cli-ldap afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_parse_control',
+ source='fuzz_ldb_parse_control.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_dn_explode',
+ source='fuzz_ldb_dn_explode.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_ldif_read',
+ source='fuzz_ldb_ldif_read.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_parse_binary_decode',
+ source='fuzz_ldb_parse_binary_decode.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_ldb_parse_tree',
+ source='fuzz_ldb_parse_tree.c',
+ deps='fuzzing ldb afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_dcerpc_parse_binding',
+ source='fuzz_dcerpc_parse_binding.c',
+ deps='fuzzing dcerpc afl-fuzz-main',
+ fuzzer=True)
+
+bld.SAMBA_BINARY('fuzz_cli_credentials_parse_string',
+ source='fuzz_cli_credentials_parse_string.c',
+ deps='fuzzing samba-credentials 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
+# could be sent to the client or server as the stub data.
+
+def SAMBA_NDR_FUZZ(bld, interface, auto_deps=False,
+ fuzz_type=None, fuzz_function=None):
+ name = "fuzz_ndr_%s" % (interface.lower())
+ fuzz_dir = os.path.join(bld.env.srcdir, 'lib/fuzzing')
+ fuzz_reldir = os.path.relpath(fuzz_dir, bld.path.abspath())
+ fuzz_src = os.path.join(fuzz_reldir, 'fuzz_ndr_X.c')
+
+ cflags = "-D FUZZ_PIPE_TABLE=ndr_table_%s" % interface
+ if fuzz_type:
+ name += "_%s" % (fuzz_type)
+ cflags += " -D FUZZ_TYPE=%s " % (fuzz_type)
+ if fuzz_type and fuzz_function:
+ name += "_%d" % (fuzz_function)
+ cflags += " -D FUZZ_FUNCTION=%d" % (fuzz_function)
+
+ fuzz_named_src = os.path.join(fuzz_reldir,
+ '%s.c' % (name))
+ # Work around an issue that WAF is invoked from up to 3 different
+ # directories so doesn't create a unique name for the multiple .o
+ # files like it would if called from just one place.
+ bld.SAMBA_GENERATOR(fuzz_named_src,
+ source=fuzz_src,
+ target=fuzz_named_src,
+ rule='cp ${SRC} ${TGT}')
+
+ if auto_deps:
+ deps = "afl-fuzz-main talloc ndr NDR_%s" % interface.upper()
+ else:
+ deps = "afl-fuzz-main ndr-table NDR_DCERPC"
+
+ bld.SAMBA_BINARY(name, source=fuzz_named_src,
+ cflags = cflags,
+ deps = deps,
+ fuzzer=True)
+
+Build.BuildContext.SAMBA_NDR_FUZZ = SAMBA_NDR_FUZZ
+
+# fuzz_ndr_X is generated from the list if IDL fed to PIDL
+# however there are exceptions to the normal pattern
+bld.SAMBA_NDR_FUZZ('IOXIDResolver') # oxidresolver.idl
+bld.SAMBA_NDR_FUZZ('IRemoteActivation') # remact.idl
+bld.SAMBA_NDR_FUZZ('iremotewinspool') # winspool.idl
+bld.SAMBA_NDR_FUZZ('FileServerVssAgent') # fsvrp.idl
+bld.SAMBA_NDR_FUZZ('lsarpc') # lsa.idl
+bld.SAMBA_NDR_FUZZ('netdfs') # dfs.idl
+bld.SAMBA_NDR_FUZZ('nfs4acl_interface') # nfs4acl.idl
+bld.SAMBA_NDR_FUZZ('rpcecho') # echo.idl
+
+# quota.idl
+bld.SAMBA_NDR_FUZZ('file_quota')
+bld.SAMBA_NDR_FUZZ('smb2_query_quota')
+bld.SAMBA_NDR_FUZZ('smb1_nt_transact_query_quota')
+
+# ioctl.idl
+bld.SAMBA_NDR_FUZZ('copychunk')
+bld.SAMBA_NDR_FUZZ('compression')
+bld.SAMBA_NDR_FUZZ('netinterface')
+bld.SAMBA_NDR_FUZZ('sparse')
+bld.SAMBA_NDR_FUZZ('resiliency')
+bld.SAMBA_NDR_FUZZ('trim')
+
+# WMI tables
+bld.SAMBA_NDR_FUZZ('IWbemClassObject')
+bld.SAMBA_NDR_FUZZ('IWbemServices')
+bld.SAMBA_NDR_FUZZ('IEnumWbemClassObject')
+bld.SAMBA_NDR_FUZZ('IWbemContext')
+bld.SAMBA_NDR_FUZZ('IWbemLevel1Login')
+bld.SAMBA_NDR_FUZZ('IWbemWCOSmartEnum')
+bld.SAMBA_NDR_FUZZ('IWbemFetchSmartEnum')
+bld.SAMBA_NDR_FUZZ('IWbemCallResult')
+bld.SAMBA_NDR_FUZZ('IWbemObjectSink')
+
+# DCOM tables
+bld.SAMBA_NDR_FUZZ('dcom_Unknown')
+bld.SAMBA_NDR_FUZZ('IUnknown')
+bld.SAMBA_NDR_FUZZ('IClassFactory')
+bld.SAMBA_NDR_FUZZ('IRemUnknown')
+bld.SAMBA_NDR_FUZZ('IClassActivator')
+bld.SAMBA_NDR_FUZZ('ISCMLocalActivator')
+bld.SAMBA_NDR_FUZZ('IMachineLocalActivator')
+bld.SAMBA_NDR_FUZZ('ILocalObjectExporter')
+bld.SAMBA_NDR_FUZZ('ISystemActivator')
+bld.SAMBA_NDR_FUZZ('IRemUnknown2')
+bld.SAMBA_NDR_FUZZ('IDispatch')
+bld.SAMBA_NDR_FUZZ('IMarshal')
+bld.SAMBA_NDR_FUZZ('ICoffeeMachine')
+bld.SAMBA_NDR_FUZZ('IStream')
+
+# Specific struct or function on the interface
+
+bld.SAMBA_NDR_FUZZ('spoolss',
+ auto_deps=True,
+ fuzz_type="TYPE_IN",
+ fuzz_function=65)