static void fatal(lua_State * L, const char * msg) { dump_lua_stack(L, 0); fprintf(stderr, "%s\nSTACK\n%s", msg, lua_tostring(L, -1)); lua_pop(L, 1); fflush(stderr); exit(1); }
/* 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; }
/* 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; }
/* * Function used as a callback for all Lua functions passed through * get_as3_value_from_lua_stack() */ AS3_Val as3_lua_callback(void * data, AS3_Val args) { /* WARNING: Panic alert! Use L*_FN checkers here! */ SPAM(("as3_lua_callback(): begin")); AS3_Val res; LuaFunctionCallbackData * func_data = (LuaFunctionCallbackData *) data; int nargs = 0; int status = 0; int results_base = 0; lua_State * L = func_data->L; if (L == NULL) { /* TODO: Should we crash here? fatal_error("state expired"); / * Does not return * / */ sztrace("as3_lua_callback: state expired"); return AS3_Undefined(); } { /* A new scope for LCALL to work (C89 conformance) */ LCALL(L, stack); /* TODO: Cache that with lua_ref, it is faster */ lua_getfield(L, LUA_REGISTRYINDEX, AS3LUA_CALLBACKS); /* TODO: Assert we have a table here */ lua_rawgeti(L, -1, func_data->ref); /* push stored function */ if (lua_istable(L, -1) == 0) /* Probably nil */ { lua_pop(L, 1); /* Pop bad callback table */ LCHECK_FN(L, stack, 0, fatal_error); fatal_error("function callback not found"); /* Does not return */ } lua_rawgeti(L, -1, AS3LUA_CBFNINDEX); /* push stored callback function */ #ifdef DO_SPAM { SPAM(("as3_lua_callback(): AS3 arguments")); AS3_Val a = AS3_CallS("join", args, AS3_Undefined()); AS3_Trace(a); SAFE_RELEASE(a); } #endif /* DO_SPAM */ /* TODO: Assert we have Lua function (or other callable object) on the top of the stack */ LCHECK_FN(L, stack, 2 + 1, fatal_error); nargs = push_as3_array_to_lua_stack(L, args); /* push arguments */ #ifdef DO_SPAM /* TODO: Remove */ lua_pushcfunction(L, as3_trace); dump_lua_stack(L, LBASE(L, stack) + 2 + 1); lua_pushliteral(L, "ARGUMENTS"); lua_pushnumber(L, nargs); lua_call(L, 3, 0); #endif /* DO_SPAM */ LCHECK_FN(L, stack, 2 + 1 + nargs, fatal_error); results_base = LBASE(L, stack) + 2; status = do_pcall_with_traceback(L, nargs, LUA_MULTRET); if (status != 0) { const char * msg = NULL; LCHECK_FN(L, stack, 2 + 1, fatal_error); /* Tables and error message */ lua_remove(L, -2); /* Remove AS3LUA_CALLBACKS table */ lua_remove(L, -2); /* Remove holder table */ LCHECK_FN(L, stack, 1, fatal_error); /* Only error message */ /* Error message is on stack */ /* NOTE: It is not necessary string! If we want to preserve its type, see lua_DoString. */ if (lua_tostring(L, -1) == NULL) { lua_pop(L, 1); lua_pushliteral(L, "(non-string)"); } LCHECK_FN(L, stack, 1, fatal_error); lua_pushliteral(L, "Error in Lua callback:\n"); lua_insert(L, -2); LCHECK_FN(L, stack, 2, fatal_error); lua_concat(L, 2); LCHECK_FN(L, stack, 1, fatal_error); sztrace((char *)lua_tostring(L, -1)); /* TODO: ?! */ /* lua_error(L); */ msg = lua_tostring(L, -1); lua_pop(L, 1); /* fatal_error(msg); / * Does not return * / */ } /* Process results */ #ifdef DO_SPAM /* TODO: Remove */ /* lua_pushcfunction(L, as3_trace); lua_pushliteral(L, "STACK"); dump_lua_stack(L, results_base); lua_call(L, 2, 0); */ #endif /* DO_SPAM */ res = create_as3_value_from_lua_stack(L, results_base + 1, LTOP(L, stack), TRUE); #ifdef DO_SPAM SPAM(("as3_lua_callback() result type")); AS3_Trace(AS3_Call(getQualifiedClassName_method, NULL, AS3_Array("AS3ValType", res))); #endif /* DO_SPAM */ lua_settop(L, LBASE(L, stack)); /* Cleanup results and two holder tables */ SPAM(("as3_lua_callback(): end")); return res; } /* Unreachable */ }
/* 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); }
/* Exec Postprocessing: */ int lb_execve_postprocess(const char *exec_type, const char *exec_policy_name, char **mapped_file, char **filename, const char *binary_name, char ***argv, char ***envp) { struct lbcontext *lbctx; int res, new_argc; int replace_environment = 0; PROCESSCLOCK(clk1) START_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, "lb_execve_postprocess"); lbctx = get_lbcontext_lua(); if (!lbctx) return(0); if(LB_LOG_IS_ACTIVE(LB_LOGLEVEL_NOISE3)) { dump_lua_stack("lb_execve_postprocess entry", lbctx->lua); } if (!argv || !envp) { LB_LOG(LB_LOGLEVEL_ERROR, "ERROR: lb_argvenvp: (argv || envp) == NULL"); release_lbcontext(lbctx); return -1; } LB_LOG(LB_LOGLEVEL_NOISE, "lb_execve_postprocess: gettop=%d", lua_gettop(lbctx->lua)); lua_getfield(lbctx->lua, LUA_GLOBALSINDEX, "lb_execve_postprocess"); lua_pushstring(lbctx->lua, exec_policy_name); lua_pushstring(lbctx->lua, exec_type); lua_pushstring(lbctx->lua, *mapped_file); lua_pushstring(lbctx->lua, *filename); lua_pushstring(lbctx->lua, binary_name); strvec_to_lua_table(lbctx, *argv); strvec_to_lua_table(lbctx, *envp); /* args: exec_policy_name, exec_type, mapped_file, filename, * binaryname, argv, envp * returns: res, mapped_file, filename, argc, argv, envc, envp */ lua_call(lbctx->lua, 7, 7); res = lua_tointeger(lbctx->lua, -7); switch (res) { case 0: /* exec arguments were modified, replace contents of * argv vector */ LB_LOG(LB_LOGLEVEL_DEBUG, "lb_execve_postprocess: Updated argv&envp"); free(*mapped_file); *mapped_file = strdup(lua_tostring(lbctx->lua, -6)); free(*filename); *filename = strdup(lua_tostring(lbctx->lua, -5)); strvec_free(*argv); new_argc = lua_tointeger(lbctx->lua, -4); lua_string_table_to_strvec(lbctx->lua, -3, argv, new_argc); replace_environment = 1; break; case 1: LB_LOG(LB_LOGLEVEL_DEBUG, "lb_execve_postprocess: argv was not modified"); /* always update environment when we are going to exec */ replace_environment = 1; break; case -1: LB_LOG(LB_LOGLEVEL_DEBUG, "lb_execve_postprocess: exec denied"); break; default: LB_LOG(LB_LOGLEVEL_ERROR, "lb_execve_postprocess: Unsupported result %d", res); break; } if (replace_environment) { int new_envc; new_envc = lua_tointeger(lbctx->lua, -2); strvec_free(*envp); lua_string_table_to_strvec(lbctx->lua, -1, envp, new_envc); } /* remove lb_execve_postprocess return values from the stack. */ lua_pop(lbctx->lua, 7); STOP_AND_REPORT_PROCESSCLOCK(LB_LOGLEVEL_INFO, &clk1, mapped_file); LB_LOG(LB_LOGLEVEL_NOISE, "lb_execve_postprocess: at exit, gettop=%d", lua_gettop(lbctx->lua)); release_lbcontext(lbctx); return res; }