krb5 commit: Add OSS-Fuzz target for ccache marshalling
[email protected] Sat, 13 Jun 2026 02:55:11 -0400 (EDT)
| Newsgroups | gmane.comp.encryption.kerberos.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://github.com/krb5/krb5/commit/63b55949eff0ac47202d3d717d5b68ebad2fc6b1 commit 63b55949eff0ac47202d3d717d5b68ebad2fc6b1 Author: Arthur Chan <[email protected]> Date: Thu Jun 11 12:49:35 2026 +0100 Add OSS-Fuzz target for ccache marshalling .gitignore | 1 + src/tests/fuzzing/Makefile.in | 6 + src/tests/fuzzing/deps | 10 ++ src/tests/fuzzing/fuzz_ccache.c | 133 +++++++++++++++++++++ .../fuzz_ccache_seed_corpus/v1_principal_only | Bin 0 -> 27 bytes .../fuzz_ccache_seed_corpus/v4_principal_only | Bin 0 -> 29 bytes src/tests/fuzzing/oss-fuzz.sh | 9 +- 7 files changed, 155 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index d4e978349..c7e18066a 100644 --- a/.gitignore +++ b/.gitignore @@ -437,6 +437,7 @@ local.properties /src/tests/fuzzing/fuzz_aes /src/tests/fuzzing/fuzz_asn /src/tests/fuzzing/fuzz_attrset +/src/tests/fuzzing/fuzz_ccache /src/tests/fuzzing/fuzz_chpw /src/tests/fuzzing/fuzz_crypto /src/tests/fuzzing/fuzz_des diff --git a/src/tests/fuzzing/Makefile.in b/src/tests/fuzzing/Makefile.in index 15bbbbf1a..d6aafc17b 100644 --- a/src/tests/fuzzing/Makefile.in +++ b/src/tests/fuzzing/Makefile.in @@ -11,6 +11,7 @@ OBJS= \ fuzz_aes.o \ fuzz_asn.o \ fuzz_attrset.o \ + fuzz_ccache.o \ fuzz_chpw.o \ fuzz_crypto.o \ fuzz_des.o \ @@ -32,6 +33,7 @@ SRCS= \ $(srcdir)/fuzz_aes.c \ $(srcdir)/fuzz_asn.c \ $(srcdir)/fuzz_attrset.c \ + $(srcdir)/fuzz_ccache.c \ $(srcdir)/fuzz_chpw.c \ $(srcdir)/fuzz_crypto.c \ $(srcdir)/fuzz_des.c \ @@ -53,6 +55,7 @@ FUZZ_TARGETS= \ fuzz_aes \ fuzz_asn \ fuzz_attrset \ + fuzz_ccache \ fuzz_chpw \ fuzz_crypto \ fuzz_des \ @@ -84,6 +87,9 @@ fuzz_asn: fuzz_asn.o $(KRB5_BASE_DEPLIBS) fuzz_attrset: fuzz_attrset.o $(KRB5_BASE_DEPLIBS) $(CXX_LINK) -o $@ fuzz_attrset.o -lkrad $(KRB5_BASE_LIBS) $(FUZZ_LDFLAGS) +fuzz_ccache: fuzz_ccache.o $(KRB5_BASE_DEPLIBS) + $(CXX_LINK) -o $@ fuzz_ccache.o $(KRB5_BASE_LIBS) $(FUZZ_LDFLAGS) + fuzz_chpw: fuzz_chpw.o $(KRB5_BASE_DEPLIBS) $(CXX_LINK) -o $@ fuzz_chpw.o $(KRB5_BASE_LIBS) $(FUZZ_LDFLAGS) diff --git a/src/tests/fuzzing/deps b/src/tests/fuzzing/deps index fbd77e8ea..539d4fd2e 100644 --- a/src/tests/fuzzing/deps +++ b/src/tests/fuzzing/deps @@ -35,6 +35,16 @@ $(OUTPRE)fuzz_attrset.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \ $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ fuzz_attrset.c +$(OUTPRE)fuzz_ccache.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ + $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ + $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ + $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \ + $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \ + $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \ + $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \ + $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \ + $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \ + $(top_srcdir)/include/socket-utils.h fuzz_ccache.c $(OUTPRE)fuzz_chpw.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \ diff --git a/src/tests/fuzzing/fuzz_ccache.c b/src/tests/fuzzing/fuzz_ccache.c new file mode 100644 index 000000000..ae79d4087 --- /dev/null +++ b/src/tests/fuzzing/fuzz_ccache.c @@ -0,0 +1,133 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* tests/fuzzing/fuzz_ccache.c - fuzzing harness for the FILE ccache parser */ +/* + * Copyright (C) 2026 by Arthur Chan. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This harness fuzzes the FILE credential cache parser in + * lib/krb5/ccache/cc_file.c. The fuzz input is written verbatim to a + * temporary file, which is then resolved as a "FILE:" ccache and read back; + * then the cache's default principal is fetched and its credentials are + * iterated to drive the parser (version, header, principal and credential + * unmarshalling). + */ + +#include <k5-int.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define kMinInputLength 2 +#define kMaxInputLength 4096 + +extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +/* krb5_init_context is expensive, so create the context once and reuse it. */ +static krb5_context +get_context(void) +{ + static krb5_context context = NULL; + static int initialized = 0; + + if (!initialized) { + initialized = 1; + if (krb5_init_context(&context) != 0) + context = NULL; + } + return context; +} + +/* Iterate over every credential in the cache to exercise the parser. */ +static void +iterate_creds(krb5_context context, krb5_ccache ccache) +{ + krb5_error_code ret; + krb5_cc_cursor cursor; + krb5_creds cred; + + ret = krb5_cc_start_seq_get(context, ccache, &cursor); + if (ret) + return; + + while (krb5_cc_next_cred(context, ccache, &cursor, &cred) == 0) + krb5_free_cred_contents(context, &cred); + + krb5_cc_end_seq_get(context, ccache, &cursor); +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + krb5_error_code ret; + krb5_context context; + krb5_ccache ccache; + krb5_principal princ; + char tmpl[] = "/tmp/fuzz_ccache.XXXXXX"; + char name[64]; + int fd; + + if (size < kMinInputLength || size > kMaxInputLength) + return 0; + + context = get_context(); + if (context == NULL) + return 0; + + /* Write the fuzz input to a temporary file. */ + fd = mkstemp(tmpl); + if (fd < 0) + return 0; + if (write(fd, data, size) != (ssize_t)size) { + close(fd); + unlink(tmpl); + return 0; + } + close(fd); + + snprintf(name, sizeof(name), "FILE:%s", tmpl); + + ret = krb5_cc_resolve(context, name, &ccache); + if (ret) { + unlink(tmpl); + return 0; + } + + /* Fetch the default principal, then walk the credentials. */ + ret = krb5_cc_get_principal(context, ccache, &princ); + if (!ret) + krb5_free_principal(context, princ); + + iterate_creds(context, ccache); + + krb5_cc_close(context, ccache); + unlink(tmpl); + + return 0; +} diff --git a/src/tests/fuzzing/fuzz_ccache_seed_corpus/v1_principal_only b/src/tests/fuzzing/fuzz_ccache_seed_corpus/v1_principal_only new file mode 100644 index 000000000..dab7e2fa6 Binary files /dev/null and b/src/tests/fuzzing/fuzz_ccache_seed_corpus/v1_principal_only differ diff --git a/src/tests/fuzzing/fuzz_ccache_seed_corpus/v4_principal_only b/src/tests/fuzzing/fuzz_ccache_seed_corpus/v4_principal_only new file mode 100644 index 000000000..6dde9d673 Binary files /dev/null and b/src/tests/fuzzing/fuzz_ccache_seed_corpus/v4_principal_only differ diff --git a/src/tests/fuzzing/oss-fuzz.sh b/src/tests/fuzzing/oss-fuzz.sh index b01d4bcbd..313adfc53 100644 --- a/src/tests/fuzzing/oss-fuzz.sh +++ b/src/tests/fuzzing/oss-fuzz.sh @@ -15,10 +15,11 @@ popd # Copy fuzz targets and seed corpus to $OUT. pushd src/tests/fuzzing -fuzzers=("fuzz_aes" "fuzz_asn" "fuzz_attrset" "fuzz_chpw" "fuzz_crypto" - "fuzz_des" "fuzz_gss" "fuzz_json" "fuzz_kdc" "fuzz_krad" "fuzz_krb" - "fuzz_krb5_ticket" "fuzz_marshal_cred" "fuzz_marshal_princ" - "fuzz_ndr" "fuzz_oid" "fuzz_pac" "fuzz_profile" "fuzz_util") +fuzzers=("fuzz_aes" "fuzz_asn" "fuzz_attrset" "fuzz_ccache" "fuzz_chpw" + "fuzz_crypto" "fuzz_des" "fuzz_gss" "fuzz_json" "fuzz_kdc" + "fuzz_krad" "fuzz_krb" "fuzz_krb5_ticket" "fuzz_marshal_cred" + "fuzz_marshal_princ" "fuzz_ndr" "fuzz_oid" "fuzz_pac" "fuzz_profile" + "fuzz_util") for fuzzer in "${fuzzers[@]}"; do cp "$fuzzer" "$OUT/$fuzzer"