From: Todd C. Miller Date: Thu, 6 Oct 2016 02:21:18 +0000 (-0600) Subject: Wrap wordexp(3) in sudo_noexec. X-Git-Tag: SUDO_1_8_18p1^2~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d0ccd947d0745ebf097dd38850ad880df88f4292;p=sudo Wrap wordexp(3) in sudo_noexec. --- diff --git a/aclocal.m4 b/aclocal.m4 index ed555540b..c2591690e 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -13,7 +13,7 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) # longlong.m4 serial 17 -dnl Copyright (C) 1999-2007, 2009-2015 Free Software Foundation, Inc. +dnl Copyright (C) 1999-2007, 2009-2016 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. diff --git a/config.h.in b/config.h.in index f9d63a5d5..3ca005678 100644 --- a/config.h.in +++ b/config.h.in @@ -838,6 +838,12 @@ /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF +/* Define to 1 if you have the `wordexp' function. */ +#undef HAVE_WORDEXP + +/* Define to 1 if you have the header file. */ +#undef HAVE_WORDEXP_H + /* Define to 1 if you have the header file. */ #undef HAVE_ZLIB_H diff --git a/configure b/configure index d753be4ef..576ca1028 100755 --- a/configure +++ b/configure @@ -2648,6 +2648,7 @@ as_fn_append ac_header_list " netgroup.h" as_fn_append ac_header_list " paths.h" as_fn_append ac_header_list " spawn.h" as_fn_append ac_header_list " utmpx.h" +as_fn_append ac_header_list " wordexp.h" as_fn_append ac_header_list " sys/sockio.h" as_fn_append ac_header_list " sys/bsdtypes.h" as_fn_append ac_header_list " sys/select.h" @@ -2661,6 +2662,7 @@ as_fn_append ac_func_list " pread" as_fn_append ac_func_list " pwrite" as_fn_append ac_func_list " openat" as_fn_append ac_func_list " faccessat" +as_fn_append ac_func_list " wordexp" as_fn_append ac_func_list " seteuid" # Check that the precious variables saved in the cache have kept the same # value. @@ -16813,6 +16815,8 @@ done + + for ac_header in endian.h sys/endian.h machine/endian.h @@ -18072,6 +18076,8 @@ done + + case "$host_os" in hpux*) if test X"$ac_cv_func_pread" = X"yes"; then diff --git a/configure.ac b/configure.ac index 9feddfdd9..2479b54dc 100644 --- a/configure.ac +++ b/configure.ac @@ -2261,7 +2261,7 @@ AC_HEADER_DIRENT AC_HEADER_TIME AC_HEADER_STDBOOL AC_HEADER_MAJOR -AC_CHECK_HEADERS_ONCE([netgroup.h paths.h spawn.h utmpx.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h]) +AC_CHECK_HEADERS_ONCE([netgroup.h paths.h spawn.h utmpx.h wordexp.h sys/sockio.h sys/bsdtypes.h sys/select.h sys/stropts.h sys/sysmacros.h]) AC_CHECK_HEADERS([endian.h] [sys/endian.h] [machine/endian.h], [break]) AC_CHECK_HEADERS([procfs.h] [sys/procfs.h], [AC_CHECK_MEMBERS(struct psinfo.pr_ttydev, [AC_CHECK_FUNCS([_ttyname_dev])], [], [AC_INCLUDES_DEFAULT #ifdef HAVE_PROCFS_H @@ -2400,7 +2400,7 @@ dnl dnl Function checks dnl AC_FUNC_GETGROUPS -AC_CHECK_FUNCS_ONCE([fexecve killpg nl_langinfo strftime pread pwrite openat faccessat]) +AC_CHECK_FUNCS_ONCE([fexecve killpg nl_langinfo strftime pread pwrite openat faccessat wordexp]) case "$host_os" in hpux*) if test X"$ac_cv_func_pread" = X"yes"; then diff --git a/src/sudo_noexec.c b/src/sudo_noexec.c index 91bc994d3..43392da68 100644 --- a/src/sudo_noexec.c +++ b/src/sudo_noexec.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005, 2010-2015 Todd C. Miller + * Copyright (c) 2004-2005, 2010-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 @@ -26,8 +26,23 @@ #ifdef HAVE_SPAWN_H #include #endif +#ifdef HAVE_STRING_H +# include +#endif /* HAVE_STRING_H */ +#ifdef HAVE_STRINGS_H +# include +#endif /* HAVE_STRINGS_H */ +#ifdef HAVE_WORDEXP_H +#include +#endif +#if defined(HAVE_SHL_LOAD) +# include +#elif defined(HAVE_DLOPEN) +# include +#endif #include "sudo_compat.h" +#include "pathnames.h" #ifdef HAVE___INTERPOSE /* @@ -141,3 +156,51 @@ FN_NAME(popen)(const char *c, const char *t) return NULL; } INTERPOSE(popen) + +/* + * We can't use a wrapper for wordexp(3) since we still want to call + * the real wordexp(3) but with WRDE_NOCMD added to the flags argument. + */ +typedef int (*sudo_fn_wordexp_t)(const char *, wordexp_t *, int); + +__dso_public int +FN_NAME(wordexp)(const char *words, wordexp_t *we, int flags) +{ +#if defined(HAVE___INTERPOSE) + return wordexp(words, we, flags | WRDE_NOCMD); +#else +# if defined(HAVE_DLOPEN) + void *fn = dlsym(RTLD_NEXT, "wordexp"); +# elif defined(HAVE_SHL_LOAD) + const char *name, *myname = _PATH_SUDO_NOEXEC; + struct shl_descriptor *desc; + void *fn = NULL; + int idx = 0; + + name = strrchr(myname, '/'); + if (name != NULL) + myname = name + 1; + + /* Search for wordexp() but skip this shared object. */ + while (shl_get(idx++, &desc) == 0) { + name = strrchr(desc->filename, '/'); + if (name == NULL) + name = desc->filename; + else + name++; + if (strcmp(name, myname) == 0) + continue; + if (shl_findsym(&desc->handle, "wordexp", TYPE_PROCEDURE, &fn) == 0) + break; + } +# else + void *fn = NULL; +# endif + if (fn == NULL) { + errno = EACCES; + return -1; + } + return ((sudo_fn_wordexp_t)fn)(words, we, flags | WRDE_NOCMD); +#endif /* HAVE___INTERPOSE */ +} +INTERPOSE(wordexp)