Add daemonization, fix any bugs found.

Add support for daemonizing via the --daemon flag. If daemonized, the
pid is written to the file provided via the --pidfile flag. When
daemonized, falco immediately returns an error if stderr output or
logging was chosen on the command line.

Clean up handling of outputs to match the expected use case (daemon):

 - syslog output is enabled by default
 - stdout output is disabled by default
 - If not configured at all, both outputs are enabled.

Also fix some bugs I found while running via packages:

 - There were still some references to the old rules filename
   falco_rules.conf.
 - The redhat package mistakenly defined some system directories like
   /etc, /etc/init.d. Add them to the exclusion list (See
   https://cmake.org/Bug/view.php?id=13609 for context).
 - Clean up some of the error messages to be more consistent.

After this I was able to build and install debian and rpm
packages. Starting the falco service ran falco as a daemon with syslog
output.
This commit is contained in:
Mark Stemm 2016-05-06 17:25:54 -07:00
parent cfc89127e7
commit a787dc84d5
7 changed files with 98 additions and 20 deletions

View File

@ -209,6 +209,7 @@ set(CPACK_RPM_PACKAGE_REQUIRES "sysdig")
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/postinstall")
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/preuninstall")
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE "${PROJECT_SOURCE_DIR}/scripts/rpm/postuninstall")
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src /usr/share/man /usr/share/man/man8)
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/src /usr/share/man /usr/share/man/man8 /etc /usr /usr/bin /usr/share /etc/rc.d /etc/rc.d/init.d )
set(CPACK_RPM_PACKAGE_RELOCATABLE "OFF")
include(CPack)

View File

@ -1,16 +1,16 @@
rules_file: /etc/falco_rules.conf
rules_file: /etc/falco_rules.yaml
json_output: false
log_stderr: true
log_syslog: true
syslog_output:
enabled: false
enabled: true
file_output:
enabled: true
filename: ./events.txt
stdout_output:
enabled: true
enabled: false

View File

@ -20,7 +20,7 @@ DESC="Falco"
NAME=falco
DAEMON=/usr/bin/$NAME
PIDFILE=/var/run/$NAME.pid
DAEMON_ARGS="--daemon --falcopid=$PIDFILE"
DAEMON_ARGS="--daemon --pidfile=$PIDFILE"
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed

View File

@ -34,7 +34,7 @@ start() {
[ -x $exec ] || exit 5
# [ -f $config ] || exit 6
echo -n $"Starting $prog: "
daemon $exec --daemon --falcopid=$pidfile
daemon $exec --daemon --pidfile=$pidfile
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile

View File

@ -19,7 +19,7 @@ void falco_configuration::init(string conf_filename)
string m_config_file = conf_filename;
m_config = new yaml_configuration(m_config_file);
m_rules_filename = m_config->get_scalar<string>("rules_file", "/etc/falco_rules.conf");
m_rules_filename = m_config->get_scalar<string>("rules_file", "/etc/falco_rules.yaml");
m_json_output = m_config->get_scalar<bool>("json_output", false);
output_config file_output;

View File

@ -39,11 +39,13 @@ static void usage()
printf(
"Usage: falco [options] rules_filename\n\n"
"Options:\n"
" -h, --help Print this page\n"
" -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
" -o Output type (options are 'stdout', 'syslog', default is 'stdout')\n"
" -e <events_file> Read the events from <events_file> (in .scap format) instead of tapping into live.\n"
" -r <rules_file> Rules file (defaults to value set in configuration file, or /etc/falco_rules.conf).\n"
" -h, --help Print this page\n"
" -c Configuration file (default " FALCO_SOURCE_CONF_FILE ", " FALCO_INSTALL_CONF_FILE ")\n"
" -o Output type (options are 'stdout', 'syslog', default is 'stdout')\n"
" -d, --daemon Run as a daemon\n"
" -p, --pidfile <pid_file> When run as a daemon, write pid to specified file\n"
" -e <events_file> Read the events from <events_file> (in .scap format) instead of tapping into live.\n"
" -r <rules_file> Rules file (defaults to value set in configuration file, or /etc/falco_rules.conf).\n"
"\n"
);
}
@ -192,16 +194,20 @@ int falco_init(int argc, char **argv)
sinsp_evt::param_fmt event_buffer_format;
int long_index = 0;
string lua_main_filename;
string output_name = "stdout";
string output_name = "syslog";
string scap_filename;
string conf_filename;
string rules_filename;
string lua_dir = FALCO_LUA_DIR;
lua_State* ls = NULL;
bool daemon = false;
string pidfilename = "/var/run/falco.pid";
static struct option long_options[] =
{
{"help", no_argument, 0, 'h' },
{"daemon", no_argument, 0, 'd' },
{"pidfile", required_argument, 0, 'd' },
{0, 0, 0, 0}
};
@ -214,7 +220,7 @@ int falco_init(int argc, char **argv)
// Parse the args
//
while((op = getopt_long(argc, argv,
"c:ho:e:r:",
"c:ho:e:r:dp:",
long_options, &long_index)) != -1)
{
switch(op)
@ -239,6 +245,12 @@ int falco_init(int argc, char **argv)
case 'r':
rules_filename = optarg;
break;
case 'd':
daemon = true;
break;
case 'p':
pidfilename = optarg;
break;
case '?':
result = EXIT_FAILURE;
goto exit;
@ -248,6 +260,18 @@ int falco_init(int argc, char **argv)
}
// Some combinations of arguments are not allowed.
if (daemon && pidfilename == "") {
falco_logger::log(LOG_ERR, "If -d is provided, a pid file must also be provided. Exiting.\n");
result = EXIT_FAILURE;
goto exit;
}
if (daemon && output_name == "stdout") {
falco_logger::log(LOG_ERR, "If -d is provided, can not output to stdout. Exiting.\n");
result = EXIT_FAILURE;
goto exit;
}
ifstream* conf_stream;
if (conf_filename.size())
@ -255,7 +279,7 @@ int falco_init(int argc, char **argv)
conf_stream = new ifstream(conf_filename);
if (!conf_stream->good())
{
falco_logger::log(LOG_ERR, "Could not find configuration file at " + conf_filename + ". Exiting \n");
falco_logger::log(LOG_ERR, "Could not find configuration file at " + conf_filename + ". Exiting.\n");
result = EXIT_FAILURE;
goto exit;
}
@ -308,7 +332,7 @@ int falco_init(int argc, char **argv)
{
falco_logger::log(LOG_ERR, "Could not find Falco Lua libraries (tried " +
string(FALCO_LUA_DIR FALCO_LUA_MAIN) + ", " +
lua_main_filename + "). Exiting \n");
lua_main_filename + "). Exiting.\n");
result = EXIT_FAILURE;
goto exit;
}
@ -365,11 +389,64 @@ int falco_init(int argc, char **argv)
{
if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null"))
{
falco_logger::log(LOG_ERR, "Unable to load the driver. Exiting\n");
falco_logger::log(LOG_ERR, "Unable to load the driver. Exiting.\n");
}
inspector->open();
}
}
// If daemonizing, do it here so any init errors will
// be returned in the foreground process.
if (daemon) {
pid_t pid, sid;
pid = fork();
if (pid < 0) {
// error
falco_logger::log(LOG_ERR, "Could not fork. Exiting.\n");
result = EXIT_FAILURE;
goto exit;
} else if (pid > 0) {
// parent. Write child pid to pidfile and exit
std::ofstream pidfile;
pidfile.open(pidfilename);
if (!pidfile.good())
{
falco_logger::log(LOG_ERR, "Could not write pid to pid file " + pidfilename + ". Exiting.\n");
result = EXIT_FAILURE;
goto exit;
}
pidfile << pid;
pidfile.close();
goto exit;
}
// if here, child.
// Become own process group.
sid = setsid();
if (sid < 0) {
falco_logger::log(LOG_ERR, "Could not set session id. Exiting.\n");
result = EXIT_FAILURE;
goto exit;
}
// Set umask so no files are world anything or group writable.
umask(027);
// Change working directory to '/'
if ((chdir("/")) < 0) {
falco_logger::log(LOG_ERR, "Could not change working directory to '/'. Exiting.\n");
result = EXIT_FAILURE;
goto exit;
}
// Close stdin, stdout, stderr.
close(0);
close(1);
close(2);
}
do_inspect(inspector,
rules,
ls);
@ -378,7 +455,7 @@ int falco_init(int argc, char **argv)
}
catch(sinsp_exception& e)
{
falco_logger::log(LOG_ERR, "Runtime error: " + string(e.what()) + ". Exiting\n");
falco_logger::log(LOG_ERR, "Runtime error: " + string(e.what()) + ". Exiting.\n");
result = EXIT_FAILURE;
}

View File

@ -30,8 +30,8 @@ int falco_logger::syslog(lua_State *ls) {
return 0;
}
bool falco_logger::log_stderr;
bool falco_logger::log_syslog;
bool falco_logger::log_stderr = true;
bool falco_logger::log_syslog = true;
void falco_logger::log(int priority, const string msg) {
if (falco_logger::log_syslog) {