summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Bagnall <douglas.bagnall@catalyst.net.nz>2019-10-31 16:28:28 +1300
committerAndrew Bartlett <abartlet@samba.org>2019-12-10 07:50:28 +0000
commit7b265830ad6796dbbe721f7abfd62a19c2185b65 (patch)
tree86dea325c0e73ef5765b6768a1a8bfade35602d2
parentef5d79e24ba8aec226419e594de0cf91c24d7fc4 (diff)
downloadsamba-7b265830ad6796dbbe721f7abfd62a19c2185b65.tar.gz
lib/fuzzing: add fuzz_ndr_X
This NDR fuzzer links with each "interface" in the IDL files to create avsingle binary. This tries to matches what the fuzzing engines desire. It started as a copy of ndrdump but very little of that remains in place. The fancy build rules try to avoid needing a lof of boilerplate in the wscript_build files and ensure new fuzzers are generated and run when new IDL is added automatically. Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Signed-off-by: Andrew Bartlett <abartlet@samba.org> Pair-programmed-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
-rw-r--r--buildtools/wafsamba/samba_pidl.py12
-rw-r--r--buildtools/wafsamba/wscript2
-rw-r--r--lib/fuzzing/fuzz_ndr_X.c291
-rw-r--r--lib/fuzzing/wscript_build80
-rw-r--r--librpc/idl/wscript_build72
-rw-r--r--pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm25
-rw-r--r--wscript_build6
7 files changed, 471 insertions, 17 deletions
diff --git a/buildtools/wafsamba/samba_pidl.py b/buildtools/wafsamba/samba_pidl.py
index a34c871d183..8785563e5e6 100644
--- a/buildtools/wafsamba/samba_pidl.py
+++ b/buildtools/wafsamba/samba_pidl.py
@@ -108,14 +108,22 @@ def SAMBA_PIDL(bld, pname, source,
t.more_includes = '#' + bld.path.path_from(bld.srcnode)
Build.BuildContext.SAMBA_PIDL = SAMBA_PIDL
-
def SAMBA_PIDL_LIST(bld, name, source,
options='',
output_dir='.',
- generate_tables=True):
+ generate_tables=True,
+ generate_fuzzers=True):
'''A wrapper for building a set of IDL files'''
for p in TO_LIST(source):
bld.SAMBA_PIDL(name, p, options=options, output_dir=output_dir, generate_tables=generate_tables)
+
+ # Some IDL files don't exactly match between name and
+ # "interface" so we need a way to skip those, while other IDL
+ # files have the table generation skipped entirely, on which
+ # the fuzzers rely
+ if generate_tables and generate_fuzzers:
+ interface = p[0:-4] # strip off the .idl suffix
+ bld.SAMBA_NDR_FUZZ(interface)
Build.BuildContext.SAMBA_PIDL_LIST = SAMBA_PIDL_LIST
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
index b9f2f495617..764e357cc87 100644
--- a/buildtools/wafsamba/wscript
+++ b/buildtools/wafsamba/wscript
@@ -605,7 +605,7 @@ struct foo bar = { .y = 'X', .x = 1 };
conf.env.enable_libfuzzer = Options.options.enable_libfuzzer
if conf.env.enable_libfuzzer:
- conf.DEFINE('ENABLE_LIBFUZZER', 1)
+ conf.DEFINE('FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION', 1)
conf.env.FUZZ_TARGET_LDFLAGS = Options.options.FUZZ_TARGET_LDFLAGS
conf.load('clang_compilation_database')
diff --git a/lib/fuzzing/fuzz_ndr_X.c b/lib/fuzzing/fuzz_ndr_X.c
new file mode 100644
index 00000000000..8c9e5721739
--- /dev/null
+++ b/lib/fuzzing/fuzz_ndr_X.c
@@ -0,0 +1,291 @@
+/*
+ Unix SMB/CIFS implementation.
+ SMB torture tester
+ 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;
+
+ 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;
+
+ 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;
+ }
+ ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
+
+ 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;
+}
diff --git a/lib/fuzzing/wscript_build b/lib/fuzzing/wscript_build
index 386145c43b2..25cdcd323bf 100644
--- a/lib/fuzzing/wscript_build
+++ b/lib/fuzzing/wscript_build
@@ -1,5 +1,7 @@
#!/usr/bin/env python
+from waflib import Build
+
bld.SAMBA_SUBSYSTEM('fuzzing',
source='fuzzing.c',
deps='talloc',
@@ -40,3 +42,81 @@ bld.SAMBA_BINARY('fuzz_ldb_parse_tree',
source='fuzz_ldb_parse_tree.c',
deps='fuzzing ldb',
fuzzer=True)
+
+def SAMBA_NDR_FUZZ(bld, interface):
+ 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')
+ fuzz_named_src = os.path.join(fuzz_reldir,
+ 'fuzz_ndr_%s.c' % interface.lower())
+
+ # 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}')
+
+ bld.SAMBA_BINARY(name, source=fuzz_named_src,
+ cflags = "-D FUZZ_PIPE_TABLE=ndr_table_%s" % interface,
+ deps = "ndr-table NDR_DCERPC",
+ install=False,
+ 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('ObjectRpcBaseTypes') # orpc.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')
+
+# Skipped: dsbackup (all todo)
+
+# 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')
diff --git a/librpc/idl/wscript_build b/librpc/idl/wscript_build
index c9b19c4aac4..5dda944ca71 100644
--- a/librpc/idl/wscript_build
+++ b/librpc/idl/wscript_build
@@ -5,16 +5,26 @@ bld.SAMBA_PIDL_LIST('PIDL',
eventlog.idl
browser.idl dssetup.idl frsapi.idl
spoolss.idl
- dnsserver.idl echo.idl lsa.idl
+ dnsserver.idl
samr.idl srvsvc.idl winreg.idl
mgmt.idl netlogon.idl
svcctl.idl wkssvc.idl eventlog6.idl backupkey.idl
- fsrvp.idl witness.idl clusapi.idl
- mdssvc.idl
- winspool.idl''',
+ witness.idl clusapi.idl
+ mdssvc.idl''',
options='--header --ndr-parser --samba3-ndr-server --server --client --python',
output_dir='../gen_ndr')
+# The interface names here are not the same as the IDL name, so the
+# auto-genration of the fuzzer fails to link
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''echo.idl
+ fsrvp.idl
+ lsa.idl
+ winspool.idl''',
+ options='--header --ndr-parser --samba3-ndr-server --server --client --python',
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+
# Services that we only have a client for
bld.SAMBA_PIDL_LIST('PIDL',
'''atsvc.idl''',
@@ -23,26 +33,42 @@ bld.SAMBA_PIDL_LIST('PIDL',
# Services that we only have a server in the source3 style
bld.SAMBA_PIDL_LIST('PIDL',
- '''dfs.idl initshutdown.idl ntsvcs.idl''',
+ '''initshutdown.idl ntsvcs.idl''',
options='--header --ndr-parser --client --python --samba3-ndr-server',
output_dir='../gen_ndr')
-# Services that we only have a server in the source4 style
+# The interface names here are not the same as the IDL name, so the
+# auto-genration of the fuzzer fails to link
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''dfs.idl''',
+ options='--header --ndr-parser --client --python --samba3-ndr-server',
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+
+# Services that we only have a server in the source4 style.
+
bld.SAMBA_PIDL_LIST('PIDL',
'''unixinfo.idl''',
options='--header --ndr-parser --client --python --server',
output_dir='../gen_ndr')
# DCOM stuff
+
+# The interface names here are not the same as the IDL name, so the
+# auto-genration of the fuzzer fails to link
bld.SAMBA_PIDL_LIST('PIDL',
'''oxidresolver.idl remact.idl''',
options='--header --ndr-parser --client',
- output_dir='../gen_ndr')
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+# The interface names here are not the same as the IDL name, so the
+# auto-genration of the fuzzer fails to link
bld.SAMBA_PIDL_LIST('PIDL',
'wmi.idl dcom.idl',
options='--header --ndr-parser --server --client --dcom-proxy --com-header',
- output_dir='../gen_ndr')
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
# DCE/RPC protocols which Samba does not implement a client or server
# for
@@ -50,13 +76,11 @@ bld.SAMBA_PIDL_LIST('PIDL',
bld.SAMBA_PIDL_LIST('PIDL',
'''
audiosrv.idl
- dsbackup.idl
efs.idl
frstrans.idl
frsrpc.idl
keysvc.idl
msgsvc.idl
- orpc.idl
policyagent.idl
rot.idl
scerpc.idl
@@ -67,6 +91,18 @@ bld.SAMBA_PIDL_LIST('PIDL',
options='--header --ndr-parser',
output_dir='../gen_ndr')
+# The interface names here are not the same as the IDL name, so the
+# auto-genration of the fuzzer fails to link
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''
+ dsbackup.idl
+ orpc.idl
+ ''',
+ options='--header --ndr-parser',
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+
# Non-DCE/RPC protocols encoded in IDL for Samba or helper IDLs for
# DCE/RPC protocols (eg defining constands or structures but not
# functions)
@@ -78,14 +114,11 @@ bld.SAMBA_PIDL_LIST('PIDL',
file_id.idl
fscc.idl
fsrvp_state.idl
- ioctl.idl
named_pipe_auth.idl
negoex.idl
- nfs4acl.idl
notify.idl
ntprinting.idl
printcap.idl
- quota.idl
rap.idl
schannel.idl
smb2_lease_struct.idl
@@ -93,6 +126,19 @@ bld.SAMBA_PIDL_LIST('PIDL',
options='--header --ndr-parser',
output_dir='../gen_ndr')
+# The interface names here are not the same as the IDL name, so the
+# auto-genration of the fuzzer fails to link
+
+bld.SAMBA_PIDL_LIST('PIDL',
+ '''
+ ioctl.idl
+ nfs4acl.idl
+ quota.idl
+ ''',
+ options='--header --ndr-parser',
+ output_dir='../gen_ndr',
+ generate_fuzzers=False)
+
# Non-DCE/RPC protocls with Python bindings
# (for structures or constants)
diff --git a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
index 94428ec2037..91b5f942994 100644
--- a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
+++ b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
@@ -2604,6 +2604,31 @@ sub ParseFunctionPull($$)
$self->pidl("if (flags & NDR_OUT) {");
$self->indent;
+ $self->pidl("#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION");
+
+ # This for fuzzers of ndr_pull where the out elements refer to
+ # in elements in size_is or length_is.
+ #
+ # Not actually very harmful but also not useful outsie a fuzzer
+ foreach my $e (@{$fn->{ELEMENTS}}) {
+ next unless (grep(/in/, @{$e->{DIRECTION}}));
+ next unless ($e->{LEVELS}[0]->{TYPE} eq "POINTER" and
+ $e->{LEVELS}[0]->{POINTER_TYPE} eq "ref");
+ next if (($e->{LEVELS}[1]->{TYPE} eq "DATA") and
+ ($e->{LEVELS}[1]->{DATA_TYPE} eq "string"));
+ next if ($e->{LEVELS}[1]->{TYPE} eq "PIPE");
+ next if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY");
+
+ $self->pidl("if (r->in.$e->{NAME} == NULL) {");
+ $self->indent;
+ $self->pidl("NDR_PULL_ALLOC($ndr, r->in.$e->{NAME});");
+ $self->pidl("NDR_ZERO_STRUCTP(r->in.$e->{NAME});");
+ $self->deindent;
+ $self->pidl("}");
+ }
+
+ $self->pidl("#endif /* FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION */");
+
$env = GenerateFunctionOutEnv($fn);
foreach my $e (@{$fn->{ELEMENTS}}) {
next unless grep(/out/, @{$e->{DIRECTION}});
diff --git a/wscript_build b/wscript_build
index f9e033c0dab..b2e32987acb 100644
--- a/wscript_build
+++ b/wscript_build
@@ -38,6 +38,11 @@ bld.CONFIGURE_FILE('docs-xml/build/DTD/samba.build.version',
DOC_VERSION=bld.env.DOC_VERSION)
bld.RECURSE('docs-xml')
+# This needs to be earlier than anything containing IDL
+# That in turn allows the build rules for fuzz_ndr_X to be
+# near the code
+bld.RECURSE('lib/fuzzing')
+
bld.RECURSE('lib/replace')
bld.RECURSE('lib/socket')
bld.RECURSE('lib/talloc')
@@ -150,7 +155,6 @@ bld.RECURSE('dfs_server')
bld.RECURSE('file_server')
bld.RECURSE('lib/krb5_wrap')
bld.RECURSE('packaging')
-bld.RECURSE('lib/fuzzing')
bld.RECURSE('testsuite/headers')