示例#1
0
static int prepare_hashbang(
	char **mapped_file,	/* In: script, out: mapped script interpreter */
	char *orig_file,
	char ***argvp,
	char ***envpp,
	const char *exec_policy_name)
{
	int argc, fd, c, i, j, n;
	char ch;
	char *mapped_interpreter = NULL;
	char **new_argv = NULL;
	char hashbang[SBOX_MAXPATH]; /* only 60 needed on linux, just be safe */
	char interpreter[SBOX_MAXPATH];
	char *interp_arg = NULL;
	char *tmp = NULL, *mapped_binaryname = NULL;
	int result = 0;

	if ((fd = open_nomap(*mapped_file, O_RDONLY)) < 0) {
		/* unexpected error, just run it */
		return 0;
	}

	if ((c = read(fd, &hashbang[0], SBOX_MAXPATH - 1)) < 2) {
		/* again unexpected error, close fd and run it */
		close_nomap_nolog(fd);
		return 0;
	}

	argc = elem_count(*argvp);

	/* extra element for hashbang argument */
	new_argv = calloc(argc + 3, sizeof(char *));

	/* skip any initial whitespace following "#!" */
	for (i = 2; (hashbang[i] == ' ' 
			|| hashbang[i] == '\t') && i < c; i++)
		;

	for (n = 0, j = i; i < c; i++) {
		ch = hashbang[i];
		if (hashbang[i] == 0
			|| hashbang[i] == ' '
			|| hashbang[i] == '\t'
			|| hashbang[i] == '\n') {
			hashbang[i] = 0;
			if (i > j) {
				if (n == 0) {
					char *ptr = &hashbang[j];
					strcpy(interpreter, ptr);
					new_argv[n++] = strdup(interpreter);
				} else {
					/* this was the one and only
					 * allowed argument for the
					 * interpreter
					 */
					interp_arg = strdup(&hashbang[j]);
					new_argv[n++] = interp_arg;
					break;
				}
			}
			j = i + 1;
		}
		if (ch == '\n' || ch == 0) break;
	}

	new_argv[n++] = strdup(orig_file); /* the unmapped script path */
	for (i = 1; (*argvp)[i] != NULL && i < argc; ) {
		new_argv[n++] = (*argvp)[i++];
	}
	new_argv[n] = NULL;

	/* Now we need to update __SB2_ORIG_BINARYNAME to point to 
	 * the unmapped script interpreter (exec_map_script_interpreter
	 * may change it again (not currently, but in the future)
	*/
	change_environment_variable(
		*envpp, "__SB2_ORIG_BINARYNAME=", interpreter);

	/* script interpreter mapping in C */
	exec_policy_handle_t     eph = find_exec_policy_handle(exec_policy_name);
	int c_mapping_result_code;
	const char *c_new_exec_policy_name = NULL;
	
	c_mapping_result_code = exec_map_script_interpreter(eph, exec_policy_name,
		interpreter, interp_arg, *mapped_file,
		orig_file, new_argv, &c_new_exec_policy_name, &mapped_interpreter);
	SB_LOG(SB_LOGLEVEL_DEBUG,
		"back from exec_map_script_interpreter => %d (%s)",
		c_mapping_result_code, (mapped_interpreter ? mapped_interpreter : "<NULL>"));

	switch (c_mapping_result_code) {
	case 0:
                /* exec arguments were modified, argv has been modified */
                SB_LOG(SB_LOGLEVEL_DEBUG,
                        "%s: <0> argv has been updated", __func__);
		break;
	case 1:
                SB_LOG(SB_LOGLEVEL_DEBUG,
                        "%s: <1> argv was not modified", __func__);
		break;
	case 2:
                SB_LOG(SB_LOGLEVEL_DEBUG,
                        "%s: <2> Use ordinary path mapping", __func__);
		if (mapped_interpreter) free(mapped_interpreter);
                mapped_interpreter = NULL;
                {
                        mapping_results_t       mapping_result;

                        clear_mapping_results_struct(&mapping_result);
                        sbox_map_path_for_exec("script_interp",
                                interpreter, &mapping_result);
                        if (mapping_result.mres_result_buf) {
                                mapped_interpreter =
                                        strdup(mapping_result.mres_result_buf);
                        }
                        if (mapping_result.mres_exec_policy_name)
				c_new_exec_policy_name = strdup(mapping_result.mres_exec_policy_name);
			else
				c_new_exec_policy_name = NULL;
                        free_mapping_results(&mapping_result);
                }
                SB_LOG(SB_LOGLEVEL_DEBUG, "%s: "
                        "interpreter=%s mapped_interpreter=%s policy=%s",
                        __func__, interpreter, mapped_interpreter,
                        c_new_exec_policy_name ? c_new_exec_policy_name : "NULL");
		break;
	case -1:
		SB_LOG(SB_LOGLEVEL_DEBUG, "%s: <-1> exec denied", __func__);
		if (mapped_interpreter) free(mapped_interpreter);
		mapped_interpreter = NULL;
		return(-1);
	default:
                SB_LOG(SB_LOGLEVEL_ERROR,
                        "%s: Unsupported result %d", __func__, c_mapping_result_code);
		return(-1);
	}
	exec_policy_name = c_new_exec_policy_name;

	if (!mapped_interpreter) {
		SB_LOG(SB_LOGLEVEL_ERROR,
			"failed to map script interpreter=%s", interpreter);
		return(-1);
	}

	/*
	 * Binaryname (the one expected by the rules) comes still from
	 * the interpreter name so we set it here.  Note that it is now
	 * basename of the mapped interpreter (not the original one)!
	 */
	tmp = strdup(mapped_interpreter);
	mapped_binaryname = strdup(basename(tmp));
	change_environment_variable(*envpp, "__SB2_BINARYNAME=",
	    mapped_binaryname);
	free(mapped_binaryname);
	free(tmp);
	
	SB_LOG(SB_LOGLEVEL_DEBUG, "prepare_hashbang(): interpreter=%s,"
			"mapped_interpreter=%s", interpreter,
			mapped_interpreter);

	/* feed this through prepare_exec to let it deal with
	 * cpu transparency etc.
	 */
	result = prepare_exec("run_hashbang",
		exec_policy_name,
		mapped_interpreter,
		1/*file_has_been_mapped, and rue&policy exist*/,
		new_argv, *envpp,
		(enum binary_type*)NULL,
		mapped_file, argvp, envpp);

	SB_LOG(SB_LOGLEVEL_DEBUG, "prepare_hashbang done: mapped_file='%s'",
			*mapped_file);

	return(result);
}
示例#2
0
文件: argvenvp.c 项目: neeraj9/sbox2
/* Map script interpreter:
 * Called with "rule" and "exec_policy" already in lua's stack,
 * leaves (possibly modified) "rule" and "exec_policy" to lua's stack.
*/
char *sb_execve_map_script_interpreter(
    const char *interpreter,
    const char *interp_arg,
    const char *mapped_script_filename,
    const char *orig_script_filename,
    char ***argv,
    char ***envp)
{
    struct lua_instance *luaif;
    char *mapped_interpreter;
    int new_argc, new_envc;
    int res;

    luaif = get_lua();
    if (!luaif) return(0);

    if (!argv || !envp) {
        SB_LOG(SB_LOGLEVEL_ERROR,
               "ERROR: sb_execve_map_script_interpreter: "
               "(argv || envp) == NULL");
        release_lua(luaif);
        return NULL;
    }

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: gettop=%d"
           " interpreter=%s interp_arg=%s "
           "mapped_script_filename=%s orig_script_filename=%s",
           lua_gettop(luaif->lua), interpreter, interp_arg,
           mapped_script_filename, orig_script_filename);

    lua_getfield(luaif->lua, LUA_GLOBALSINDEX,
                 "sb_execve_map_script_interpreter");

    /* stack now contains "rule", "exec_policy" and
     * "sb_execve_map_script_interpreter".
     * move "sb_execve_map_script_interpreter" to the bottom : */
    lua_insert(luaif->lua, -3);

    lua_pushstring(luaif->lua, interpreter);
    if (interp_arg) lua_pushstring(luaif->lua, interp_arg);
    else lua_pushnil(luaif->lua);
    lua_pushstring(luaif->lua, mapped_script_filename);
    lua_pushstring(luaif->lua, orig_script_filename);
    strvec_to_lua_table(luaif, *argv);
    strvec_to_lua_table(luaif, *envp);

    /* args: rule, exec_policy, interpreter, interp_arg,
     *	 mapped_script_filename, orig_script_filename,
     *	 argv, envp
     * returns: rule, policy, result, mapped_interpreter, #argv, argv,
     *	#envp, envp
     * "result" is one of:
     *  0: argv / envp were modified; mapped_interpreter was set
     *  1: argv / envp were not modified; mapped_interpreter was set
     * -1: deny exec.
    */
    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_map_script_interpreter M1", luaif->lua);
    }
    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: call lua, gettop=%d",
           lua_gettop(luaif->lua));
    lua_call(luaif->lua, 8, 8);
    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: return from lua, gettop=%d",
           lua_gettop(luaif->lua));
    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_map_script_interpreter M2", luaif->lua);
    }

    mapped_interpreter = (char *)lua_tostring(luaif->lua, -5);
    if (mapped_interpreter) mapped_interpreter = strdup(mapped_interpreter);

    res = lua_tointeger(luaif->lua, -6);
    switch (res) {

    case 0:
        /* exec arguments were modified, replace contents of
         * argv and envp vectors */
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: Updated argv&envp");

        strvec_free(*argv);
        new_argc = lua_tointeger(luaif->lua, -4);
        lua_string_table_to_strvec(luaif, -3, argv, new_argc);

        new_envc = lua_tointeger(luaif->lua, -2);
        strvec_free(*envp);
        lua_string_table_to_strvec(luaif, -1, envp, new_envc);

        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        break;

    case 1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: argv&envp were not modified");
        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        break;

    case 2:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: use sbox_map_path_for_exec");
        /* remove all return values from the stack. */
        lua_pop(luaif->lua, 8);
        if (mapped_interpreter) free(mapped_interpreter);
        mapped_interpreter = NULL;
        {
            mapping_results_t	mapping_result;

            clear_mapping_results_struct(&mapping_result);
            sbox_map_path_for_exec("script_interp",
                                   interpreter, &mapping_result);
            if (mapping_result.mres_result_buf) {
                mapped_interpreter =
                    strdup(mapping_result.mres_result_buf);
            }
            free_mapping_results(&mapping_result);
        }
        SB_LOG(SB_LOGLEVEL_DEBUG, "sb_execve_map_script_interpreter: "
               "interpreter=%s mapped_interpreter=%s",
               interpreter, mapped_interpreter);
        break;

    case -1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_map_script_interpreter: exec denied");
        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        if (mapped_interpreter) free(mapped_interpreter);
        mapped_interpreter = NULL;
        break;

    default:
        SB_LOG(SB_LOGLEVEL_ERROR,
               "sb_execve_map_script_interpreter: Unsupported result %d", res);
        /* remove return values from the stack, leave rule & policy.  */
        lua_pop(luaif->lua, 6);
        break;
    }


    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_map_script_interpreter E2", luaif->lua);
    }

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_map_script_interpreter: at exit, gettop=%d",
           lua_gettop(luaif->lua));
    release_lua(luaif);
    return mapped_interpreter;
}
示例#3
0
static int prepare_exec(const char *exec_fn_name,
	const char *exec_policy_name,
	const char *orig_file,
	int file_has_been_mapped,
	char *const *orig_argv,
	char *const *orig_envp,
	enum binary_type *typep,
	char **new_file,  /* return value */
	char ***new_argv,
	char ***new_envp) /* *new_envp must be filled by the caller */
{
	char **my_envp = *new_envp; /* FIXME */
	const char **my_new_envp = NULL;
	const char **my_new_argv = NULL;
	char **my_argv = NULL, *my_file = NULL;
	char *binaryname, *tmp, *mapped_file;
	int err = 0;
	enum binary_type type;
	int postprocess_result = 0;
	int ret = 0; /* 0: ok to exec, ret<0: exec fails */
	int file_mode;
	uid_t file_uid;
	gid_t file_gid;
	PROCESSCLOCK(clk1)
	PROCESSCLOCK(clk4)

	START_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, "prepare_exec");
	(void)exec_fn_name; /* not yet used */
	(void)orig_envp; /* not used */

	SB_LOG(SB_LOGLEVEL_DEBUG,
		"prepare_exec(): orig_file='%s'",
		orig_file);
	SB_LOG(SB_LOGLEVEL_NOISE,
		"%s: exec_policy_name='%s'", __func__, exec_policy_name);

	tmp = strdup(orig_file);
	binaryname = strdup(basename(tmp)); /* basename may modify *tmp */
	free(tmp);
	
	my_file = strdup(orig_file);

	my_argv = duplicate_argv(orig_argv);

	if (!file_has_been_mapped) {
		PROCESSCLOCK(clk2)

		START_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk2, "execve_preprocess");
		if ((err = apply_exec_preprocessing_rules(&my_file, &my_argv, &my_envp)) != 0) {
			SB_LOG(SB_LOGLEVEL_ERROR, "argvenvp processing error %i", err);
		}
		STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk2, my_file);
	}

	/* test if mapping is enabled during the exec()..
	 * (host-* tools disable it)
	*/
	if (file_has_been_mapped) {
		/* (e.g. we came back from run_hashbang()) */
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"prepare_exec(): no double mapping, my_file = %s", my_file);
		mapped_file = strdup(my_file);
	} else if (strvec_contains_prefix(my_envp, "SBOX_DISABLE_MAPPING=1", NULL)) {
		SB_LOG(SB_LOGLEVEL_DEBUG,
			"do_exec(): mapping disabled, my_file = %s", my_file);
		mapped_file = strdup(my_file);

		/* we won't call sbox_map_path_for_exec() because mapping
		 * is disabled.  */
	} else {
		/* now we have to do path mapping for my_file to find exactly
		 * what is the path we're supposed to deal with
		 */
		mapping_results_t	mapping_result;
		PROCESSCLOCK(clk3)

		clear_mapping_results_struct(&mapping_result);
		START_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk3, "map_path_for_exec");
		sbox_map_path_for_exec("do_exec", my_file, &mapping_result);
		mapped_file = (mapping_result.mres_result_buf ?
			strdup(mapping_result.mres_result_buf) : NULL);
		exec_policy_name = (mapping_result.mres_exec_policy_name ?
			strdup(mapping_result.mres_exec_policy_name) : NULL);
		STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk3, mapped_file);
			
		free_mapping_results(&mapping_result);

		SB_LOG(SB_LOGLEVEL_DEBUG,
			"do_exec(): my_file = %s, mapped_file = %s",
			my_file, mapped_file);
	}

	/*
	 * prepare_envp_for_do_exec() left us placeholder in envp array
	 * that we will fill now with fully mangled binary name.
	 */
	change_environment_variable(my_envp,
		"__SB2_REAL_BINARYNAME=", mapped_file);

	/* inspect the completely mangled filename */
	type = inspect_binary(mapped_file, 1/*check_x_permission*/,
		&file_mode, &file_uid, &file_gid);
	if (typep) *typep = type;

	if (!exec_policy_name) {
		if ((type != BIN_INVALID) && (type != BIN_NONE)) {
			exec_policy_name = find_exec_policy_name(mapped_file, my_file);
			if (!exec_policy_name) {
				errno = ENOEXEC;
				ret = -1;
				SB_LOG(SB_LOGLEVEL_ERROR,
					"No exec policy (%s,%s) => ENOEXEC",
					my_file, mapped_file);
				goto out;
			}
		}
	}
	SB_LOG(SB_LOGLEVEL_DEBUG, "%s: exec_policy_name=%s", __func__, exec_policy_name);

	START_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk4, "exec/typeswitch");
	switch (type) {
		case BIN_HASHBANG:
			SB_LOG(SB_LOGLEVEL_DEBUG, "Exec/hashbang %s", mapped_file);
			/* prepare_hashbang() will call prepare_exec()
			 * recursively */
			ret = prepare_hashbang(&mapped_file, my_file,
					&my_argv, &my_envp, exec_policy_name);
			break;

		case BIN_HOST_DYNAMIC:
			SB_LOG(SB_LOGLEVEL_DEBUG, "Exec/host-dynamic %s",
					mapped_file);

#if 0
			postprocess_result = sb_execve_postprocess("native",
				exec_policy_name,
				&mapped_file, &my_file, binaryname,
				&my_argv, &my_envp);
#else
			postprocess_result = exec_postprocess_native_executable(
				exec_policy_name,
				&mapped_file, &my_file, binaryname,
				(const char **)my_argv, &my_new_argv, (const char **)*new_envp, &my_new_envp);
			my_envp = (char**)my_new_envp; /* FIXME */
			my_argv = (char**)my_new_argv; /* FIXME */
#endif

			if (postprocess_result < 0) {
				errno = EINVAL;
				ret = -1;
			} else {
				simulate_suid_and_sgid_if_needed(mapped_file, my_envp,
					file_mode, file_uid, file_gid,
					1/*host_compatible_binary*/);
			}
			break;

		case BIN_HOST_STATIC:
#if 0
			postprocess_result = sb_execve_postprocess("static",
				exec_policy_name,
				&mapped_file, &my_file, binaryname,
				&my_argv, &my_envp);
#else
			{
				const char			*namev_in_ruletree[4];
				const char			*cputransp_cmd = NULL;
				ruletree_object_offset_t	cmd_offs;

				namev_in_ruletree[0] = "cputransparency";
				namev_in_ruletree[1] = "native";
				namev_in_ruletree[2] = "cmd";
				namev_in_ruletree[3] = NULL;
				cmd_offs = ruletree_catalog_vget(namev_in_ruletree);
				if (cmd_offs) {
					cputransp_cmd = offset_to_ruletree_string_ptr(cmd_offs, NULL);
				}
				if (cputransp_cmd && (cputransp_cmd[0] != '\0')) {
					postprocess_result = exec_postprocess_cpu_transparency_executable(
						exec_policy_name,
						&mapped_file, &my_file, binaryname,
						(const char **)my_argv, &my_new_argv,
						(const char **)*new_envp, &my_new_envp,
						"native");
					my_envp = (char**)my_new_envp; /* FIXME */
					my_argv = (char**)my_new_argv; /* FIXME */
				} else {
					const char *allow_static_bin = NULL;

					/* don't print warning, if this static binary
					 * has been allowed (see the wrapper for
					 * ldconfig - we don't want to see warnings
					 * every time when someone executes that)
					*/
					allow_static_bin = getenv("SBOX_ALLOW_STATIC_BINARY");
					if (allow_static_bin &&
					    !strcmp(allow_static_bin, mapped_file)) {
						/* no warnning, just debug */
						SB_LOG(SB_LOGLEVEL_DEBUG,
							"statically linked "
							"native binary %s (allowed)",
							mapped_file);
					} else {
						SB_LOG(SB_LOGLEVEL_WARNING,
							"Executing statically "
							"linked native binary %s",
							mapped_file);
					}
					/* Add LD_LIBRARY_PATH and LD_PRELOAD.
					 * the static binary itself does not need
					 * these, but if it executes another 
					 * program, then there is at least some
					 * hope of getting back to SB2. It won't
					 * be able to start anything that runs
					 * under CPU transparency, but host-compatible
					 * binaries may be able to get back..
					*/
					postprocess_result = exec_postprocess_host_static_executable(
						exec_policy_name,
						&mapped_file, &my_file, binaryname,
						(const char **)my_argv, &my_new_argv,
						(const char **)*new_envp, &my_new_envp);
					my_envp = (char**)my_new_envp; /* FIXME */
					my_argv = (char**)my_new_argv; /* FIXME */
				}
			}
#endif
			if (postprocess_result < 0) {
				errno = EINVAL;
				ret = -1;
			} else {
				/* the static binary won't get SUID simulation,
				 * but if it executes something else.. */
				simulate_suid_and_sgid_if_needed(mapped_file, my_envp,
					file_mode, file_uid, file_gid,
					1/*host_compatible_binary*/);
			}
			break;

		case BIN_TARGET:
			SB_LOG(SB_LOGLEVEL_DEBUG, "Exec/target %s",
					mapped_file);

#if 0
			postprocess_result = sb_execve_postprocess(
				"cpu_transparency",
				exec_policy_name,
				&mapped_file, &my_file,
				binaryname, &my_argv, &my_envp);
#else
			postprocess_result = exec_postprocess_cpu_transparency_executable(
				exec_policy_name,
				&mapped_file, &my_file, binaryname,
				(const char **)my_argv, &my_new_argv, (const char **)*new_envp, &my_new_envp,
				"target");
			my_envp = (char**)my_new_envp; /* FIXME */
			my_argv = (char**)my_new_argv; /* FIXME */
#endif

			if (postprocess_result < 0) {
				errno = EINVAL;
				ret = -1;
			} else {
				simulate_suid_and_sgid_if_needed(mapped_file, my_envp,
					file_mode, file_uid, file_gid,
					0/*not host_compatible_binary*/);
			}
			break;

		case BIN_INVALID: /* = can't be executed, no X permission */
	 		/* don't even try to exec, errno has been set.*/
			ret = -1;
			break;

		case BIN_NONE:
			/* file does not exist. errno has been set. */
			ret = -1;
			break;

		case BIN_UNKNOWN:
			errno = ENOEXEC;
			ret = -1;
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"Unidentified executable detected (%s) => ENOEXEC",
				mapped_file);
			break;
	}
	STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk4, my_file);
    out:
	*new_file = mapped_file;
	*new_argv = my_argv;
	*new_envp = my_envp;
	STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, orig_file);
	return(ret);
}