1 From b461fdf28c71b54ad5ebe663ea09212856e61973 Mon Sep 17 00:00:00 2001
2 From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
3 Date: Mon, 17 Jul 2023 16:17:16 +1200
4 Subject: [PATCH 1/2] libcli/security: save access check attempts for fuzz
7 If this patch is applied to a Samba tree, and the
8 SAMBA_SAVE_ACCESS_CHECK_DIR environment variable points to a
9 directory, the tokens and descriptors of all access checks will be
10 stored in that directory in the form used by
11 fuzz_security_token_vs_descriptor. This can be used to build up a
12 corpus of seeds for the fuzzer.
14 The steps to create the corpus go something like this:
16 $ export SAMBA_SAVE_ACCESS_CHECK_DIR=/tmp/samba-seeds
17 $ mkdir $SAMBA_SAVE_ACCESS_CHECK_DIR
18 $ mkdir /tmp/final-seeds-go-here
21 at this point you'd want to do something like this:
23 $ for f in $SAMBA_SAVE_ACCESS_CHECK_DIR/*; do \
24 cp -n $f /tmp/final-seeds-go-here/$(md5sum $f | cut -d' ' -f 1) \
27 but it takes way too long, so use the script in the second patch in
30 $ script/find-unique-access-seeds \
31 $SAMBA_SAVE_ACCESS_CHECK_DIR \
32 /tmp/final-seeds-go-here/
34 Think before applying this patch in production. It won't slow things
35 down much, but it will capture your SIDs and ACLs.
37 Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
39 libcli/security/access_check.c | 79 ++++++++++++++++++++++++++++++++++
40 1 file changed, 79 insertions(+)
42 diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c
43 index 1364a15f4dd..d79a247455a 100644
44 --- a/libcli/security/access_check.c
45 +++ b/libcli/security/access_check.c
47 #include "libcli/security/security.h"
48 #include "librpc/gen_ndr/conditional_ace.h"
49 #include "libcli/security/conditional_ace.h"
50 +#include "ndr/libndr.h"
51 +#include "gen_ndr/ndr_security.h"
53 /* Map generic access rights to object specific rights. This technique is
54 used to give meaning to assigning read, write, execute and all access to
55 @@ -105,6 +107,77 @@ void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mappi
60 +static bool write_token_and_descriptor(const struct security_descriptor *sd,
61 + const struct security_token *token,
62 + uint32_t access_desired)
65 + * You should not be seeing this function in master or a release
66 + * branch! It should only be here if you have patched Samba to
67 + * generate fuzz seeds for fuzz_security_token_vs_descriptor.
69 + * It hooks into access_check functions, saving copies of each access
70 + * request in a structure for use as a fuzz seed, into the directory
71 + * specified by the SAMBA_SAVE_ACCESS_CHECK_DIR environment variable.
73 + * If the environment variable is not set, nothing will happen.
75 + * A full `make test` saves about four million files, but only about
76 + * forty thousand of them are unique.
81 + DATA_BLOB blob = {0};
83 + struct security_token_descriptor_fuzzing_pair p = {
86 + .access_desired = access_desired
88 + static size_t n = 0;
89 + enum ndr_err_code ndr_err;
90 + static const char *dir = NULL;
91 + TALLOC_CTX *tmp_ctx = NULL;
94 + if (n == SIZE_MAX) {
97 + dir = getenv("SAMBA_SAVE_ACCESS_CHECK_DIR");
103 + tmp_ctx = talloc_new(NULL);
104 + if (tmp_ctx == NULL) {
109 + ndr_err = ndr_push_struct_blob(
110 + &blob, tmp_ctx, &p,
111 + (ndr_push_flags_fn_t)ndr_push_security_token_descriptor_fuzzing_pair);
112 + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
113 + TALLOC_FREE(tmp_ctx);
117 + len = snprintf(buf, sizeof(buf), "%s/%08u-%05zu.seed", dir, pid, n);
118 + if (len >= sizeof(buf)) {
119 + TALLOC_FREE(tmp_ctx);
122 + f = fopen(buf, "w");
123 + fwrite(blob.data, 1, blob.length, f);
125 + TALLOC_FREE(tmp_ctx);
131 perform a SEC_FLAG_MAXIMUM_ALLOWED access check
133 @@ -117,6 +190,8 @@ static uint32_t access_check_max_allowed(const struct security_descriptor *sd,
134 bool have_owner_rights_ace = false;
137 + write_token_and_descriptor(sd, token, SEC_FLAG_MAXIMUM_ALLOWED);
139 if (sd->dacl == NULL) {
140 if (security_token_has_sid(token, sd->owner_sid)) {
141 switch (implicit_owner_rights) {
142 @@ -222,6 +297,8 @@ static NTSTATUS se_access_check_implicit_owner(const struct security_descriptor
143 bool am_owner = false;
144 bool have_owner_rights_ace = false;
146 + write_token_and_descriptor(sd, token, access_desired);
148 *access_granted = access_desired;
149 bits_remaining = access_desired;
151 @@ -613,6 +690,8 @@ NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd
152 uint32_t bits_remaining;
153 struct dom_sid self_sid;
155 + write_token_and_descriptor(sd, token, access_desired);
157 dom_sid_parse(SID_NT_SELF, &self_sid);
159 *access_granted = access_desired;
164 From 12bf242cece202658fe61f1c7408709d092632ea Mon Sep 17 00:00:00 2001
165 From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
166 Date: Tue, 18 Jul 2023 16:07:11 +1200
167 Subject: [PATCH 2/2] scripts: a script for deduplicating fuzz-seeds
169 The previous patch adds a way to collect two million fuzz seeds, only
170 a few thousand of which are unique. This script finds the unique ones.
172 Some fuzzers like seeds to have names based on md5 hashes, so we do that.
174 The naive technique takes ages.
176 Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
178 script/find-unique-access-seeds | 66 +++++++++++++++++++++++++++++++++
179 1 file changed, 66 insertions(+)
180 create mode 100755 script/find-unique-access-seeds
182 diff --git a/script/find-unique-access-seeds b/script/find-unique-access-seeds
184 index 00000000000..174e811ecd0
186 +++ b/script/find-unique-access-seeds
188 +#!/usr/bin/env python3
190 +# Copyright (C) Catalyst IT Ltd. 2023
192 +# This program is free software; you can redistribute it and/or modify
193 +# it under the terms of the GNU General Public License as published by
194 +# the Free Software Foundation; either version 3 of the License, or
195 +# (at your option) any later version.
197 +# This program is distributed in the hope that it will be useful,
198 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
199 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
200 +# GNU General Public License for more details.
202 +# You should have received a copy of the GNU General Public License
203 +# along with this program. If not, see <http://www.gnu.org/licenses/>.
205 +"""USAGE: find-unique-access-seeds SRCDIR DESTDIR
207 +Copy the files in SRCDIR to DESTDIR with the name set to the
208 +md5sum of the contents. DESTDIR will thus have no duplicates.
210 +This is the same as going:
212 + for f in $SRC/*; do
213 + cp $f $DEST/$(md5sum $f | cut -d' ' -f 1)
216 +but much more efficient.
222 +from pathlib import Path
223 +from hashlib import md5
232 + if {'-h', '--help'}.intersection(sys.argv):
234 + if len(sys.argv) != 3:
237 + src, dest = sys.argv[1:]
243 + for filename in sp.iterdir():
244 + with open(filename, 'rb') as f:
245 + strings.add(f.read())
248 + name = md5(s).hexdigest()
249 + with open(dp / name, "wb") as f: