Skip to content

Instantly share code, notes, and snippets.

@vinipsmaker
Created March 4, 2023 21:10
Show Gist options
  • Save vinipsmaker/b4d857402a98bf9582e58e1423cc4325 to your computer and use it in GitHub Desktop.
Save vinipsmaker/b4d857402a98bf9582e58e1423cc4325 to your computer and use it in GitHub Desktop.
/* Copyright (c) 2021, 2022, 2023 Vinícius dos Santos Oliveira
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */
#include <csignal>
#include <boost/preprocessor/control/iif.hpp>
#include <boost/vmd/is_number.hpp>
#include <boost/vmd/empty.hpp>
#define LUA_REGISTRYINDEX (-10000)
struct lua_State;
typedef long lua_Integer;
typedef int (*lua_CFunction) (lua_State *L);
struct vm_context
{
bool is_master();
};
void lua_newtable (lua_State *L);
void lua_pushliteral (lua_State *L, const char *s);
void lua_pushlightuserdata (lua_State *L, void *p);
void lua_pushinteger (lua_State *L, lua_Integer n);
void lua_pushcfunction (lua_State *L, lua_CFunction f);
void lua_rawset (lua_State *L, int index);
lua_Integer luaL_checkinteger(lua_State*, int);
int luaL_error (lua_State *L, const char *fmt, ...);
vm_context& get_vm_context(lua_State*);
namespace emilua {
static char system_signal_key;
static int system_signal_raise(lua_State* L)
{
int signal_number = luaL_checkinteger(L, 1);
#define EMILUA_DETAIL_IS_SIG_X_OR(SIG) signal_number == SIG ||
#define EMILUA_IS_SIG_X_OR(SIG) BOOST_PP_IIF( \
BOOST_VMD_IS_NUMBER(SIG), EMILUA_DETAIL_IS_SIG_X_OR, BOOST_VMD_EMPTY \
)(SIG)
#define EMILUA_DETAIL_IS_NOT_SIG_X_AND(SIG) signal_number != SIG &&
#define EMILUA_IS_NOT_SIG_X_AND(SIG) BOOST_PP_IIF( \
BOOST_VMD_IS_NUMBER(SIG), \
EMILUA_DETAIL_IS_NOT_SIG_X_AND, BOOST_VMD_EMPTY \
)(SIG)
auto& vm_ctx = get_vm_context(L);
if (!vm_ctx.is_master()) {
// SIGKILL and SIGSTOP are the only signals that cannot be caught,
// blocked, or ignored. If we allowed any child VM to raise these
// signals, then the protection to only allow the main VM to force-exit
// the process would be moot.
if (
EMILUA_IS_SIG_X_OR(SIGKILL)
EMILUA_IS_SIG_X_OR(SIGSTOP)
false
) {
return luaL_error(L, "EPERM");
}
// Unless the main VM has a handler installed (the check doesn't need to
// be race-free... that's not a problem) for the process-terminating
// signal, forbid slave VMs from raising it.
if (
// Default action is to continue the process (whatever lol)
EMILUA_IS_NOT_SIG_X_AND(SIGCONT)
// Default action is to ignore the signal
EMILUA_IS_NOT_SIG_X_AND(SIGCHLD)
EMILUA_IS_NOT_SIG_X_AND(SIGURG)
EMILUA_IS_NOT_SIG_X_AND(SIGWINCH)
true
) {
// TODO: a Windows implementation that checks for SIG_DFL
return luaL_error(L, "EPERM");
}
}
#undef EMILUA_IS_NOT_SIG_X_AND
#undef EMILUA_DETAIL_IS_NOT_SIG_X_AND
#undef EMILUA_IS_SIG_X_OR
#undef EMILUA_DETAIL_IS_SIG_X_OR
int ret = std::raise(signal_number);
if (ret != 0) {
return luaL_error(L, "raise error");
}
return 0;
}
void init_system(lua_State* L)
{
lua_pushlightuserdata(L, &system_signal_key);
{
lua_newtable(L);
lua_pushliteral(L, "raise");
lua_pushcfunction(L, system_signal_raise);
lua_rawset(L, -3);
#define EMILUA_DEF_SIGNAL(KEY, VALUE) do { \
lua_pushliteral(L, KEY); \
lua_pushinteger(L, VALUE); \
lua_rawset(L, -3); \
} while(0)
#define EMILUA_DEF_SIGNAL2(SIG) EMILUA_DEF_SIGNAL(#SIG, SIG)
// <signal.h>
EMILUA_DEF_SIGNAL2(SIGABRT);
EMILUA_DEF_SIGNAL2(SIGFPE);
EMILUA_DEF_SIGNAL2(SIGILL);
EMILUA_DEF_SIGNAL2(SIGINT);
EMILUA_DEF_SIGNAL2(SIGSEGV);
EMILUA_DEF_SIGNAL2(SIGTERM);
#define EMILUA_DEF_SIGNAL3(SIG) BOOST_PP_IIF( \
BOOST_VMD_IS_NUMBER(SIG), EMILUA_DEF_SIGNAL, BOOST_VMD_EMPTY \
)(#SIG, SIG)
// Unix
EMILUA_DEF_SIGNAL3(SIGALRM);
EMILUA_DEF_SIGNAL3(SIGBUS);
EMILUA_DEF_SIGNAL3(SIGCHLD);
EMILUA_DEF_SIGNAL3(SIGCONT);
EMILUA_DEF_SIGNAL3(SIGHUP);
EMILUA_DEF_SIGNAL3(SIGIO);
EMILUA_DEF_SIGNAL3(SIGKILL);
EMILUA_DEF_SIGNAL3(SIGPIPE);
EMILUA_DEF_SIGNAL3(SIGPROF);
EMILUA_DEF_SIGNAL3(SIGQUIT);
EMILUA_DEF_SIGNAL3(SIGSTOP);
EMILUA_DEF_SIGNAL3(SIGSYS);
EMILUA_DEF_SIGNAL3(SIGTRAP);
EMILUA_DEF_SIGNAL3(SIGTSTP);
EMILUA_DEF_SIGNAL3(SIGTTIN);
EMILUA_DEF_SIGNAL3(SIGTTOU);
EMILUA_DEF_SIGNAL3(SIGURG);
EMILUA_DEF_SIGNAL3(SIGUSR1);
EMILUA_DEF_SIGNAL3(SIGUSR2);
EMILUA_DEF_SIGNAL3(SIGVTALRM);
EMILUA_DEF_SIGNAL3(SIGWINCH);
EMILUA_DEF_SIGNAL3(SIGXCPU);
EMILUA_DEF_SIGNAL3(SIGXFSZ);
// Windows
EMILUA_DEF_SIGNAL3(SIGBREAK);
#undef EMILUA_DEF_SIGNAL3
#undef EMILUA_DEF_SIGNAL2
#undef EMILUA_DEF_SIGNAL
}
lua_rawset(L, LUA_REGISTRYINDEX);
}
} // namespace emilua
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment