Exemplo n.º 1
0
void *sbox_find_next_symbol(int log_enabled, const char *fn_name)
{
	char	*msg;
	void	*fn_ptr;

	if(log_enabled)
		SB_LOG(SB_LOGLEVEL_DEBUG, "%s: %s", __func__, fn_name);

	fn_ptr = dlsym(RTLD_NEXT, fn_name);

	if ((msg = dlerror()) != NULL) {
		fprintf(stderr, "%s: dlsym(%s): %s\n",
			PACKAGE_NAME, fn_name, msg);
		if(log_enabled)
			SB_LOG(SB_LOGLEVEL_ERROR, "ERROR: %s: dlsym(%s): %s",
				PACKAGE_NAME, fn_name, msg);
		assert(0);
	}
	if (log_enabled && SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE)) {
		Dl_info	dli;

		if (dladdr(fn_ptr, &dli)) {
			SB_LOG(SB_LOGLEVEL_NOISE, "%s: %s at 0x%p, in file '%s'",
				__func__, fn_name, fn_ptr, dli.dli_fname);
		} else {
			SB_LOG(SB_LOGLEVEL_NOISE, "%s: %s at 0x%p",
				__func__, fn_name, fn_ptr);
		}
	}

	return(fn_ptr);
}
Exemplo n.º 2
0
/* compare vectors of strings and log if there are any changes.
 * TO BE IMPROVED: a more clever algorithm would be nice, something
 * that would log only the modified parts... now this displays 
 * everything if something was changed, which easily creates 
 * a *lot* of noise if SB_LOGLEVEL_NOISE is enabled.
*/
static void compare_and_log_strvec_changes(const char *vecname, 
	char *const *orig_strv, char *const *new_strv) 
{
	char *const *ptr2old = orig_strv;
	char *const *ptr2new = new_strv;
	int	strv_modified = 0;

	while (*ptr2old && *ptr2new) {
		if (strcmp(*ptr2old, *ptr2new)) {
			strv_modified = 1;
			break;
		}
		ptr2old++, ptr2new++;
	}
	if (!strv_modified && (*ptr2old || *ptr2new)) {
		strv_modified = 1;
	}
	if (strv_modified) {
		SB_LOG(SB_LOGLEVEL_DEBUG, "%s[] was modified", vecname); 
		if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE)) {
			int	i;
			for (i = 0, ptr2new = new_strv; 
			    *ptr2new;
			    i++, ptr2new++) {
				SB_LOG(SB_LOGLEVEL_NOISE, 
					"[%d]='%s'", i,
					*ptr2new);
			}
		}
	} else {
		SB_LOG(SB_LOGLEVEL_NOISE, 
			"%s[] was not modified", vecname); 
	}
}
Exemplo n.º 3
0
/* "sb.debug_messages_enabled", to be called from lua code
 * returns true if SB_LOG messages have been enabled for the debug levels
 * (debug,noise,noise2...)
*/
int lua_sb_debug_messages_enabled(lua_State *l)
{
	if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) {
		lua_pushboolean(l, 1);
	} else {
		lua_pushboolean(l, 0);
	}
	return 1;
}
Exemplo n.º 4
0
/* get access to sb2 context, create the structure 
 * if it didn't exist; in that case, the structure is only
 * cleared (most notably, the Lua system is not initialized
 * by this routine!)
 *
 * Remember to call release_sb2context() after the
 * pointer is not needed anymore.
*/
struct sb2context *get_sb2context(void)
{
	struct sb2context *ptr = NULL;

	if (!sb2_global_vars_initialized__) sb2_initialize_global_variables();

	if (!SB_LOG_INITIALIZED()) sblog_init();

	SB_LOG(SB_LOGLEVEL_NOISE, "get_sb2context()");

	if (pthread_detection_done == 0) check_pthread_library();

	if (pthread_library_is_available) {
		if (pthread_once_fnptr)
			(*pthread_once_fnptr)(&sb2context_key_once, alloc_sb2context_key);
		if (pthread_getspecific_fnptr)
			ptr = (*pthread_getspecific_fnptr)(sb2context_key);
		if (!ptr) ptr = alloc_sb2context();
		if (!ptr) {
			SB_LOG(SB_LOGLEVEL_ERROR,
				"Something's wrong with"
				" the pthreads support");
			fprintf(stderr, "FATAL: sb2 preload library:"
				" Something's wrong with"
				" the pthreads support.\n");
			exit(1);
		}
	} else {
		/* no pthreads, single-thread application */
		ptr = my_sb2context;
		if (!ptr) ptr = alloc_sb2context();
		if (!ptr) {
			SB_LOG(SB_LOGLEVEL_ERROR,
				"Failed to get Lua instance"
				" (and the pthreads support is "
				" disabled!)");
			fprintf(stderr, "FATAL: sb2 preload library:"
				" Failed to get Lua instance"
				" (and the pthreads support is disabled!)\n");
			exit(1);
		}
	}

	if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) {
		increment_sb2if_usage_counter(ptr);
	}
	return(ptr);
}
Exemplo n.º 5
0
static void increment_sb2if_usage_counter(volatile struct sb2context *ptr)
{
	if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) {
		/* Well, to make this bullet-proof the sb2if structure
		 * should be locked, but since this code is now used only for
		 * producing debugging information and the pointer is marked
		 * "volatile", the results are good enough. No need to slow 
		 * down anything with additional locks - this function is 
		 * called frequently. */
		if (ptr->sb2context_in_use > 0) SB_LOG(SB_LOGLEVEL_DEBUG,
			"Lua instance already in use! (%d)",
			ptr->sb2context_in_use);

		(ptr->sb2context_in_use)++;
	}
}
Exemplo n.º 6
0
void release_sb2context(struct sb2context *sb2if)
{
	if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) {
		int	i;
		volatile struct sb2context *ptr = sb2if;

		SB_LOG(SB_LOGLEVEL_NOISE, "release_sb2context()");

		if (!ptr) {
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"release_sb2context(): ptr is NULL ");
			return;
		}

		i = ptr->sb2context_in_use;
		if (i > 1) SB_LOG(SB_LOGLEVEL_DEBUG,
			"Lua instance usage counter was %d", i);

		(ptr->sb2context_in_use)--;
	}
}
Exemplo n.º 7
0
void release_lua(struct lua_instance *luaif)
{
	if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) {
		int	i;
		volatile struct lua_instance *ptr = luaif;

		SB_LOG(SB_LOGLEVEL_NOISE, "release_lua()");

		if (!ptr) {
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"release_lua(): ptr is NULL ");
			return;
		}

		i = ptr->lua_instance_in_use;
		if (i > 1) SB_LOG(SB_LOGLEVEL_DEBUG,
			"Lua instance usage counter was %d", i);

		(ptr->lua_instance_in_use)--;
	}
}
Exemplo n.º 8
0
static void revert_to_user_version_of_env_var(
	const char *realvarname, const char *wrappedname)
{
	char *cp = getenv(wrappedname);

	if (cp) {
		SB_LOG(SB_LOGLEVEL_DEBUG, "Revert env.var:%s=%s (%s)",
			realvarname, cp, wrappedname);
		setenv(realvarname, cp, 1/*overwrite*/);
	} else {
		int r;
		SB_LOG(SB_LOGLEVEL_DEBUG, "Revert env.var:Clear %s", realvarname);
		r = unsetenv(realvarname);
		if(r < 0) {
			int e = errno;
			SB_LOG(SB_LOGLEVEL_ERROR, "unsetenv(%s) failed, errno=%d",
				realvarname, e);
		}
	}
	if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3))
		dump_environ_to_log("revert_to_user_version_of_env_var: env. is now:");
}
Exemplo n.º 9
0
/* 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;
}
Exemplo n.º 10
0
/* Exec Postprocessing:
 * Called with "rule" and "exec_policy" already in lua's stack.
*/
int sb_execve_postprocess(char *exec_type,
                          char **mapped_file,
                          char **filename,
                          const char *binary_name,
                          char ***argv,
                          char ***envp)
{
    struct lua_instance *luaif;
    int res, new_argc;
    int replace_environment = 0;

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

    if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
        dump_lua_stack("sb_execve_postprocess entry", luaif->lua);
    }

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

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_postprocess: gettop=%d", lua_gettop(luaif->lua));

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

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

    lua_pushstring(luaif->lua, exec_type);
    lua_pushstring(luaif->lua, *mapped_file);
    lua_pushstring(luaif->lua, *filename);
    lua_pushstring(luaif->lua, binary_name);
    strvec_to_lua_table(luaif, *argv);
    strvec_to_lua_table(luaif, *envp);

    /* args: rule, exec_policy, exec_type, mapped_file, filename,
     *	 binaryname, argv, envp
     * returns: res, mapped_file, filename, argc, argv, envc, envp */
    lua_call(luaif->lua, 8, 7);

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

    case 0:
        /* exec arguments were modified, replace contents of
         * argv vector */
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_postprocess: Updated argv&envp");
        free(*mapped_file);
        *mapped_file = strdup(lua_tostring(luaif->lua, -6));

        free(*filename);
        *filename = strdup(lua_tostring(luaif->lua, -5));

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

        replace_environment = 1;
        break;

    case 1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_postprocess: argv was not modified");
        /* always update environment when we are going to exec */
        replace_environment = 1;
        break;

    case -1:
        SB_LOG(SB_LOGLEVEL_DEBUG,
               "sb_execve_postprocess: exec denied");
        break;

    default:
        SB_LOG(SB_LOGLEVEL_ERROR,
               "sb_execve_postprocess: Unsupported result %d", res);
        break;
    }

    if (replace_environment) {
        int new_envc;
        new_envc = lua_tointeger(luaif->lua, -2);
        strvec_free(*envp);
        lua_string_table_to_strvec(luaif, -1, envp, new_envc);
    }

    /* remove sb_execve_postprocess return values from the stack.  */
    lua_pop(luaif->lua, 7);

    SB_LOG(SB_LOGLEVEL_NOISE,
           "sb_execve_postprocess: at exit, gettop=%d", lua_gettop(luaif->lua));
    release_lua(luaif);
    return res;
}
Exemplo n.º 11
0
/* note: this expects that the lua stack already contains the mapping rule,
 * needed by sbox_translate_path (lua code).
 * at exit the rule is still there.
*/
char *call_lua_function_sbox_translate_path(
	const path_mapping_context_t *ctx,
	int result_log_level,
	const char *abs_clean_virtual_path,
	int *flagsp,
	char **exec_policy_name_ptr)
{
	struct sb2context	*sb2ctx = ctx->pmc_sb2ctx;
	int flags;
	char *host_path = NULL;

	SB_LOG(SB_LOGLEVEL_NOISE, "calling sbox_translate_path for %s(%s), fn_class=0x%X",
		ctx->pmc_func_name, abs_clean_virtual_path, ctx->pmc_fn_class);
	if (!sb2ctx->lua) sb2context_initialize_lua(sb2ctx);
	SB_LOG(SB_LOGLEVEL_NOISE,
		"call_lua_function_sbox_translate_path: gettop=%d",
		lua_gettop(sb2ctx->lua));
	if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
		dump_lua_stack("call_lua_function_sbox_translate_path entry",
			sb2ctx->lua);
	}

	lua_getfield(sb2ctx->lua, LUA_GLOBALSINDEX, "sbox_translate_path");
	/* stack now contains the rule object and string "sbox_translate_path",
         * move the string to the bottom: */
	lua_insert(sb2ctx->lua, -2);
	/* add other parameters */
	lua_pushstring(sb2ctx->lua, ctx->pmc_binary_name);
	lua_pushstring(sb2ctx->lua, ctx->pmc_func_name);
	lua_pushstring(sb2ctx->lua, abs_clean_virtual_path);
	lua_pushnumber(sb2ctx->lua, ctx->pmc_fn_class);
	 /* 5 arguments, returns rule,policy,path,flags */
	lua_call(sb2ctx->lua, 5, 4);

	host_path = (char *)lua_tostring(sb2ctx->lua, -2);
	if (host_path && (*host_path != '/')) {
		SB_LOG(SB_LOGLEVEL_ERROR,
			"Mapping failed: Result is not absolute ('%s'->'%s')",
			abs_clean_virtual_path, host_path);
		host_path = NULL;
	} else if (host_path) {
		host_path = strdup(host_path);
	}
	flags = lua_tointeger(sb2ctx->lua, -1);
	check_mapping_flags(flags, "sbox_translate_path");
	if (flagsp) *flagsp = flags;

	if (exec_policy_name_ptr) {
		char *exec_policy_name;

		if (*exec_policy_name_ptr) {
			free(*exec_policy_name_ptr);
			*exec_policy_name_ptr = NULL;
		}
		exec_policy_name = (char *)lua_tostring(sb2ctx->lua, -3);
		if (exec_policy_name) {
			*exec_policy_name_ptr = strdup(exec_policy_name);
		}
	}

	lua_pop(sb2ctx->lua, 3); /* leave the rule to the stack */

	if (host_path) {
		char *new_host_path = clean_and_log_fs_mapping_result(ctx,
			abs_clean_virtual_path, result_log_level, host_path, flags);
		free(host_path);
		host_path = new_host_path;
	}
	if (!host_path) {
		SB_LOG(SB_LOGLEVEL_ERROR,
			"No result from sbox_translate_path for: %s '%s'",
			ctx->pmc_func_name, abs_clean_virtual_path);
	}
	SB_LOG(SB_LOGLEVEL_NOISE,
		"call_lua_function_sbox_translate_path: at exit, gettop=%d",
		lua_gettop(sb2ctx->lua));
	if(SB_LOG_IS_ACTIVE(SB_LOGLEVEL_NOISE3)) {
		dump_lua_stack("call_lua_function_sbox_translate_path exit",
			sb2ctx->lua);
	}
	return(host_path);
}
Exemplo n.º 12
0
int do_exec(int *result_errno_ptr,
	const char *exec_fn_name, const char *orig_file,
	char *const *orig_argv, char *const *orig_envp)
{
	char *new_file = NULL;
	char **new_argv = NULL;
	char **new_envp = NULL;
	int  result;
	PROCESSCLOCK(clk1)

	START_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, "do_exec");
	if (getenv("SBOX_DISABLE_MAPPING")) {
		/* just run it, don't worry, be happy! */
	} else {
		int	r;
		char	**my_envp_copy = NULL; /* used only for debug log */
		char	*tmp, *binaryname;
		enum binary_type type;

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

		if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) {
			char *buf = strvec_to_string(orig_argv);

			SB_LOG(SB_LOGLEVEL_DEBUG,
				"EXEC/Orig.args: %s : %s", orig_file, buf);
			free(buf);
		
			/* create a copy of intended environment for logging,
			 * before preprocessing */
			my_envp_copy = prepare_envp_for_do_exec(orig_file,
				binaryname, orig_envp);
		}
		
		new_envp = prepare_envp_for_do_exec(orig_file, binaryname, orig_envp);

		r = prepare_exec(exec_fn_name, NULL/*exec_policy_name: not yet known*/,
			orig_file, 0, orig_argv, orig_envp,
			&type, &new_file, &new_argv, &new_envp);

		if (SB_LOG_IS_ACTIVE(SB_LOGLEVEL_DEBUG)) {
			/* find out and log if preprocessing did something */
			compare_and_log_strvec_changes("argv", orig_argv, new_argv);
			compare_and_log_strvec_changes("envp", my_envp_copy, new_envp);
		}

		if (r < 0) {
			SB_LOG(SB_LOGLEVEL_DEBUG,
				"EXEC denied by prepare_exec(), %s", orig_file);
			*result_errno_ptr = errno;
			STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, "Exec denied");
			return(r); /* exec denied */
		}

		if (check_envp_has_ld_preload_and_ld_library_path(
			new_envp ? new_envp : orig_envp) == 0) {

			SB_LOG(SB_LOGLEVEL_ERROR,
				"exec(%s) failed, internal configuration error: "
				"LD_LIBRARY_PATH and/or LD_PRELOAD were not set "
				"by exec mapping logic", orig_file);
			*result_errno_ptr = EINVAL;
			STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, "Config error");
			return(-1);
		}
	}

	errno = *result_errno_ptr; /* restore to orig.value */
	STOP_AND_REPORT_PROCESSCLOCK(SB_LOGLEVEL_INFO, &clk1, orig_file);
	result = sb_next_execve(
		(new_file ? new_file : orig_file),
		(new_argv ? new_argv : orig_argv),
		(new_envp ? new_envp : orig_envp));
	*result_errno_ptr = errno;
	SB_LOG(SB_LOGLEVEL_DEBUG,
		"EXEC failed (%s), errno=%d", orig_file, *result_errno_ptr);
	return(result);
}