From 8daa83a594a2e98f39d764422bfbdbc62c9efd44 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 19:20:00 +0200 Subject: Adding upstream version 2:4.20.0+dfsg. Signed-off-by: Daniel Baumann --- lib/fuzzing/patches/collect-access-check-seeds.txt | 256 +++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 lib/fuzzing/patches/collect-access-check-seeds.txt (limited to 'lib/fuzzing/patches') diff --git a/lib/fuzzing/patches/collect-access-check-seeds.txt b/lib/fuzzing/patches/collect-access-check-seeds.txt new file mode 100644 index 0000000..db85f40 --- /dev/null +++ b/lib/fuzzing/patches/collect-access-check-seeds.txt @@ -0,0 +1,256 @@ +From b461fdf28c71b54ad5ebe663ea09212856e61973 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Mon, 17 Jul 2023 16:17:16 +1200 +Subject: [PATCH 1/2] libcli/security: save access check attempts for fuzz + examples + +If this patch is applied to a Samba tree, and the +SAMBA_SAVE_ACCESS_CHECK_DIR environment variable points to a +directory, the tokens and descriptors of all access checks will be +stored in that directory in the form used by +fuzz_security_token_vs_descriptor. This can be used to build up a +corpus of seeds for the fuzzer. + +The steps to create the corpus go something like this: + +$ export SAMBA_SAVE_ACCESS_CHECK_DIR=/tmp/samba-seeds +$ mkdir $SAMBA_SAVE_ACCESS_CHECK_DIR +$ mkdir /tmp/final-seeds-go-here +$ make test + +at this point you'd want to do something like this: + +$ for f in $SAMBA_SAVE_ACCESS_CHECK_DIR/*; do \ + cp -n $f /tmp/final-seeds-go-here/$(md5sum $f | cut -d' ' -f 1) \ + done + +but it takes way too long, so use the script in the second patch in +this series, like so: + +$ script/find-unique-access-seeds \ + $SAMBA_SAVE_ACCESS_CHECK_DIR \ + /tmp/final-seeds-go-here/ + +Think before applying this patch in production. It won't slow things +down much, but it will capture your SIDs and ACLs. + +Signed-off-by: Douglas Bagnall +--- + libcli/security/access_check.c | 79 ++++++++++++++++++++++++++++++++++ + 1 file changed, 79 insertions(+) + +diff --git a/libcli/security/access_check.c b/libcli/security/access_check.c +index 1364a15f4dd..d79a247455a 100644 +--- a/libcli/security/access_check.c ++++ b/libcli/security/access_check.c +@@ -26,6 +26,8 @@ + #include "libcli/security/security.h" + #include "librpc/gen_ndr/conditional_ace.h" + #include "libcli/security/conditional_ace.h" ++#include "ndr/libndr.h" ++#include "gen_ndr/ndr_security.h" + + /* Map generic access rights to object specific rights. This technique is + used to give meaning to assigning read, write, execute and all access to +@@ -105,6 +107,77 @@ void se_map_standard(uint32_t *access_mask, const struct standard_mapping *mappi + } + } + ++ ++static bool write_token_and_descriptor(const struct security_descriptor *sd, ++ const struct security_token *token, ++ uint32_t access_desired) ++{ ++ /* ++ * You should not be seeing this function in master or a release ++ * branch! It should only be here if you have patched Samba to ++ * generate fuzz seeds for fuzz_security_token_vs_descriptor. ++ * ++ * It hooks into access_check functions, saving copies of each access ++ * request in a structure for use as a fuzz seed, into the directory ++ * specified by the SAMBA_SAVE_ACCESS_CHECK_DIR environment variable. ++ * ++ * If the environment variable is not set, nothing will happen. ++ * ++ * A full `make test` saves about four million files, but only about ++ * forty thousand of them are unique. ++ */ ++ FILE *f = NULL; ++ char buf[200]; ++ int len; ++ DATA_BLOB blob = {0}; ++ uint pid; ++ struct security_token_descriptor_fuzzing_pair p = { ++ .token = *token, ++ .sd = *sd, ++ .access_desired = access_desired ++ }; ++ static size_t n = 0; ++ enum ndr_err_code ndr_err; ++ static const char *dir = NULL; ++ TALLOC_CTX *tmp_ctx = NULL; ++ ++ if (dir == NULL) { ++ if (n == SIZE_MAX) { ++ return true; ++ } ++ dir = getenv("SAMBA_SAVE_ACCESS_CHECK_DIR"); ++ if (dir == NULL) { ++ n = SIZE_MAX; ++ return false; ++ } ++ } ++ tmp_ctx = talloc_new(NULL); ++ if (tmp_ctx == NULL) { ++ return false; ++ } ++ ++ n++; ++ ndr_err = ndr_push_struct_blob( ++ &blob, tmp_ctx, &p, ++ (ndr_push_flags_fn_t)ndr_push_security_token_descriptor_fuzzing_pair); ++ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { ++ TALLOC_FREE(tmp_ctx); ++ return false; ++ } ++ pid = getpid(); ++ len = snprintf(buf, sizeof(buf), "%s/%08u-%05zu.seed", dir, pid, n); ++ if (len >= sizeof(buf)) { ++ TALLOC_FREE(tmp_ctx); ++ return false; ++ } ++ f = fopen(buf, "w"); ++ fwrite(blob.data, 1, blob.length, f); ++ fclose(f); ++ TALLOC_FREE(tmp_ctx); ++ return true; ++} ++ ++ + /* + perform a SEC_FLAG_MAXIMUM_ALLOWED access check + */ +@@ -117,6 +190,8 @@ static uint32_t access_check_max_allowed(const struct security_descriptor *sd, + bool have_owner_rights_ace = false; + unsigned i; + ++ write_token_and_descriptor(sd, token, SEC_FLAG_MAXIMUM_ALLOWED); ++ + if (sd->dacl == NULL) { + if (security_token_has_sid(token, sd->owner_sid)) { + switch (implicit_owner_rights) { +@@ -222,6 +297,8 @@ static NTSTATUS se_access_check_implicit_owner(const struct security_descriptor + bool am_owner = false; + bool have_owner_rights_ace = false; + ++ write_token_and_descriptor(sd, token, access_desired); ++ + *access_granted = access_desired; + bits_remaining = access_desired; + +@@ -613,6 +690,8 @@ NTSTATUS sec_access_check_ds_implicit_owner(const struct security_descriptor *sd + uint32_t bits_remaining; + struct dom_sid self_sid; + ++ write_token_and_descriptor(sd, token, access_desired); ++ + dom_sid_parse(SID_NT_SELF, &self_sid); + + *access_granted = access_desired; +-- +2.34.1 + + +From 12bf242cece202658fe61f1c7408709d092632ea Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Tue, 18 Jul 2023 16:07:11 +1200 +Subject: [PATCH 2/2] scripts: a script for deduplicating fuzz-seeds + +The previous patch adds a way to collect two million fuzz seeds, only +a few thousand of which are unique. This script finds the unique ones. + +Some fuzzers like seeds to have names based on md5 hashes, so we do that. + +The naive technique takes ages. + +Signed-off-by: Douglas Bagnall +--- + script/find-unique-access-seeds | 66 +++++++++++++++++++++++++++++++++ + 1 file changed, 66 insertions(+) + create mode 100755 script/find-unique-access-seeds + +diff --git a/script/find-unique-access-seeds b/script/find-unique-access-seeds +new file mode 100755 +index 00000000000..174e811ecd0 +--- /dev/null ++++ b/script/find-unique-access-seeds +@@ -0,0 +1,66 @@ ++#!/usr/bin/env python3 ++# ++# Copyright (C) Catalyst IT Ltd. 2023 ++# ++# 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 . ++# ++"""USAGE: find-unique-access-seeds SRCDIR DESTDIR ++ ++Copy the files in SRCDIR to DESTDIR with the name set to the ++md5sum of the contents. DESTDIR will thus have no duplicates. ++ ++This is the same as going: ++ ++ for f in $SRC/*; do ++ cp $f $DEST/$(md5sum $f | cut -d' ' -f 1) ++ done ++ ++but much more efficient. ++""" ++ ++ ++import sys ++import os ++from pathlib import Path ++from hashlib import md5 ++ ++ ++def usage(ret): ++ print(__doc__) ++ exit(ret) ++ ++ ++def main(): ++ if {'-h', '--help'}.intersection(sys.argv): ++ usage(0) ++ if len(sys.argv) != 3: ++ usage(1) ++ ++ src, dest = sys.argv[1:] ++ sp = Path(src) ++ dp = Path(dest) ++ ++ strings = set() ++ ++ for filename in sp.iterdir(): ++ with open(filename, 'rb') as f: ++ strings.add(f.read()) ++ ++ for s in strings: ++ name = md5(s).hexdigest() ++ with open(dp / name, "wb") as f: ++ f.write(s) ++ ++ ++main() +-- +2.34.1 + -- cgit v1.2.3