You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
14 KiB
473 lines
14 KiB
7 years ago
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 1852983..b7aa1a3 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -15,6 +15,7 @@
|
||
|
## along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
##
|
||
|
## Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+## Jiri Vymazal <jvymazal@redhat.com>
|
||
|
##
|
||
|
SUBDIRS=src/Tests/
|
||
|
|
||
|
diff --git a/doc/usbguard-daemon.8 b/doc/usbguard-daemon.8
|
||
|
index 18c72fe..dfdb285 100644
|
||
|
--- a/doc/usbguard-daemon.8
|
||
|
+++ b/doc/usbguard-daemon.8
|
||
|
@@ -1,4 +1,4 @@
|
||
|
-.\" Automatically generated by Pandoc 1.17.0.3
|
||
|
+.\" Automatically generated by Pandoc 1.19.1
|
||
|
.\"
|
||
|
.TH "USBGUARD\-DAEMON" "8" "June 2016" "" ""
|
||
|
.hy
|
||
|
@@ -25,6 +25,11 @@ Enable debugging messages in the log.
|
||
|
.RS
|
||
|
.RE
|
||
|
.TP
|
||
|
+.B \f[B]\-f\f[]
|
||
|
+Enable classical daemon behavior (fork at start, sysV compliant).
|
||
|
+.RS
|
||
|
+.RE
|
||
|
+.TP
|
||
|
.B \f[B]\-s\f[]
|
||
|
Log to syslog.
|
||
|
.RS
|
||
|
@@ -41,7 +46,8 @@ Log to a file at \f[I]path\f[].
|
||
|
.RE
|
||
|
.TP
|
||
|
.B \f[B]\-p\f[] <\f[I]path\f[]>
|
||
|
-Write PID to a file at \f[I]path\f[].
|
||
|
+Write PID to a file at \f[I]path\f[] (default:
|
||
|
+\f[I]/var/run/usbguard.pid\f[]).
|
||
|
.RS
|
||
|
.RE
|
||
|
.TP
|
||
|
diff --git a/doc/usbguard-daemon.8.md b/doc/usbguard-daemon.8.md
|
||
|
index 3e2fcaf..581613d 100644
|
||
|
--- a/doc/usbguard-daemon.8.md
|
||
|
+++ b/doc/usbguard-daemon.8.md
|
||
|
@@ -19,6 +19,9 @@ The **usbguard-daemon** is the main component of the USBGuard software framework
|
||
|
**-d**
|
||
|
: Enable debugging messages in the log.
|
||
|
|
||
|
+**-f**
|
||
|
+: Enable classical daemon behavior (fork at start, sysV compliant).
|
||
|
+
|
||
|
**-s**
|
||
|
: Log to syslog.
|
||
|
|
||
|
@@ -29,7 +32,7 @@ The **usbguard-daemon** is the main component of the USBGuard software framework
|
||
|
: Log to a file at *path*.
|
||
|
|
||
|
**-p** <*path*>
|
||
|
-: Write PID to a file at *path*.
|
||
|
+: Write PID to a file at *path* (default: */var/run/usbguard.pid*).
|
||
|
|
||
|
**-c** <*path*>
|
||
|
: Load configuration from a file at *path* (default: */etc/usbguard/usbguard-daemon.conf*).
|
||
|
diff --git a/src/Common/Utility.cpp b/src/Common/Utility.cpp
|
||
|
index f84d2a8..237acfb 100644
|
||
|
--- a/src/Common/Utility.cpp
|
||
|
+++ b/src/Common/Utility.cpp
|
||
|
@@ -42,56 +42,6 @@
|
||
|
namespace usbguard
|
||
|
{
|
||
|
|
||
|
- void daemonize()
|
||
|
- {
|
||
|
- const ::pid_t pid = fork();
|
||
|
-
|
||
|
- switch(pid) {
|
||
|
- case 0: /* child */
|
||
|
- break;
|
||
|
- case -1: /* error */
|
||
|
- ::exit(EXIT_FAILURE);
|
||
|
- default: /* parent */
|
||
|
- ::exit(EXIT_SUCCESS);
|
||
|
- }
|
||
|
- //
|
||
|
- // Decouple from parent environment
|
||
|
- // - chdir to /
|
||
|
- // - create new process session
|
||
|
- // - reset umask
|
||
|
- // - cleanup file descriptors
|
||
|
- // - ???
|
||
|
- // - consider using libdaemon
|
||
|
- //
|
||
|
- if (::chdir("/") != 0) {
|
||
|
- ::exit(EXIT_FAILURE);
|
||
|
- }
|
||
|
- const ::pid_t sid = ::setsid();
|
||
|
- if (sid != 0) {
|
||
|
- ::exit(EXIT_FAILURE);
|
||
|
- }
|
||
|
- ::umask(::umask(077)|022);
|
||
|
- struct rlimit rlim;
|
||
|
- if (::getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
|
||
|
- ::exit(EXIT_FAILURE);
|
||
|
- }
|
||
|
- const int maxfd = (rlim.rlim_max == RLIM_INFINITY ? 1024 : rlim.rlim_max);
|
||
|
- for (int fd = 0; fd < maxfd; ++fd) {
|
||
|
- ::close(fd);
|
||
|
- }
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- bool writePID(const std::string& filepath)
|
||
|
- {
|
||
|
- std::ofstream pidstream(filepath, std::ios_base::trunc);
|
||
|
- if (!pidstream) {
|
||
|
- return false;
|
||
|
- }
|
||
|
- pidstream << numberToString(getpid()) << std::endl;
|
||
|
- return true;
|
||
|
- }
|
||
|
-
|
||
|
static void runCommandExecChild(const std::string& path, const std::vector<std::string>& args)
|
||
|
{
|
||
|
struct rlimit rlim;
|
||
|
diff --git a/src/Common/Utility.hpp b/src/Common/Utility.hpp
|
||
|
index f722b22..54e1ea1 100644
|
||
|
--- a/src/Common/Utility.hpp
|
||
|
+++ b/src/Common/Utility.hpp
|
||
|
@@ -41,25 +41,6 @@
|
||
|
namespace usbguard
|
||
|
{
|
||
|
/**
|
||
|
- * Create a background process.
|
||
|
- *
|
||
|
- * Performs the following actions:
|
||
|
- * 1) fork a new process (parent process exists with 0)
|
||
|
- * 2) chdir to /
|
||
|
- * 3) creates a new process session
|
||
|
- * 4) resets umask
|
||
|
- * 5) closes all file descriptors
|
||
|
- * 6) Reinitialize logging for the child
|
||
|
- */
|
||
|
- void daemonize(void);
|
||
|
-
|
||
|
- /**
|
||
|
- * Writes the current PID to a file at filepath.
|
||
|
- * Returns true on success, otherwise returns false.
|
||
|
- */
|
||
|
- bool writePID(const std::string& filepath);
|
||
|
-
|
||
|
- /**
|
||
|
* Wrappers for the __builtin_expect function.
|
||
|
*/
|
||
|
#if defined(__GNUC__)
|
||
|
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp
|
||
|
index b317c85..2a9a37c 100644
|
||
|
--- a/src/Daemon/Daemon.cpp
|
||
|
+++ b/src/Daemon/Daemon.cpp
|
||
|
@@ -15,6 +15,7 @@
|
||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
//
|
||
|
// Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+// Jiri Vymazal <jvymazal@redhat.com>
|
||
|
//
|
||
|
#ifdef HAVE_BUILD_CONFIG_H
|
||
|
#include <build-config.h>
|
||
|
@@ -27,6 +28,8 @@
|
||
|
#include "usbguard/RuleParser.hpp"
|
||
|
#include "usbguard/Audit.hpp"
|
||
|
|
||
|
+#include <array>
|
||
|
+
|
||
|
#include <sys/select.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/types.h>
|
||
|
@@ -112,6 +115,8 @@ namespace usbguard
|
||
|
|
||
|
_device_rules_with_port = false;
|
||
|
_restore_controller_device_state = false;
|
||
|
+
|
||
|
+ pid_fd = -1;
|
||
|
}
|
||
|
|
||
|
Daemon::~Daemon()
|
||
|
@@ -402,6 +407,10 @@ namespace usbguard
|
||
|
}
|
||
|
} while(!exit_loop);
|
||
|
|
||
|
+ if (pid_fd != -1) {
|
||
|
+ lockf(pid_fd, F_ULOCK, 0);
|
||
|
+ close(pid_fd);
|
||
|
+ }
|
||
|
IPCServer::stop();
|
||
|
_dm->stop();
|
||
|
USBGUARD_LOG(Trace) << "Leaving main loop.";
|
||
|
@@ -411,6 +420,73 @@ namespace usbguard
|
||
|
{
|
||
|
}
|
||
|
|
||
|
+ void Daemon::daemonize(const std::string &pid_file)
|
||
|
+ {
|
||
|
+ USBGUARD_LOG(Trace) << "Starting daemonization";
|
||
|
+
|
||
|
+ pid_t pid = 0;
|
||
|
+ pid_t original_pid = getpid();
|
||
|
+
|
||
|
+ sigset_t mask;
|
||
|
+ sigemptyset(&mask);
|
||
|
+ sigaddset(&mask, SIGUSR1);
|
||
|
+ sigprocmask(SIG_BLOCK, &mask, nullptr);
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (pid = fork()) < 0);
|
||
|
+ if (pid > 0) {
|
||
|
+ constexpr int timeout_val = 5;
|
||
|
+ struct timespec timeout {timeout_val,0};
|
||
|
+ const time_t start = time(nullptr);
|
||
|
+ siginfo_t info;
|
||
|
+ do {
|
||
|
+ const int signum = sigtimedwait(&mask, &info, &timeout);
|
||
|
+ if (signum == SIGUSR1 && info.si_signo == SIGUSR1 && info.si_pid == pid) {
|
||
|
+ USBGUARD_LOG(Trace) << "Finished daemonization";
|
||
|
+ exit(EXIT_SUCCESS);
|
||
|
+ }
|
||
|
+ if (signum == -1 && errno == EAGAIN) {
|
||
|
+ break; /* timed out */
|
||
|
+ }
|
||
|
+ timeout.tv_sec = timeout_val - difftime(time(nullptr), start); /* avoid potentially endless loop */
|
||
|
+ } while(true);
|
||
|
+ throw Exception("Deamonize", "signal", "Waiting on pid file write timeout!");
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Now we are forked */
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", setsid() < 0);
|
||
|
+ signal(SIGCHLD, SIG_IGN);
|
||
|
+
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (pid_fd = open(pid_file.c_str(), O_RDWR|O_CREAT, 0640)) < 0);
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (lockf(pid_fd, F_TLOCK, 0)) < 0);
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (pid = fork()) < 0);
|
||
|
+ if (pid > 0) {
|
||
|
+ try {
|
||
|
+ std::string pid_str = std::to_string(pid);
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", write(pid_fd, pid_str.c_str(), pid_str.size()) != static_cast<ssize_t>(pid_str.size()));
|
||
|
+ kill(original_pid, SIGUSR1);
|
||
|
+ exit(EXIT_SUCCESS);
|
||
|
+ }
|
||
|
+ catch(...) {
|
||
|
+ kill(pid, SIGKILL);
|
||
|
+ throw;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Now we are forked 2nd time */
|
||
|
+ umask(0047); /* no need for world-accessible or executable files */
|
||
|
+ chdir("/");
|
||
|
+ const std::array<int,3> std_fds {{STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}};
|
||
|
+ int fd_null;
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (fd_null = open("/dev/null", O_RDWR)) < 0);
|
||
|
+ /* We do not need to close all fds because there is only logging open at this point */
|
||
|
+ for (auto fd : std_fds) {
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", close(fd));
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (dup2(fd_null, fd)) < 0);
|
||
|
+ }
|
||
|
+ close(fd_null);
|
||
|
+
|
||
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (lockf(pid_fd, F_LOCK, 0)) < 0);
|
||
|
+ }
|
||
|
+
|
||
|
uint32_t Daemon::assignID()
|
||
|
{
|
||
|
return _ruleset.assignID();
|
||
|
diff --git a/src/Daemon/Daemon.hpp b/src/Daemon/Daemon.hpp
|
||
|
index cfd02d9..065deaf 100644
|
||
|
--- a/src/Daemon/Daemon.hpp
|
||
|
+++ b/src/Daemon/Daemon.hpp
|
||
|
@@ -15,6 +15,7 @@
|
||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
//
|
||
|
// Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+// Jiri Vymazal <jvymazal@redhat.com>
|
||
|
//
|
||
|
#pragma once
|
||
|
#ifdef HAVE_BUILD_CONFIG_H
|
||
|
@@ -72,6 +73,8 @@ namespace usbguard
|
||
|
void run();
|
||
|
/* Stop the daemon */
|
||
|
void quit();
|
||
|
+ /* Handle process daemonization */
|
||
|
+ void daemonize(const std::string& pid_file);
|
||
|
|
||
|
uint32_t assignID();
|
||
|
uint32_t upsertRule(const std::string& match_spec, const std::string& rule_spec, bool parent_insensitive = false);
|
||
|
@@ -112,6 +115,8 @@ namespace usbguard
|
||
|
ConfigFile _config;
|
||
|
RuleSet _ruleset;
|
||
|
|
||
|
+ int pid_fd;
|
||
|
+
|
||
|
std::string _device_manager_backend;
|
||
|
std::shared_ptr<DeviceManager> _dm;
|
||
|
|
||
|
diff --git a/src/Daemon/main.cpp b/src/Daemon/main.cpp
|
||
|
index 869c2e2..4b9b351 100644
|
||
|
--- a/src/Daemon/main.cpp
|
||
|
+++ b/src/Daemon/main.cpp
|
||
|
@@ -15,6 +15,7 @@
|
||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
//
|
||
|
// Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+// Jiri Vymazal <jvymazal@redhat.com>
|
||
|
//
|
||
|
#ifdef HAVE_BUILD_CONFIG_H
|
||
|
#include <build-config.h>
|
||
|
@@ -37,9 +38,13 @@
|
||
|
static void setupCapabilities(void);
|
||
|
#endif
|
||
|
|
||
|
+#ifndef USBGUARD_PID_FILE
|
||
|
+#define USBGUARD_PID_FILE "/var/run/usbguard.pid"
|
||
|
+#endif
|
||
|
+
|
||
|
using namespace usbguard;
|
||
|
|
||
|
-const char * const G_optstring = "dskl:p:c:hWC";
|
||
|
+const char * const G_optstring = "dfskl:p:c:hWC";
|
||
|
|
||
|
static void printUsage(std::ostream& stream, const char *arg0)
|
||
|
{
|
||
|
@@ -47,6 +52,7 @@ static void printUsage(std::ostream& stream, const char *arg0)
|
||
|
stream << "Usage: " << filenameFromPath(std::string(arg0), true) << " [OPTIONS]" << std::endl;
|
||
|
stream << std::endl;
|
||
|
stream << " -d Enable debugging messages in the log." << std::endl;
|
||
|
+ stream << " -f Enable classical daemon forking behavior." << std::endl;
|
||
|
stream << " -s Log to syslog." << std::endl;
|
||
|
stream << " -k Log to console." << std::endl;
|
||
|
stream << " -l <path> Log to a file at `path'." << std::endl;
|
||
|
@@ -68,8 +74,9 @@ int main(int argc, char *argv[])
|
||
|
bool log_file = false;
|
||
|
bool use_seccomp_whitelist = false;
|
||
|
bool drop_capabilities = false;
|
||
|
+ bool daemonize = false;
|
||
|
std::string log_file_path;
|
||
|
- std::string pid_file;
|
||
|
+ std::string pid_file = USBGUARD_PID_FILE;
|
||
|
std::string conf_file = "/etc/usbguard/usbguard-daemon.conf";
|
||
|
int opt;
|
||
|
|
||
|
@@ -79,6 +86,9 @@ int main(int argc, char *argv[])
|
||
|
case 'd':
|
||
|
debug_mode = true;
|
||
|
break;
|
||
|
+ case 'f':
|
||
|
+ daemonize = true;
|
||
|
+ break;
|
||
|
case 's':
|
||
|
log_syslog = true;
|
||
|
break;
|
||
|
@@ -144,6 +154,13 @@ int main(int argc, char *argv[])
|
||
|
if (!conf_file.empty()) {
|
||
|
daemon.loadConfiguration(conf_file);
|
||
|
}
|
||
|
+ if (daemonize) {
|
||
|
+ if (log_console && !log_syslog && !log_file) {
|
||
|
+ USBGUARD_LOG(Warning) << "You have selected to fork and log only to \
|
||
|
+ console, nothing will be logged after forking!";
|
||
|
+ }
|
||
|
+ daemon.daemonize(pid_file);
|
||
|
+ }
|
||
|
daemon.run();
|
||
|
ret = EXIT_SUCCESS;
|
||
|
}
|
||
|
diff --git a/src/Tests/Makefile.am b/src/Tests/Makefile.am
|
||
|
index 7d93474..a952d18 100644
|
||
|
--- a/src/Tests/Makefile.am
|
||
|
+++ b/src/Tests/Makefile.am
|
||
|
@@ -40,6 +40,7 @@ EXTRA_DIST=\
|
||
|
$(top_srcdir)/src/Tests/UseCase/001_cli_policy.sh \
|
||
|
$(top_srcdir)/src/Tests/UseCase/002_cli_devices.sh \
|
||
|
$(top_srcdir)/src/Tests/UseCase/003_cli_devices_dummy.sh \
|
||
|
+ $(top_srcdir)/src/Tests/UseCase/004_daemonize.sh \
|
||
|
$(top_srcdir)/src/Tests/UseCase/DummyDevices
|
||
|
|
||
|
LOG_DRIVER=\
|
||
|
@@ -62,7 +63,8 @@ TESTS=\
|
||
|
UseCase/000_executable.sh \
|
||
|
UseCase/001_cli_policy.sh \
|
||
|
UseCase/002_cli_devices.sh \
|
||
|
- UseCase/003_cli_devices_dummy.sh
|
||
|
+ UseCase/003_cli_devices_dummy.sh \
|
||
|
+ UseCase/004_daemonize.sh
|
||
|
|
||
|
check_PROGRAMS=\
|
||
|
test-unit \
|
||
|
diff --git a/src/Tests/UseCase/004_daemonize.sh b/src/Tests/UseCase/004_daemonize.sh
|
||
|
new file mode 100755
|
||
|
index 0000000..d59dad1
|
||
|
--- /dev/null
|
||
|
+++ b/src/Tests/UseCase/004_daemonize.sh
|
||
|
@@ -0,0 +1,55 @@
|
||
|
+#!/bin/bash
|
||
|
+#
|
||
|
+#
|
||
|
+# Copyright (C) 2016 Red Hat, Inc.
|
||
|
+#
|
||
|
+# This program is free software; you can redistribute it and/or modify
|
||
|
+# it under the terms of the GNU General Public License as published by
|
||
|
+# the Free Software Foundation; either version 2 of the License, or
|
||
|
+# (at your option) any later version.
|
||
|
+#
|
||
|
+# This program is distributed in the hope that it will be useful,
|
||
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
+# GNU General Public License for more details.
|
||
|
+#
|
||
|
+# You should have received a copy of the GNU General Public License
|
||
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
+#
|
||
|
+# Authors: Jiri Vymazal <jvymazal@redhat.com>
|
||
|
+#
|
||
|
+# Test whether the binaries are executable as expected (no linker errors, etc.)
|
||
|
+#
|
||
|
+source "${USBGUARD_TESTLIB_BASH}" || exit 129
|
||
|
+
|
||
|
+# TODO? Move to testlib
|
||
|
+export USBGUARD_TESTLIB_TMPDIR="$(mktemp -d --tmpdir usbguard-test.XXXXXX)"
|
||
|
+
|
||
|
+export config_path="${USBGUARD_TESTLIB_TMPDIR}/daemon.conf"
|
||
|
+export pidfile_path="${USBGUARD_TESTLIB_TMPDIR}/usbguard.pid"
|
||
|
+export logfile="${USBGUARD_TESTLIB_TMPDIR}/daemon.log"
|
||
|
+
|
||
|
+function test_cli_daemonize()
|
||
|
+{
|
||
|
+ sleep 5
|
||
|
+
|
||
|
+ if [ ! -f "$pidfile_path" ]; then
|
||
|
+ echo "Test error: PID file for usbguard not present"
|
||
|
+ exit 1
|
||
|
+ fi
|
||
|
+
|
||
|
+ if [ ! `pgrep usbguard` == `cat $pidfile_path` ]; then
|
||
|
+ echo "Test error: PID of usbguard daemon not present in PID file"
|
||
|
+ exit 1
|
||
|
+ fi
|
||
|
+}
|
||
|
+
|
||
|
+cat > "$config_path" <<EOF
|
||
|
+EOF
|
||
|
+
|
||
|
+schedule "${USBGUARD_DAEMON} -f -p $pidfile_path -d -P -l $logfile -c $config_path" :service
|
||
|
+schedule "test_cli_daemonize"
|
||
|
+execute 20
|
||
|
+retval=$?
|
||
|
+cat $pidfile_path | xargs kill -9
|
||
|
+exit $retval
|
||
|
diff --git a/usbguard.service.in b/usbguard.service.in
|
||
|
index 5bed4e6..f862d3b 100644
|
||
|
--- a/usbguard.service.in
|
||
|
+++ b/usbguard.service.in
|
||
|
@@ -4,8 +4,9 @@ Wants=systemd-udevd.service local-fs.target
|
||
|
Documentation=man:usbguard-daemon(8)
|
||
|
|
||
|
[Service]
|
||
|
-Type=simple
|
||
|
-ExecStart=%sbindir%/usbguard-daemon -k -c %sysconfdir%/usbguard/usbguard-daemon.conf
|
||
|
+Type=forking
|
||
|
+PIDFile=/var/run/usbguard.pid
|
||
|
+ExecStart=%sbindir%/usbguard-daemon -f -s -c %sysconfdir%/usbguard/usbguard-daemon.conf
|
||
|
Restart=on-failure
|
||
|
|
||
|
[Install]
|