From 22f4f10a3a6e40245b5444ea2eb0893122696f1f Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" <Todd.Miller@courtesan.com> Date: Tue, 21 Feb 2012 13:26:02 -0500 Subject: [PATCH] Check for LD_PRELOAD variants in configure instead of checkign cpp symbols. In disable_execute(), compute the length of the new envp and allocate it once instead of reallocating on demand. Also append old value of LD_PRELOAD (if any) to the new value. --- config.h.in | 13 +++++++ configure | 50 ++++++++++++++++++++++++++ configure.in | 44 +++++++++++++++++++++++ src/exec_common.c | 89 +++++++++++++++++++++++++---------------------- 4 files changed, 155 insertions(+), 41 deletions(-) diff --git a/config.h.in b/config.h.in index bab0510c1..277b018f2 100644 --- a/config.h.in +++ b/config.h.in @@ -745,6 +745,19 @@ /* The syslog priority sudo will use for successful attempts. */ #undef PRI_SUCCESS +/* The default value of preloaded objects (if any). */ +#undef RTLD_PRELOAD_DEFAULT + +/* The delimiter to use when defining multiple preloaded objects. */ +#undef RTLD_PRELOAD_DELIM + +/* An extra environment variable that is required to enable preloading (if + any). */ +#undef RTLD_PRELOAD_ENABLE_VAR + +/* The environment variable that controls preloading of dynamic objects. */ +#undef RTLD_PRELOAD_VAR + /* The user sudo should run commands as by default. */ #undef RUNAS_DEFAULT diff --git a/configure b/configure index d6a578a49..513129acd 100755 --- a/configure +++ b/configure @@ -2946,6 +2946,11 @@ shadow_libs= shadow_libs_optional= CONFIGURE_ARGS="$@" +RTLD_PRELOAD_VAR="LD_PRELOAD" +RTLD_PRELOAD_ENABLE_VAR= +RTLD_PRELOAD_DELIM=":" +RTLD_PRELOAD_DEFAULT= + @@ -13728,6 +13733,9 @@ fi case "$host" in *-*-sunos4*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # getcwd(3) opens a pipe to getpwd(1)!?! BROKEN_GETCWD=1 @@ -13739,6 +13747,9 @@ case "$host" in shadow_funcs="getpwanam issecure" ;; *-*-solaris2*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # To get the crypt(3) prototype (so we pass -Wall) OSDEFS="${OSDEFS} -D__EXTENSIONS__" # AFS support needs -lucb @@ -13855,6 +13866,8 @@ done # LDR_PRELOAD is only supported in AIX 5.3 and later if test $OSMAJOR -lt 5; then with_noexec=no + else + RTLD_PRELOAD_VAR="LDR_PRELOAD" fi # AIX-specific functions @@ -14056,6 +14069,9 @@ $as_echo "yes, fixing locally" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='8'} : ${mansectform='4'} ;; @@ -14122,6 +14138,9 @@ if test "x$ac_cv_lib_sun_getpwnam" = xyes; then : fi fi + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='1m'} : ${mansectform='4'} ;; @@ -14313,11 +14332,15 @@ done CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" : ${with_logincap='yes'} + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-nextstep*) # lockf() on is broken on the NeXT -- use flock instead ac_cv_func_lockf=no ac_cv_func_flock=yes + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-*sysv4*) : ${mansectsu='1m'} @@ -14333,6 +14356,29 @@ done ;; esac +if test -n "$with_noexec"; then + cat >>confdefs.h <<EOF +#define RTLD_PRELOAD_VAR "$RTLD_PRELOAD_VAR" +EOF + + cat >>confdefs.h <<EOF +#define RTLD_PRELOAD_DELIM "$RTLD_PRELOAD_DELIM" +EOF + + if test -n "$RTLD_PRELOAD_DEFAULT"; then + cat >>confdefs.h <<EOF +#define RTLD_PRELOAD_DEFAULT "$RTLD_PRELOAD_DEFAULT" +EOF + + fi + if test -n "$RTLD_PRELOAD_ENABLE_VAR"; then + cat >>confdefs.h <<EOF +#define RTLD_PRELOAD_ENABLE_VAR "$RTLD_PRELOAD_ENABLE_VAR" +EOF + + fi +fi + AUTH_REG=${AUTH_REG# } AUTH_EXCL=${AUTH_EXCL# } if test -n "$AUTH_EXCL"; then @@ -22313,6 +22359,10 @@ fi + + + + diff --git a/configure.in b/configure.in index 5893b7da6..56e1b6042 100644 --- a/configure.in +++ b/configure.in @@ -184,6 +184,14 @@ shadow_libs= shadow_libs_optional= CONFIGURE_ARGS="$@" +dnl +dnl LD_PRELOAD equivalents +dnl +RTLD_PRELOAD_VAR="LD_PRELOAD" +RTLD_PRELOAD_ENABLE_VAR= +RTLD_PRELOAD_DELIM=":" +RTLD_PRELOAD_DEFAULT= + dnl dnl libc replacement functions live in compat dnl @@ -1465,6 +1473,9 @@ fi case "$host" in *-*-sunos4*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # getcwd(3) opens a pipe to getpwd(1)!?! BROKEN_GETCWD=1 @@ -1476,6 +1487,9 @@ case "$host" in shadow_funcs="getpwanam issecure" ;; *-*-solaris2*) + # LD_PRELOAD is space-delimited + RTLD_PRELOAD_DELIM=" " + # To get the crypt(3) prototype (so we pass -Wall) OSDEFS="${OSDEFS} -D__EXTENSIONS__" # AFS support needs -lucb @@ -1538,6 +1552,8 @@ case "$host" in # LDR_PRELOAD is only supported in AIX 5.3 and later if test $OSMAJOR -lt 5; then with_noexec=no + else + RTLD_PRELOAD_VAR="LDR_PRELOAD" fi # AIX-specific functions @@ -1671,6 +1687,9 @@ case "$host" in ]], [[exit(0);]])], [AC_MSG_RESULT(no)], [AC_MSG_RESULT([yes, fixing locally]) sed 's:<acl.h>:<sys/acl.h>:g' < /usr/include/prot.h > prot.h ]) + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='8'} : ${mansectform='4'} ;; @@ -1698,6 +1717,9 @@ case "$host" in if test "$OSMAJOR" -le 4; then AC_CHECK_LIB(sun, getpwnam, [LIBS="${LIBS} -lsun"]) fi + # ":DEFAULT" must be appended to _RLD_LIST + RTLD_PRELOAD_VAR="_RLD_LIST" + RTLD_PRELOAD_DEFAULT="DEFAULT" : ${mansectsu='1m'} : ${mansectform='4'} ;; @@ -1840,11 +1862,15 @@ case "$host" in CHECKSHADOW="false" test -z "$with_pam" && AUTH_EXCL_DEF="PAM" : ${with_logincap='yes'} + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-nextstep*) # lockf() on is broken on the NeXT -- use flock instead ac_cv_func_lockf=no ac_cv_func_flock=yes + RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES" + RTLD_PRELOAD_ENABLE_VAR="DYLD_FORCE_FLAT_NAMESPACE" ;; *-*-*sysv4*) : ${mansectsu='1m'} @@ -1860,6 +1886,20 @@ case "$host" in ;; esac +dnl +dnl Library preloading to support NOEXEC +dnl +if test -n "$with_noexec"; then + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_VAR, "$RTLD_PRELOAD_VAR") + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_DELIM, "$RTLD_PRELOAD_DELIM") + if test -n "$RTLD_PRELOAD_DEFAULT"; then + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_DEFAULT, "$RTLD_PRELOAD_DEFAULT") + fi + if test -n "$RTLD_PRELOAD_ENABLE_VAR"; then + SUDO_DEFINE_UNQUOTED(RTLD_PRELOAD_ENABLE_VAR, "$RTLD_PRELOAD_ENABLE_VAR") + fi +fi + dnl dnl Check for mixing mutually exclusive and regular auth methods dnl @@ -3308,6 +3348,10 @@ AH_TEMPLATE(HAVE_STRUCT_UTMP_UT_EXIT, [Define to 1 if `ut_exit' is a member of ` AH_TEMPLATE(HAVE_STRUCT_UTMPX_UT_EXIT, [Define to 1 if `ut_exit' is a member of `struct utmpx'.]) AH_TEMPLATE(HAVE___FUNC__, [Define to 1 if the compiler supports the C99 __func__ variable.]) AH_TEMPLATE(SUDO_KRB5_INSTANCE, [An instance string to append to the username (separated by a slash) for Kerberos V authentication]) +AH_TEMPLATE(RTLD_PRELOAD_VAR, [The environment variable that controls preloading of dynamic objects.]) +AH_TEMPLATE(RTLD_PRELOAD_ENABLE_VAR, [An extra environment variable that is required to enable preloading (if any).]) +AH_TEMPLATE(RTLD_PRELOAD_DELIM, [The delimiter to use when defining multiple preloaded objects.]) +AH_TEMPLATE(RTLD_PRELOAD_DEFAULT, [The default value of preloaded objects (if any).]) dnl dnl Bits to copy verbatim into config.h.in diff --git a/src/exec_common.c b/src/exec_common.c index 389aa5c64..a4cd5400b 100644 --- a/src/exec_common.c +++ b/src/exec_common.c @@ -53,9 +53,12 @@ static char * const * disable_execute(char *const envp[]) { #ifdef _PATH_SUDO_NOEXEC - char * const *ev; - char *preload, **nenvp; - int env_len = 0, env_size = 128; + char *preload, **nenvp = NULL; + int env_len, env_size; + int preload_idx = -1; +# ifdef RTLD_PRELOAD_ENABLE_VAR + bool enabled = false; +# endif #endif /* _PATH_SUDO_NOEXEC */ debug_decl(disable_execute, SUDO_DEBUG_UTIL) @@ -67,55 +70,59 @@ disable_execute(char *const envp[]) #endif /* HAVE_PRIV_SET */ #ifdef _PATH_SUDO_NOEXEC - nenvp = emalloc2(env_size, sizeof(char *)); - /* * Preload a noexec file. For a list of LD_PRELOAD-alikes, see * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html * XXX - need to support 32-bit and 64-bit variants */ -# if defined(__darwin__) || defined(__APPLE__) - nenvp[env_len++] = "DYLD_FORCE_FLAT_NAMESPACE="; - preload = fmt_string("DYLD_INSERT_LIBRARIES", sudo_conf_noexec_path()); -# elif defined(__osf__) || defined(__sgi) - easprintf(&preload, "_RLD_LIST=%s:DEFAULT", sudo_conf_noexec_path()); -# elif defined(_AIX) - preload = fmt_string("LDR_PRELOAD", sudo_conf_noexec_path()); -# else - preload = fmt_string("LD_PRELOAD", sudo_conf_noexec_path()); -# endif - if (preload == NULL) - errorx(1, _("unable to allocate memory")); - nenvp[env_len++] = preload; - for (ev = envp; *ev != NULL; ev++) { - /* - * Prune out existing preloaded libraries. - * XXX - should append to new value instead. - */ -# if defined(__darwin__) || defined(__APPLE__) - if (strncmp(*ev, "DYLD_INSERT_LIBRARIES=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0) - continue; - if (strncmp(*ev, "DYLD_FORCE_FLAT_NAMESPACE=", sizeof("DYLD_INSERT_LIBRARIES=") - 1) == 0) + /* Count entries in envp, looking for LD_PRELOAD as we go. */ + for (env_len = 0; envp[env_len] != NULL; env_len++) { + if (strncmp(envp[env_len], RTLD_PRELOAD_VAR "=", sizeof(RTLD_PRELOAD_VAR)) == 0) { + preload_idx = env_len; continue; -# elif defined(__osf__) || defined(__sgi) - if (strncmp(*ev, "_RLD_LIST=", sizeof("_RLD_LIST=") - 1) == 0) - continue; -# elif defined(_AIX) - if (strncmp(*ev, "LDR_PRELOAD=", sizeof("LDR_PRELOAD=") - 1) == 0) - continue; -# else - if (strncmp(*ev, "LD_PRELOAD=", sizeof("LD_PRELOAD=") - 1) == 0) + } +#ifdef RTLD_PRELOAD_ENABLE_VAR + if (strncmp(envp[env_len], RTLD_PRELOAD_ENABLE_VAR "=", sizeof(RTLD_PRELOAD_ENABLE_VAR)) == 0) { + enabled = true; continue; -# endif - /* Need at least 2 slots for current element and a NULL. */ - if (env_len + 2 > env_size) { - env_size += 128; - nenvp = erealloc3(nenvp, env_size, sizeof(char *)); } - nenvp[env_len++] = *ev; +#endif } + + /* Make a new copy of envp as needed. */ + env_size = env_len + 1 + (preload_idx == -1); +#ifdef RTLD_PRELOAD_ENABLE_VAR + if (!enabled) + env_size++; +#endif + nenvp = emalloc2(env_size, sizeof(*envp)); + memcpy(nenvp, envp, env_len * sizeof(*envp)); nenvp[env_len] = NULL; + + /* Prepend our LD_PRELOAD to existing value or add new entry at the end. */ + if (preload_idx == -1) { +# ifdef RTLD_PRELOAD_DEFAULT + easprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR, sudo_conf_noexec_path(), RTLD_PRELOAD_DELIM, RTLD_PRELOAD_DEFAULT); +# else + preload = fmt_string(RTLD_PRELOAD_VAR, sudo_conf_noexec_path()); +# endif + if (preload == NULL) + errorx(1, _("unable to allocate memory")); + nenvp[env_len++] = preload; + nenvp[env_len] = NULL; + } else { + easprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR, sudo_conf_noexec_path(), RTLD_PRELOAD_DELIM, nenvp[preload_idx]); + nenvp[preload_idx] = preload; + } +# ifdef RTLD_PRELOAD_ENABLE_VAR + if (!enabled) { + nenvp[env_len++] = RTLD_PRELOAD_ENABLE_VAR "="; + nenvp[env_len] = NULL; + } +# endif + + /* Install new env pointer. */ envp = nenvp; #endif /* _PATH_SUDO_NOEXEC */ -- 2.40.0