Annotation of embedaddon/sudo/src/exec_common.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 2009-2012 Todd C. Miller <Todd.Miller@courtesan.com>
! 3: *
! 4: * Permission to use, copy, modify, and distribute this software for any
! 5: * purpose with or without fee is hereby granted, provided that the above
! 6: * copyright notice and this permission notice appear in all copies.
! 7: *
! 8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 15: */
! 16:
! 17: #include <config.h>
! 18:
! 19: #include <sys/types.h>
! 20: #include <sys/param.h>
! 21: #include <stdio.h>
! 22: #ifdef STDC_HEADERS
! 23: # include <stdlib.h>
! 24: # include <stddef.h>
! 25: #else
! 26: # ifdef HAVE_STDLIB_H
! 27: # include <stdlib.h>
! 28: # endif
! 29: #endif /* STDC_HEADERS */
! 30: #ifdef HAVE_STRING_H
! 31: # include <string.h>
! 32: #endif /* HAVE_STRING_H */
! 33: #ifdef HAVE_STRINGS_H
! 34: # include <strings.h>
! 35: #endif /* HAVE_STRINGS_H */
! 36: #ifdef HAVE_UNISTD_H
! 37: # include <unistd.h>
! 38: #endif /* HAVE_UNISTD_H */
! 39: #ifdef HAVE_PRIV_SET
! 40: # include <priv.h>
! 41: #endif
! 42: #include <errno.h>
! 43:
! 44: #include "sudo.h"
! 45: #include "sudo_exec.h"
! 46:
! 47: /*
! 48: * Disable execution of child processes in the command we are about
! 49: * to run. On systems with privilege sets, we can remove the exec
! 50: * privilege. On other systems we use LD_PRELOAD and the like.
! 51: */
! 52: static char * const *
! 53: disable_execute(char *const envp[])
! 54: {
! 55: #ifdef _PATH_SUDO_NOEXEC
! 56: char *preload, **nenvp = NULL;
! 57: int env_len, env_size;
! 58: int preload_idx = -1;
! 59: # ifdef RTLD_PRELOAD_ENABLE_VAR
! 60: bool enabled = false;
! 61: # endif
! 62: #endif /* _PATH_SUDO_NOEXEC */
! 63: debug_decl(disable_execute, SUDO_DEBUG_UTIL)
! 64:
! 65: #ifdef HAVE_PRIV_SET
! 66: /* Solaris privileges, remove PRIV_PROC_EXEC post-execve. */
! 67: if (priv_set(PRIV_OFF, PRIV_LIMIT, "PRIV_PROC_EXEC", NULL) == 0)
! 68: debug_return_ptr(envp);
! 69: warning(_("unable to remove PRIV_PROC_EXEC from PRIV_LIMIT"));
! 70: #endif /* HAVE_PRIV_SET */
! 71:
! 72: #ifdef _PATH_SUDO_NOEXEC
! 73: /*
! 74: * Preload a noexec file. For a list of LD_PRELOAD-alikes, see
! 75: * http://www.fortran-2000.com/ArnaudRecipes/sharedlib.html
! 76: * XXX - need to support 32-bit and 64-bit variants
! 77: */
! 78:
! 79: /* Count entries in envp, looking for LD_PRELOAD as we go. */
! 80: for (env_len = 0; envp[env_len] != NULL; env_len++) {
! 81: if (strncmp(envp[env_len], RTLD_PRELOAD_VAR "=", sizeof(RTLD_PRELOAD_VAR)) == 0) {
! 82: preload_idx = env_len;
! 83: continue;
! 84: }
! 85: #ifdef RTLD_PRELOAD_ENABLE_VAR
! 86: if (strncmp(envp[env_len], RTLD_PRELOAD_ENABLE_VAR "=", sizeof(RTLD_PRELOAD_ENABLE_VAR)) == 0) {
! 87: enabled = true;
! 88: continue;
! 89: }
! 90: #endif
! 91: }
! 92:
! 93: /* Make a new copy of envp as needed. */
! 94: env_size = env_len + 1 + (preload_idx == -1);
! 95: #ifdef RTLD_PRELOAD_ENABLE_VAR
! 96: if (!enabled)
! 97: env_size++;
! 98: #endif
! 99: nenvp = emalloc2(env_size, sizeof(*envp));
! 100: memcpy(nenvp, envp, env_len * sizeof(*envp));
! 101: nenvp[env_len] = NULL;
! 102:
! 103: /* Prepend our LD_PRELOAD to existing value or add new entry at the end. */
! 104: if (preload_idx == -1) {
! 105: # ifdef RTLD_PRELOAD_DEFAULT
! 106: easprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR, sudo_conf_noexec_path(), RTLD_PRELOAD_DELIM, RTLD_PRELOAD_DEFAULT);
! 107: # else
! 108: preload = fmt_string(RTLD_PRELOAD_VAR, sudo_conf_noexec_path());
! 109: # endif
! 110: if (preload == NULL)
! 111: errorx(1, _("unable to allocate memory"));
! 112: nenvp[env_len++] = preload;
! 113: nenvp[env_len] = NULL;
! 114: } else {
! 115: easprintf(&preload, "%s=%s%s%s", RTLD_PRELOAD_VAR, sudo_conf_noexec_path(), RTLD_PRELOAD_DELIM, nenvp[preload_idx]);
! 116: nenvp[preload_idx] = preload;
! 117: }
! 118: # ifdef RTLD_PRELOAD_ENABLE_VAR
! 119: if (!enabled) {
! 120: nenvp[env_len++] = RTLD_PRELOAD_ENABLE_VAR "=";
! 121: nenvp[env_len] = NULL;
! 122: }
! 123: # endif
! 124:
! 125: /* Install new env pointer. */
! 126: envp = nenvp;
! 127: #endif /* _PATH_SUDO_NOEXEC */
! 128:
! 129: debug_return_ptr(envp);
! 130: }
! 131:
! 132: /*
! 133: * Like execve(2) but falls back to running through /bin/sh
! 134: * ala execvp(3) if we get ENOEXEC.
! 135: */
! 136: int
! 137: sudo_execve(const char *path, char *const argv[], char *const envp[], int noexec)
! 138: {
! 139: /* Modify the environment as needed to disable further execve(). */
! 140: if (noexec)
! 141: envp = disable_execute(envp);
! 142:
! 143: execve(path, argv, envp);
! 144: if (errno == ENOEXEC) {
! 145: int argc;
! 146: char **nargv;
! 147:
! 148: for (argc = 0; argv[argc] != NULL; argc++)
! 149: continue;
! 150: nargv = emalloc2(argc + 2, sizeof(char *));
! 151: nargv[0] = "sh";
! 152: nargv[1] = (char *)path;
! 153: memcpy(nargv + 2, argv + 1, argc * sizeof(char *));
! 154: execve(_PATH_BSHELL, nargv, envp);
! 155: efree(nargv);
! 156: }
! 157: return -1;
! 158: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>