mirror of
https://github.com/samba-team/samba.git
synced 2024-12-22 13:34:15 +03:00
c6a62d69ca
The token has more stuff in it. Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
207 lines
5.1 KiB
C
207 lines
5.1 KiB
C
/*
|
|
Fuzz access check using SDDL strings and a known token
|
|
Copyright (C) Catalyst IT 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "replace.h"
|
|
#include "libcli/security/security.h"
|
|
#include "libcli/security/conditional_ace.h"
|
|
#include "libcli/security/claims-conversions.h"
|
|
#include "lib/util/attr.h"
|
|
#include "librpc/gen_ndr/ndr_security.h"
|
|
#include "librpc/gen_ndr/ndr_conditional_ace.h"
|
|
#include "lib/util/bytearray.h"
|
|
#include "fuzzing/fuzzing.h"
|
|
|
|
|
|
static struct security_token token = {0};
|
|
|
|
static struct dom_sid dom_sid = {0};
|
|
|
|
/*
|
|
* For this one we initialise a security token to have a few claims
|
|
* and SIDs. The fuzz strings contain SDDL that will be tested against
|
|
* this token in se_access_check() or sec_access_check_ds() --
|
|
* supposing they compile.
|
|
*/
|
|
|
|
int LLVMFuzzerInitialize(int *argc, char ***argv)
|
|
{
|
|
size_t i;
|
|
TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
|
struct dom_sid *sid = NULL;
|
|
|
|
struct claim_def {
|
|
const char *type;
|
|
const char *name;
|
|
const char *claim_sddl;
|
|
} claims[] = {
|
|
{
|
|
"user",
|
|
"shoe size",
|
|
"44"
|
|
},
|
|
{
|
|
"user",
|
|
"©",
|
|
"{\"unknown\", \"\", \" ←ā\"}"
|
|
},
|
|
{
|
|
"device",
|
|
"©",
|
|
"{\"unknown\", \" \", \" ←ā\"}"
|
|
},
|
|
{
|
|
"device",
|
|
"least favourite groups",
|
|
"{SID(S-1-1-0),SID(S-1-5-3),SID(S-1-57777-333-33-33-2)}"
|
|
},
|
|
{
|
|
"local",
|
|
"birds",
|
|
"{\"tern\"}"
|
|
},
|
|
};
|
|
|
|
const char * device_sids[] = {
|
|
"S-1-1-0",
|
|
"S-1-333-66",
|
|
"S-1-2-3-4-5-6-7-8-9",
|
|
};
|
|
const char * user_sids[] = {
|
|
"S-1-333-66",
|
|
"S-1-16-8448",
|
|
"S-1-9-8-7",
|
|
};
|
|
|
|
for (i = 0; i < ARRAY_SIZE(user_sids); i++) {
|
|
sid = sddl_decode_sid(mem_ctx, &user_sids[i], NULL);
|
|
if (sid == NULL) {
|
|
abort();
|
|
}
|
|
add_sid_to_array(mem_ctx, sid,
|
|
&token.sids,
|
|
&token.num_sids);
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(device_sids); i++) {
|
|
sid = sddl_decode_sid(mem_ctx, &device_sids[i], NULL);
|
|
if (sid == NULL) {
|
|
abort();
|
|
}
|
|
add_sid_to_array(mem_ctx, sid,
|
|
&token.device_sids,
|
|
&token.num_device_sids);
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(claims); i++) {
|
|
struct CLAIM_SECURITY_ATTRIBUTE_RELATIVE_V1 *claim = NULL;
|
|
struct claim_def c = claims[i];
|
|
|
|
claim = parse_sddl_literal_as_claim(mem_ctx,
|
|
c.name,
|
|
c.claim_sddl);
|
|
if (claim == NULL) {
|
|
abort();
|
|
}
|
|
add_claim_to_token(mem_ctx, &token, claim, c.type);
|
|
}
|
|
|
|
/* we also need a global domain SID */
|
|
string_to_sid(&dom_sid, device_sids[2]);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int LLVMFuzzerTestOneInput(const uint8_t *input, size_t len)
|
|
{
|
|
TALLOC_CTX *mem_ctx = NULL;
|
|
struct security_descriptor *sd = NULL;
|
|
uint32_t access_desired;
|
|
uint32_t access_granted;
|
|
const char *sddl;
|
|
ssize_t i;
|
|
if (len < 5) {
|
|
return 0;
|
|
}
|
|
access_desired = PULL_LE_U32(input + len - 4, 0);
|
|
|
|
/*
|
|
* check there is a '\0'.
|
|
*
|
|
* Note this allows double-dealing for the last 4 bytes: they are used
|
|
* as the access_desired mask (see just above) but also *could* be
|
|
* part of the sddl string. But this doesn't matter, for three
|
|
* reasons:
|
|
*
|
|
* 1. the desired access mask doesn't usually matter much.
|
|
*
|
|
* 2. the final '\0' is rarely the operative one. Usually the
|
|
* effective string ends a long time before the end of the input, and
|
|
* the tail is just junk that comes along for the ride.
|
|
*
|
|
* 3. Even if there is a case where the end of the SDDL is part of the
|
|
* mask, the evolution strategy is very likely to try a different mask,
|
|
* because it likes to add junk on the end.
|
|
*
|
|
* But still, you ask, WHY? So that the seeds from here can be shared
|
|
* back and forth with the fuzz_sddl_parse seeds, which have the same
|
|
* form of a null-terminated-string-with-trailing-junk. If we started
|
|
* the loop at `len - 5` instead of `len - 1`, there might be
|
|
* interesting seeds that are valid there that would fail here. That's
|
|
* all.
|
|
*/
|
|
for (i = len - 1; i >= 0; i--) {
|
|
if (input[i] == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (i < 0) {
|
|
return 0;
|
|
}
|
|
|
|
sddl = (const char *)input;
|
|
mem_ctx = talloc_new(NULL);
|
|
|
|
sd = sddl_decode(mem_ctx, sddl, &dom_sid);
|
|
if (sd == NULL) {
|
|
goto end;
|
|
}
|
|
|
|
#ifdef FUZZ_SEC_ACCESS_CHECK_DS
|
|
/*
|
|
* The sec_access_check_ds() function has two arguments not found in
|
|
* se_access_check, and also not found in our fuzzing examples.
|
|
*
|
|
* One is a struct object_tree, which is used for object ACE types.
|
|
* The other is a SID, which is used as a default if an ACE lacks a
|
|
* SID.
|
|
*/
|
|
sec_access_check_ds(sd,
|
|
&token,
|
|
access_desired,
|
|
&access_granted,
|
|
NULL,
|
|
NULL);
|
|
#else
|
|
se_access_check(sd, &token, access_desired, &access_granted);
|
|
#endif
|
|
|
|
end:
|
|
talloc_free(mem_ctx);
|
|
return 0;
|
|
}
|