diff --git a/MANIFEST b/MANIFEST index a27e2c76a..1e82b5130 100644 --- a/MANIFEST +++ b/MANIFEST @@ -259,6 +259,7 @@ plugins/sudoers/defaults.h plugins/sudoers/editor.c plugins/sudoers/env.c plugins/sudoers/find_path.c +plugins/sudoers/gc.c plugins/sudoers/getdate.c plugins/sudoers/getdate.y plugins/sudoers/getspwuid.c diff --git a/plugins/sudoers/Makefile.in b/plugins/sudoers/Makefile.in index 04aba2e1d..17cdbc049 100644 --- a/plugins/sudoers/Makefile.in +++ b/plugins/sudoers/Makefile.in @@ -151,7 +151,7 @@ LIBPARSESUDOERS_OBJS = alias.lo audit.lo base64.lo defaults.lo hexchar.lo \ toke_util.lo SUDOERS_OBJS = $(AUTH_OBJS) boottime.lo check.lo editor.lo env.lo find_path.lo \ - goodpath.lo group_plugin.lo interfaces.lo iolog.lo \ + gc.lo goodpath.lo group_plugin.lo interfaces.lo iolog.lo \ iolog_path.lo locale.lo logging.lo logwrap.lo parse.lo \ policy.lo prompt.lo set_perms.lo sudo_nss.lo sudoers.lo \ timestamp.lo @SUDOERS_OBJS@ @@ -666,6 +666,14 @@ fwtk.lo: $(authdir)/fwtk.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \ $(srcdir)/sudoers.h $(srcdir)/sudoers_debug.h \ $(top_builddir)/config.h $(top_builddir)/pathnames.h $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(authdir)/fwtk.c +gc.lo: $(srcdir)/gc.c $(devdir)/def_data.h $(incdir)/compat/stdbool.h \ + $(incdir)/sudo_compat.h $(incdir)/sudo_conf.h $(incdir)/sudo_debug.h \ + $(incdir)/sudo_fatal.h $(incdir)/sudo_gettext.h $(incdir)/sudo_plugin.h \ + $(incdir)/sudo_queue.h $(incdir)/sudo_util.h $(srcdir)/defaults.h \ + $(srcdir)/logging.h $(srcdir)/sudo_nss.h $(srcdir)/sudoers.h \ + $(srcdir)/sudoers_debug.h $(top_builddir)/config.h \ + $(top_builddir)/pathnames.h + $(LIBTOOL) $(LTFLAGS) --mode=compile $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(srcdir)/gc.c getdate.o: $(devdir)/getdate.c $(incdir)/sudo_compat.h $(top_builddir)/config.h $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(devdir)/getdate.c getspwuid.lo: $(srcdir)/getspwuid.c $(devdir)/def_data.h \ diff --git a/plugins/sudoers/env.c b/plugins/sudoers/env.c index a50ac8132..b0097f241 100644 --- a/plugins/sudoers/env.c +++ b/plugins/sudoers/env.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2007-2015 + * Copyright (c) 2000-2005, 2007-2016 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -412,6 +412,8 @@ sudo_setenv2(const char *var, const char *val, bool dupcheck, bool overwrite) } if (rval == -1) free(estring); + else + sudoers_gc_add(GC_PTR, estring); debug_return_int(rval); } @@ -468,6 +470,8 @@ sudo_setenv_nodebug(const char *var, const char *val, int overwrite) done: if (rval == -1) free(estring); + else + sudoers_gc_add(GC_PTR, estring); return rval; } @@ -972,6 +976,7 @@ rebuild_env(void) free(cp); goto bad; } + sudoers_gc_add(GC_PTR, cp); } } else { /* @@ -1060,6 +1065,7 @@ rebuild_env(void) free(cp); goto bad; } + sudoers_gc_add(GC_PTR, cp); } else { CHECK_SETENV2("SUDO_COMMAND", user_cmnd, true, true); } @@ -1217,6 +1223,7 @@ read_env_file(const char *path, int overwrite) memcpy(cp, var, var_len + 1); /* includes '=' */ memcpy(cp + var_len + 1, val, val_len + 1); /* includes NUL */ + sudoers_gc_add(GC_PTR, cp); if (sudo_putenv(cp, true, overwrite) == -1) { /* XXX - no undo on failure */ rval = false; diff --git a/plugins/sudoers/gc.c b/plugins/sudoers/gc.c new file mode 100644 index 000000000..eeb827997 --- /dev/null +++ b/plugins/sudoers/gc.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2016 Todd C. Miller + * + * 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 + +#include + +#include +#include + +#include "sudoers.h" + +struct sudoers_gc_entry { + SLIST_ENTRY(sudoers_gc_entry) entries; + enum sudoers_gc_types type; + union { + char **vec; + void *ptr; + } u; +}; +SLIST_HEAD(sudoers_gc_list, sudoers_gc_entry); +#ifdef NO_LEAKS +static struct sudoers_gc_list sudoers_gc_list = + SLIST_HEAD_INITIALIZER(sudoers_gc_list); +#endif + +bool +sudoers_gc_add(enum sudoers_gc_types type, void *v) +{ +#ifdef NO_LEAKS + struct sudoers_gc_entry *gc; + debug_decl(sudoers_gc_add, SUDOERS_DEBUG_UTIL) + + if (v == NULL) + debug_return_bool(false); + + gc = calloc(1, sizeof(*gc)); + if (gc == NULL) { + sudo_warnx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + debug_return_bool(false); + } + switch (type) { + case GC_PTR: + gc->u.ptr = v; + break; + case GC_VECTOR: + gc->u.vec = v; + break; + default: + free(gc); + sudo_warnx("unexpected garbage type %d", type); + debug_return_bool(false); + } + gc->type = type; + SLIST_INSERT_HEAD(&sudoers_gc_list, gc, entries); + debug_return_bool(true); +#else + return true; +#endif /* NO_LEAKS */ +} + +bool +sudoers_gc_remove(enum sudoers_gc_types type, void *v) +{ +#ifdef NO_LEAKS + struct sudoers_gc_entry *gc, *prev = NULL; + debug_decl(sudoers_gc_remove, SUDOERS_DEBUG_UTIL) + + SLIST_FOREACH(gc, &sudoers_gc_list, entries) { + switch (gc->type) { + case GC_PTR: + if (gc->u.ptr == v) + goto found; + break; + case GC_VECTOR: + if (gc->u.vec == v) + goto found; + break; + default: + sudo_warnx("unexpected garbage type %d in %p", gc->type, gc); + } + prev = gc; + } + return false; +found: + if (prev != NULL) + SLIST_REMOVE_HEAD(&sudoers_gc_list, entries); + else + SLIST_REMOVE_AFTER(prev, entries); + return true; +#else + return false; +#endif /* NO_LEAKS */ +} + +#ifdef NO_LEAKS +static void +sudoers_gc_run(void) +{ + struct sudoers_gc_entry *gc; + char **cur; + debug_decl(sudoers_gc_run, SUDOERS_DEBUG_UTIL) + + /* Collect garbage. */ + while ((gc = SLIST_FIRST(&sudoers_gc_list))) { + SLIST_REMOVE_HEAD(&sudoers_gc_list, entries); + switch (gc->type) { + case GC_PTR: + free(gc->u.ptr); + free(gc); + break; + case GC_VECTOR: + for (cur = gc->u.vec; *cur != NULL; cur++) + free(*cur); + free(gc->u.vec); + free(gc); + break; + default: + sudo_warnx("unexpected garbage type %d", gc->type); + } + } + + debug_return; +} +#endif /* NO_LEAKS */ + +void +sudoers_gc_init(void) +{ +#ifdef NO_LEAKS + atexit(sudoers_gc_run); +#endif +} diff --git a/plugins/sudoers/sudoers.h b/plugins/sudoers/sudoers.h index 6d4769688..7fda05050 100644 --- a/plugins/sudoers/sudoers.h +++ b/plugins/sudoers/sudoers.h @@ -377,4 +377,14 @@ extern const char *path_plugin_dir; char *resolve_editor(const char *ed, size_t edlen, int nfiles, char **files, int *argc_out, char ***argv_out, char * const *whitelist); +/* gc.c */ +enum sudoers_gc_types { + GC_UNKNOWN, + GC_VECTOR, + GC_PTR +}; +bool sudoers_gc_add(enum sudoers_gc_types type, void *ptr); +bool sudoers_gc_remove(enum sudoers_gc_types type, void *ptr); +void sudoers_gc_init(void); + #endif /* SUDOERS_SUDOERS_H */