diff options
Diffstat (limited to 'plugins/sudoers/regress/fuzz/fuzz_sudoers_ldif.c')
-rw-r--r-- | plugins/sudoers/regress/fuzz/fuzz_sudoers_ldif.c | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/plugins/sudoers/regress/fuzz/fuzz_sudoers_ldif.c b/plugins/sudoers/regress/fuzz/fuzz_sudoers_ldif.c new file mode 100644 index 0000000..f3a28a4 --- /dev/null +++ b/plugins/sudoers/regress/fuzz/fuzz_sudoers_ldif.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2021 Todd C. Miller <Todd.Miller@sudo.ws> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> +#if defined(HAVE_STDINT_H) +# include <stdint.h> +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#endif + +#include "sudoers.h" + +static int fuzz_printf(int msg_type, const char *fmt, ...); +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +/* Required to link with parser. */ +struct sudo_user sudo_user; +struct passwd *list_pw; +sudo_printf_t sudo_printf = fuzz_printf; + +FILE * +open_sudoers(const char *file, bool doedit, bool *keepopen) +{ + /* + * If we allow the fuzzer to choose include paths it will + * include random files in the file system. + * This leads to bug reports that cannot be reproduced. + */ + return NULL; +} + +static int +fuzz_printf(int msg_type, const char *fmt, ...) +{ + return 0; +} + +bool +init_envtables(void) +{ + return true; +} + +int +set_cmnd_path(const char *runchroot) +{ + /* Cannot return FOUND without also setting user_cmnd to a new value. */ + return NOT_FOUND; +} + +static FILE * +open_data(const uint8_t *data, size_t size) +{ +#ifdef HAVE_FMEMOPEN + /* Operate in-memory. */ + return fmemopen((void *)data, size, "r"); +#else + char tempfile[] = "/tmp/ldif.XXXXXX"; + size_t nwritten; + int fd; + + /* Use (unlinked) temporary file. */ + fd = mkstemp(tempfile); + if (fd == -1) + return NULL; + unlink(tempfile); + nwritten = write(fd, data, size); + if (nwritten != size) { + close(fd); + return NULL; + } + lseek(fd, 0, SEEK_SET); + return fdopen(fd, "r"); +#endif +} + +static int +fuzz_conversation(int num_msgs, const struct sudo_conv_message msgs[], + struct sudo_conv_reply replies[], struct sudo_conv_callback *callback) +{ + int n; + + for (n = 0; n < num_msgs; n++) { + const struct sudo_conv_message *msg = &msgs[n]; + + switch (msg->msg_type & 0xff) { + case SUDO_CONV_PROMPT_ECHO_ON: + case SUDO_CONV_PROMPT_MASK: + case SUDO_CONV_PROMPT_ECHO_OFF: + /* input not supported */ + return -1; + case SUDO_CONV_ERROR_MSG: + case SUDO_CONV_INFO_MSG: + /* no output for fuzzers */ + break; + default: + return -1; + } + } + return 0; +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + struct sudoers_parse_tree parse_tree; + FILE *fp; + + /* Don't waste time fuzzing tiny inputs. */ + if (size < 5) + return 0; + + fp = open_data(data, size); + if (fp == NULL) + return 0; + + initprogname("fuzz_sudoers_ldif"); + sudoers_debug_register(getprogname(), NULL); + if (getenv("SUDO_FUZZ_VERBOSE") == NULL) + sudo_warn_set_conversation(fuzz_conversation); + + /* Initialize defaults and parse LDIF-format sudoers. */ + init_defaults(); + init_parse_tree(&parse_tree, NULL, NULL); + sudoers_parse_ldif(&parse_tree, fp, "ou=SUDOers,dc=sudo,dc=ws", true); + + /* Cleanup. */ + free_parse_tree(&parse_tree); + fclose(fp); + sudoers_debug_deregister(); + fflush(stdout); + + return 0; +} |