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>