Add simple fuzzer for sudo.conf parser.

This commit is contained in:
Todd C. Miller
2021-02-15 13:17:26 -07:00
parent d81d7e0cf2
commit 25f50e2f07
6 changed files with 479 additions and 2 deletions

View File

@@ -211,8 +211,12 @@ lib/util/progname.c
lib/util/pw_dup.c
lib/util/pwrite.c
lib/util/reallocarray.c
lib/util/regress/corpus/sudo_conf/sudo.conf.1
lib/util/regress/corpus/sudo_conf/sudo.conf.2
lib/util/regress/corpus/sudo_conf/sudo.conf.3
lib/util/regress/fnmatch/fnm_test.c
lib/util/regress/fnmatch/fnm_test.in
lib/util/regress/fuzz/fuzz_sudo_conf.c
lib/util/regress/getdelim/getdelim_test.c
lib/util/regress/getgrouplist/getgrouplist_test.c
lib/util/regress/glob/files

View File

@@ -109,6 +109,13 @@ TEST_PROGS = conf_test hltq_test parseln_test progname_test strsplit_test \
TEST_LIBS = @LIBS@
TEST_LDFLAGS = @LDFLAGS@
# Fuzzers
LIBFUZZSTUB = $(top_builddir)/lib/fuzzstub/libsudo_fuzzstub.la
LIB_FUZZING_ENGINE = @FUZZ_ENGINE@
FUZZ_PROGS = fuzz_sudo_conf
FUZZ_LIBS = @LIBS@ $(LIB_FUZZING_ENGINE)
FUZZ_LDFLAGS = @LDFLAGS@
# User and group ids the installed files should be "owned" by
install_uid = 0
install_gid = 0
@@ -166,6 +173,8 @@ STRSIG_TEST_OBJS = strsig_test.lo sig2str.lo str2sig.lo @SIGNAME@
VSYSLOG_TEST_OBJS = vsyslog_test.lo vsyslog.lo
FUZZ_SUDO_CONF_OBJS = fuzz_sudo_conf.lo
all: libsudo_util.la
pvs-log-files: $(POBJS)
@@ -279,6 +288,9 @@ strtoid_test: $(STRTOID_TEST_OBJS) libsudo_util.la
vsyslog_test: $(VSYSLOG_TEST_OBJS) libsudo_util.la
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(VSYSLOG_TEST_OBJS) libsudo_util.la $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(TEST_LDFLAGS) $(TEST_LIBS)
fuzz_sudo_conf: $(FUZZ_SUDO_CONF_OBJS) $(LIBFUZZSTUB) libsudo_util.la
$(LIBTOOL) $(LTFLAGS) --mode=link $(CC) -o $@ $(FUZZ_SUDO_CONF_OBJS) libsudo_util.la $(ASAN_LDFLAGS) $(PIE_LDFLAGS) $(SSP_LDFLAGS) $(FUZZ_LDFLAGS) $(FUZZ_LIBS)
pre-install:
install: install-dirs
@@ -313,10 +325,16 @@ cppcheck:
pvs-log-files: $(POBJS)
fuzz:
fuzz: $(FUZZ_PROGS)
@if test X"$(cross_compiling)" != X"yes"; then \
MALLOC_OPTIONS=S; export MALLOC_OPTIONS; \
MALLOC_CONF="abort:true,junk:true"; export MALLOC_CONF; \
echo "fuzz_sudo_conf: verifying corpus"; \
./fuzz_sudo_conf $(srcdir)/regress/corpus/sudo_conf/sudo.conf.*; \
fi
# Note: some regress checks are run from srcdir for consistent error messages
check: $(TEST_PROGS)
check: $(TEST_PROGS) fuzz
@if test X"$(cross_compiling)" != X"yes"; then \
MALLOC_OPTIONS=S; export MALLOC_OPTIONS; \
MALLOC_CONF="abort:true,junk:true"; export MALLOC_CONF; \
@@ -647,6 +665,20 @@ fstatat.i: $(srcdir)/fstatat.c $(incdir)/sudo_compat.h $(top_builddir)/config.h
$(CC) -E -o $@ $(CPPFLAGS) $<
fstatat.plog: fstatat.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/fstatat.c --i-file $< --output-file $@
fuzz_sudo_conf.lo: $(srcdir)/regress/fuzz/fuzz_sudo_conf.c \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(top_builddir)/config.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/regress/fuzz/fuzz_sudo_conf.c
fuzz_sudo_conf.i: $(srcdir)/regress/fuzz/fuzz_sudo_conf.c \
$(incdir)/compat/stdbool.h $(incdir)/sudo_compat.h \
$(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \
$(incdir)/sudo_queue.h $(incdir)/sudo_util.h \
$(top_builddir)/config.h
$(CC) -E -o $@ $(CPPFLAGS) $<
fuzz_sudo_conf.plog: fuzz_sudo_conf.i
rm -f $@; pvs-studio --cfg $(PVS_CFG) --sourcetree-root $(top_srcdir) --skip-cl-exe yes --source-file $(srcdir)/regress/fuzz/fuzz_sudo_conf.c --i-file $< --output-file $@
getaddrinfo.lo: $(srcdir)/getaddrinfo.c $(incdir)/compat/getaddrinfo.h \
$(incdir)/sudo_compat.h $(top_builddir)/config.h
$(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(ASAN_CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/getaddrinfo.c

View File

@@ -0,0 +1,124 @@
#
# Default /etc/sudo.conf file
#
# Sudo plugins:
# Plugin plugin_name plugin_path plugin_options ...
#
# The plugin_path is relative to /usr/local/libexec/sudo unless
# fully qualified.
# The plugin_name corresponds to a global symbol in the plugin
# that contains the plugin interface structure.
# The plugin_options are optional.
#
# The sudoers plugin is used by default if no Plugin lines are present.
#Plugin sudoers_policy sudoers.so
#Plugin sudoers_io sudoers.so
#Plugin sudoers_audit sudoers.so
#
# Sudo askpass:
# Path askpass /path/to/askpass
#
# An askpass helper program may be specified to provide a graphical
# password prompt for "sudo -A" support. Sudo does not ship with its
# own askpass program but can use the OpenSSH askpass.
#
# Use the OpenSSH askpass
#Path askpass /usr/X11R6/bin/ssh-askpass
#
# Use the Gnome OpenSSH askpass
#Path askpass /usr/libexec/openssh/gnome-ssh-askpass
#
# Sudo device search path:
# Path devsearch /dev/path1:/dev/path2:/dev
#
# A colon-separated list of paths to check when searching for a user's
# terminal device.
#
#Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
#
# Sudo noexec:
# Path noexec /path/to/sudo_noexec.so
#
# Path to a shared library containing replacements for the execv(),
# execve() and fexecve() library functions that just return an error.
# This is used to implement the "noexec" functionality on systems that
# support LD_PRELOAD or its equivalent.
#
# The compiled-in value is usually sufficient and should only be changed
# if you rename or move the sudo_noexec.so file.
#
#Path noexec /usr/local/libexec/sudo/sudo_noexec.so
#
# Sudo plugin directory:
# Path plugin_dir /path/to/plugins
#
# The default directory to use when searching for plugins that are
# specified without a fully qualified path name.
#
#Path plugin_dir /usr/local/libexec/sudo
#
# Sudo developer mode:
# Set developer_mode true|false
#
# Allow loading of plugins that are owned by non-root or are writable
# by "group" or "other". Should only be used during plugin development.
#Set developer_mode true
#
# Core dumps:
# Set disable_coredump true|false
#
# By default, sudo disables core dumps while it is executing (they
# are re-enabled for the command that is run).
# To aid in debugging sudo problems, you may wish to enable core
# dumps by setting "disable_coredump" to false.
#
#Set disable_coredump false
#
# User groups:
# Set group_source static|dynamic|adaptive
#
# Sudo passes the user's group list to the policy plugin.
# If the user is a member of the maximum number of groups (usually 16),
# sudo will query the group database directly to be sure to include
# the full list of groups.
#
# On some systems, this can be expensive so the behavior is configurable.
# The "group_source" setting has three possible values:
# static - use the user's list of groups returned by the kernel.
# dynamic - query the group database to find the list of groups.
# adaptive - if user is in less than the maximum number of groups.
# use the kernel list, else query the group database.
#
#Set group_source static
#
# Sudo interface probing:
# Set probe_interfaces true|false
#
# By default, sudo will probe the system's network interfaces and
# pass the IP address of each enabled interface to the policy plugin.
# On systems with a large number of virtual interfaces this may take
# a noticeable amount of time.
#
#Set probe_interfaces false
#
# Sudo debug files:
# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
#
# Sudo and related programs support logging debug information to a file.
# The program is typically sudo, sudoers.so, sudoreplay or visudo.
#
# Subsystems vary based on the program; "all" matches all subsystems.
# Priority may be crit, err, warn, notice, diag, info, trace or debug.
# Multiple subsystem@priority may be specified, separated by a comma.
#
#Debug sudo /var/log/sudo_debug all@debug
#Debug sudoers.so /var/log/sudoers_debug all@debug

View File

@@ -0,0 +1,124 @@
#
# Default /etc/sudo.conf file
#
# Sudo plugins:
# Plugin plugin_name plugin_path plugin_options ...
#
# The plugin_path is relative to /usr/local/libexec/sudo unless
# fully qualified.
# The plugin_name corresponds to a global symbol in the plugin
# that contains the plugin interface structure.
# The plugin_options are optional.
#
# The sudoers plugin is used by default if no Plugin lines are present.
Plugin sudoers_policy sudoers.so
Plugin sudoers_io sudoers.so
Plugin sudoers_audit sudoers.so
#
# Sudo askpass:
# Path askpass /path/to/askpass
#
# An askpass helper program may be specified to provide a graphical
# password prompt for "sudo -A" support. Sudo does not ship with its
# own askpass program but can use the OpenSSH askpass.
#
# Use the OpenSSH askpass
Path askpass /usr/X11R6/bin/ssh-askpass
#
# Use the Gnome OpenSSH askpass
Path askpass /usr/libexec/openssh/gnome-ssh-askpass
#
# Sudo device search path:
# Path devsearch /dev/path1:/dev/path2:/dev
#
# A colon-separated list of paths to check when searching for a user's
# terminal device.
#
Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
#
# Sudo noexec:
# Path noexec /path/to/sudo_noexec.so
#
# Path to a shared library containing replacements for the execv(),
# execve() and fexecve() library functions that just return an error.
# This is used to implement the "noexec" functionality on systems that
# support LD_PRELOAD or its equivalent.
#
# The compiled-in value is usually sufficient and should only be changed
# if you rename or move the sudo_noexec.so file.
#
Path noexec /usr/local/libexec/sudo/sudo_noexec.so
#
# Sudo plugin directory:
# Path plugin_dir /path/to/plugins
#
# The default directory to use when searching for plugins that are
# specified without a fully qualified path name.
#
Path plugin_dir /usr/local/libexec/sudo
#
# Sudo developer mode:
# Set developer_mode true|false
#
# Allow loading of plugins that are owned by non-root or are writable
# by "group" or "other". Should only be used during plugin development.
Set developer_mode true
#
# Core dumps:
# Set disable_coredump true|false
#
# By default, sudo disables core dumps while it is executing (they
# are re-enabled for the command that is run).
# To aid in debugging sudo problems, you may wish to enable core
# dumps by setting "disable_coredump" to false.
#
Set disable_coredump false
#
# User groups:
# Set group_source static|dynamic|adaptive
#
# Sudo passes the user's group list to the policy plugin.
# If the user is a member of the maximum number of groups (usually 16),
# sudo will query the group database directly to be sure to include
# the full list of groups.
#
# On some systems, this can be expensive so the behavior is configurable.
# The "group_source" setting has three possible values:
# static - use the user's list of groups returned by the kernel.
# dynamic - query the group database to find the list of groups.
# adaptive - if user is in less than the maximum number of groups.
# use the kernel list, else query the group database.
#
Set group_source static
#
# Sudo interface probing:
# Set probe_interfaces true|false
#
# By default, sudo will probe the system's network interfaces and
# pass the IP address of each enabled interface to the policy plugin.
# On systems with a large number of virtual interfaces this may take
# a noticeable amount of time.
#
Set probe_interfaces false
#
# Sudo debug files:
# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
#
# Sudo and related programs support logging debug information to a file.
# The program is typically sudo, sudoers.so, sudoreplay or visudo.
#
# Subsystems vary based on the program; "all" matches all subsystems.
# Priority may be crit, err, warn, notice, diag, info, trace or debug.
# Multiple subsystem@priority may be specified, separated by a comma.
#
Debug sudo /var/log/sudo_debug all@debug
Debug sudoers.so /var/log/sudoers_debug all@debug

View File

@@ -0,0 +1,134 @@
#
# Default /etc/sudo.conf file
#
# Sudo plugins:
# Plugin plugin_name plugin_path plugin_options ...
#
# The plugin_path is relative to /usr/local/libexec/sudo unless
# fully qualified.
# The plugin_name corresponds to a global symbol in the plugin
# that contains the plugin interface structure.
# The plugin_options are optional.
#
# The sudoers plugin is used by default if no Plugin lines are present.
Plugin sudoers_policy sudoers.so
Plugin sudoers_io sudoers.so
Plugin sudoers_audit sudoers.so
#
# Sudo askpass:
# Path askpass /path/to/askpass
#
# An askpass helper program may be specified to provide a graphical
# password prompt for "sudo -A" support. Sudo does not ship with its
# own askpass program but can use the OpenSSH askpass.
#
# Use the OpenSSH askpass
Path askpass /usr/X11R6/bin/ssh-askpass
#
# Use the Gnome OpenSSH askpass
Path askpass /usr/libexec/openssh/gnome-ssh-askpass
#
# Sudo device search path:
# Path devsearch /dev/path1:/dev/path2:/dev
#
# A colon-separated list of paths to check when searching for a user's
# terminal device.
#
Path devsearch /dev/pts:/dev/vt:/dev/term:/dev/zcons:/dev/pty:/dev
#
# Sudo noexec:
# Path noexec /path/to/sudo_noexec.so
#
# Path to a shared library containing replacements for the execv(),
# execve() and fexecve() library functions that just return an error.
# This is used to implement the "noexec" functionality on systems that
# support LD_PRELOAD or its equivalent.
#
# The compiled-in value is usually sufficient and should only be changed
# if you rename or move the sudo_noexec.so file.
#
Path noexec /usr/local/libexec/sudo/sudo_noexec.so
#
# Sudo plugin directory:
# Path plugin_dir /path/to/plugins
#
# The default directory to use when searching for plugins that are
# specified without a fully qualified path name.
#
Path plugin_dir /usr/local/libexec/sudo
#
# Path to the sesh binary for SELinux support
#
Path sesh /usr/local/libexec/sudo/sesh
#
# Sudo developer mode:
# Set developer_mode true|false
#
# Allow loading of plugins that are owned by non-root or are writable
# by "group" or "other". Should only be used during plugin development.
Set developer_mode true
#
# Core dumps:
# Set disable_coredump true|false
#
# By default, sudo disables core dumps while it is executing (they
# are re-enabled for the command that is run).
# To aid in debugging sudo problems, you may wish to enable core
# dumps by setting "disable_coredump" to false.
#
Set disable_coredump true
#
# User groups:
# Set group_source static|dynamic|adaptive
#
# Sudo passes the user's group list to the policy plugin.
# If the user is a member of the maximum number of groups (usually 16),
# sudo will query the group database directly to be sure to include
# the full list of groups.
#
# On some systems, this can be expensive so the behavior is configurable.
# The "group_source" setting has three possible values:
# static - use the user's list of groups returned by the kernel.
# dynamic - query the group database to find the list of groups.
# adaptive - if user is in less than the maximum number of groups.
# use the kernel list, else query the group database.
#
Set group_source dynamic
#
# Maximum number of groups to use
#
Set max_groups 8
#
# Sudo interface probing:
# Set probe_interfaces true|false
#
# By default, sudo will probe the system's network interfaces and
# pass the IP address of each enabled interface to the policy plugin.
# On systems with a large number of virtual interfaces this may take
# a noticeable amount of time.
#
Set probe_interfaces true
#
# Sudo debug files:
# Debug program /path/to/debug_log subsystem@priority[,subsyste@priority]
#
# Sudo and related programs support logging debug information to a file.
# The program is typically sudo, sudoers.so, sudoreplay or visudo.
#
# Subsystems vary based on the program; "all" matches all subsystems.
# Priority may be crit, err, warn, notice, diag, info, trace or debug.
# Multiple subsystem@priority may be specified, separated by a comma.
#
Debug sudo /var/log/sudo_debug all@debug
Debug sudoers.so /var/log/sudoers_debug all@debug

View File

@@ -0,0 +1,59 @@
/*
* 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 "sudo_compat.h"
#include "sudo_conf.h"
#include "sudo_debug.h"
#include "sudo_util.h"
int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
char tempfile[] = "/tmp/sudo_conf.XXXXXX";
size_t nwritten;
int fd;
/* sudo_conf_read() uses a conf file path, not an open file. */
fd = mkstemp(tempfile);
if (fd == -1)
return 0;
nwritten = write(fd, data, size);
if (nwritten != size) {
close(fd);
return 0;
}
close(fd);
/* sudo_conf_read() will re-init and free old data each time it runs. */
sudo_conf_clear_paths();
sudo_conf_read(tempfile, SUDO_CONF_ALL);
unlink(tempfile);
return 0;
}