#include "safe-kill.h"
#include "trace.h"
#include "util.h"
+#include "macro.h"
#include <signal.h>
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
-static bool is_process_coredumping(pid_t pid)
+EXPORT_TEST bool is_process_coredumping(pid_t pid)
{
char buf[LINE_MAX];
_cleanup_fclose_ FILE *fp = NULL;
int safe_kill(pid_t pid, int sig);
+#ifdef _UNIT_TEST
+#include <stdbool.h>
+bool is_process_coredumping(pid_t pid);
+#endif
+
#endif /* SAFE_KILL_H */
ADD_TESTS(cmocka-test-child-pid "${UNIT_TESTS_CFLAGS}" "-Wl,--wrap=fread_int,--wrap=fread_uint,--wrap=fread_ulong,--wrap=g_slist_prepend,--wrap=g_slist_remove -O0" cmocka-test-child-pid.c)
ADD_TESTS(cmocka-proc-app-list "${UNIT_TESTS_CFLAGS}" "-Wl,--wrap=fread_int,--wrap=fread_uint,--wrap=fread_ulong,--wrap=g_slist_prepend,--wrap=g_slist_remove,--wrap=g_slist_prepend,--wrap=g_slist_remove -O0" cmocka-proc-app-list.c)
ADD_TESTS(test-common "${UNIT_TESTS_CFLAGS}" "-O0" test-common.c)
+ADD_TESTS(test-safe-kill "${UNIT_TESTS_CFLAGS}" "-Wl,--wrap=kill,--wrap=fopen,--wrap=fopen64 -O0" test-safe-kill.c)
function(ADD_SKIP_TEST name wraps sources)
ADD_EXECUTABLE(${name} ${sources})
--- /dev/null
+Name: safe-kill-test
+Umask: 0002
+State: S (sleeping)
+Tgid: 4219
+Ngid: 0
+Pid: 4219
+PPid: 1
+TracerPid: 0
+Uid: 1000 1000 1000 1000
+Gid: 1000 1000 1000 1000
+FDSize: 128
+Groups: 4 20 24 27 30 46 104 116 126 132 134 1000 1002 64055
+NStgid: 4219
+NSpid: 4219
+NSpgid: 2235
+NSsid: 2235
+VmPeak: 1085588 kB
+VmSize: 1023676 kB
+VmLck: 0 kB
+VmPin: 0 kB
+VmHWM: 190900 kB
+VmRSS: 78152 kB
+RssAnon: 25948 kB
+RssFile: 52180 kB
+RssShmem: 24 kB
+VmData: 212628 kB
+VmStk: 132 kB
+VmExe: 3792 kB
+VmLib: 76476 kB
+VmPTE: 1008 kB
+VmSwap: 52424 kB
+HugetlbPages: 0 kB
+CoreDumping: 0
+THP_enabled: 1
+Threads: 4
+SigQ: 0/31144
+SigPnd: 0000000000000000
+ShdPnd: 0000000000000000
+SigBlk: 0000000000000000
+SigIgn: 0000000001001000
+SigCgt: 0000000180000002
+CapInh: 0000000000000000
+CapPrm: 0000000000000000
+CapEff: 0000000000000000
+CapBnd: 0000003fffffffff
+CapAmb: 0000000000000000
+NoNewPrivs: 0
+Seccomp: 0
+Speculation_Store_Bypass: thread vulnerable
+Cpus_allowed: ff
+Cpus_allowed_list: 0-7
+Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
+Mems_allowed_list: 0
+voluntary_ctxt_switches: 17488
+nonvoluntary_ctxt_switches: 7284
--- /dev/null
+Name: safe-kill-test
+Umask: 0002
+State: S (sleeping)
+Tgid: 4219
+Ngid: 0
+Pid: 4219
+PPid: 1
+TracerPid: 0
+Uid: 1000 1000 1000 1000
+Gid: 1000 1000 1000 1000
+FDSize: 128
+Groups: 4 20 24 27 30 46 104 116 126 132 134 1000 1002 64055
+NStgid: 4219
+NSpid: 4219
+NSpgid: 2235
+NSsid: 2235
+VmPeak: 1085588 kB
+VmSize: 1023676 kB
+VmLck: 0 kB
+VmPin: 0 kB
+VmHWM: 190900 kB
+VmRSS: 78152 kB
+RssAnon: 25948 kB
+RssFile: 52180 kB
+RssShmem: 24 kB
+VmData: 212628 kB
+VmStk: 132 kB
+VmExe: 3792 kB
+VmLib: 76476 kB
+VmPTE: 1008 kB
+VmSwap: 52424 kB
+HugetlbPages: 0 kB
+CoreDumping: 1
+THP_enabled: 1
+Threads: 4
+SigQ: 0/31144
+SigPnd: 0000000000000000
+ShdPnd: 0000000000000000
+SigBlk: 0000000000000000
+SigIgn: 0000000001001000
+SigCgt: 0000000180000002
+CapInh: 0000000000000000
+CapPrm: 0000000000000000
+CapEff: 0000000000000000
+CapBnd: 0000003fffffffff
+CapAmb: 0000000000000000
+NoNewPrivs: 0
+Seccomp: 0
+Speculation_Store_Bypass: thread vulnerable
+Cpus_allowed: ff
+Cpus_allowed_list: 0-7
+Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
+Mems_allowed_list: 0
+voluntary_ctxt_switches: 17488
+nonvoluntary_ctxt_switches: 7284
--- /dev/null
+Name: safe-kill-test
+Umask: 0002
+State: S (sleeping)
+Tgid: 4219
+Ngid: 0
+Pid: 4219
+PPid: 1
+TracerPid: 0
+Uid: 1000 1000 1000 1000
+Gid: 1000 1000 1000 1000
+FDSize: 128
+Groups: 4 20 24 27 30 46 104 116 126 132 134 1000 1002 64055
+NStgid: 4219
+NSpid: 4219
+NSpgid: 2235
+NSsid: 2235
+VmPeak: 1085588 kB
+VmSize: 1023676 kB
+VmLck: 0 kB
+VmPin: 0 kB
+VmHWM: 190900 kB
+VmRSS: 78152 kB
+RssAnon: 25948 kB
+RssFile: 52180 kB
+RssShmem: 24 kB
+VmData: 212628 kB
+VmStk: 132 kB
+VmExe: 3792 kB
+VmLib: 76476 kB
+VmPTE: 1008 kB
+VmSwap: 52424 kB
+HugetlbPages: 0 kB
+CoreDumping: dummyval
+THP_enabled: 1
+Threads: 4
+SigQ: 0/31144
+SigPnd: 0000000000000000
+ShdPnd: 0000000000000000
+SigBlk: 0000000000000000
+SigIgn: 0000000001001000
+SigCgt: 0000000180000002
+CapInh: 0000000000000000
+CapPrm: 0000000000000000
+CapEff: 0000000000000000
+CapBnd: 0000003fffffffff
+CapAmb: 0000000000000000
+NoNewPrivs: 0
+Seccomp: 0
+Speculation_Store_Bypass: thread vulnerable
+Cpus_allowed: ff
+Cpus_allowed_list: 0-7
+Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
+Mems_allowed_list: 0
+voluntary_ctxt_switches: 17488
+nonvoluntary_ctxt_switches: 7284
--- /dev/null
+Name: safe-kill-test
+Umask: 0002
+State: S (sleeping)
+Tgid: 4219
+Ngid: 0
+Pid: 4219
+PPid: 1
+TracerPid: 0
+Uid: 1000 1000 1000 1000
+Gid: 1000 1000 1000 1000
+FDSize: 128
+Groups: 4 20 24 27 30 46 104 116 126 132 134 1000 1002 64055
+NStgid: 4219
+NSpid: 4219
+NSpgid: 2235
+NSsid: 2235
+VmPeak: 1085588 kB
+VmSize: 1023676 kB
+VmLck: 0 kB
+VmPin: 0 kB
+VmHWM: 190900 kB
+VmRSS: 78152 kB
+RssAnon: 25948 kB
+RssFile: 52180 kB
+RssShmem: 24 kB
+VmData: 212628 kB
+VmStk: 132 kB
+VmExe: 3792 kB
+VmLib: 76476 kB
+VmPTE: 1008 kB
+VmSwap: 52424 kB
+HugetlbPages: 0 kB
+THP_enabled: 1
+Threads: 4
+SigQ: 0/31144
+SigPnd: 0000000000000000
+ShdPnd: 0000000000000000
+SigBlk: 0000000000000000
+SigIgn: 0000000001001000
+SigCgt: 0000000180000002
+CapInh: 0000000000000000
+CapPrm: 0000000000000000
+CapEff: 0000000000000000
+CapBnd: 0000003fffffffff
+CapAmb: 0000000000000000
+NoNewPrivs: 0
+Seccomp: 0
+Speculation_Store_Bypass: thread vulnerable
+Cpus_allowed: ff
+Cpus_allowed_list: 0-7
+Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
+Mems_allowed_list: 0
+voluntary_ctxt_switches: 17488
+nonvoluntary_ctxt_switches: 7284
--- /dev/null
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <assert.h>
+#include <cmocka.h>
+#include <errno.h>
+#include "safe-kill.h"
+
+#define BUF_MAX 1024
+
+int __real_kill(pid_t pid, int sig);
+FILE *__real_fopen(const char *pathname, const char *mode);
+
+int __wrap_kill(pid_t pid, int sig)
+{
+ bool fake = mock_type(bool);
+ if (!fake)
+ return __real_kill(pid, sig);
+
+ check_expected(pid);
+ check_expected(sig);
+
+ return 0;
+}
+
+FILE *__wrap_fopen(const char *pathname, const char *mode)
+{
+ char buf[BUF_MAX];
+
+ int fake_type = mock_type(int);
+ if (fake_type == 0) { /* don't mock */
+ return __real_fopen(pathname, mode);
+ } else if (fake_type == 1) { /* return prepared file */
+ check_expected_ptr(pathname);
+ check_expected_ptr(mode);
+
+ int coredump_state = mock_type(int);
+
+ snprintf(buf, sizeof buf, "../../tests/test-safe-kill-%d.txt", coredump_state);
+
+ return __real_fopen(buf, mode);
+ } else { /* file not found */
+ errno = ENOENT;
+ return NULL;
+ }
+}
+
+FILE *__wrap_fopen64(const char *pathname, const char *mode)
+{
+ return __wrap_fopen(pathname, mode);
+}
+
+static void is_process_coredumping_positive(void **state)
+{
+ /* CoreDumping = 0 */
+ will_return(__wrap_fopen, 1);
+ will_return(__wrap_fopen, 0);
+ expect_string(__wrap_fopen, pathname, "/proc/1/status");
+ expect_string(__wrap_fopen, mode, "r");
+
+ assert(is_process_coredumping(1) == false);
+
+ /* CoreDumping = 1 */
+ will_return(__wrap_fopen, 1);
+ will_return(__wrap_fopen, 1);
+ expect_string(__wrap_fopen, pathname, "/proc/1/status");
+ expect_string(__wrap_fopen, mode, "r");
+
+ assert(is_process_coredumping(1) == true);
+
+ /* no CoreDumping entry (i.e. unsupported by kernel) */
+ will_return(__wrap_fopen, 1);
+ will_return(__wrap_fopen, 3);
+ expect_string(__wrap_fopen, pathname, "/proc/1/status");
+ expect_string(__wrap_fopen, mode, "r");
+
+ assert(is_process_coredumping(1) == false);
+}
+
+static void is_process_coredumping_negative(void **state)
+{
+ /* file not found (fopen returns NULL) */
+ will_return(__wrap_fopen, 2);
+ assert(is_process_coredumping(1) == false);
+
+ will_return(__wrap_fopen, 1);
+ will_return(__wrap_fopen, 2);
+ expect_string(__wrap_fopen, pathname, "/proc/123/status");
+ expect_string(__wrap_fopen, mode, "r");
+
+ /* wrong CoreDumping key value */
+ assert(is_process_coredumping(123) == false);
+}
+
+static void safe_kill_positive(void **state)
+{
+ /* SIGKILL shouldn't be delivered if the process is coredumping */
+ will_return(__wrap_fopen, 1);
+ will_return(__wrap_fopen, 1);
+ expect_string(__wrap_fopen, pathname, "/proc/3/status");
+ expect_string(__wrap_fopen, mode, "r");
+
+ assert(safe_kill(3, SIGKILL) == 0);
+}
+
+static void safe_kill_negative(void **state)
+{
+ /* SIGUSR1 should be delivered always */
+ will_return(__wrap_kill, true);
+ expect_value(__wrap_kill, pid, 1);
+ expect_value(__wrap_kill, sig, SIGUSR1);
+ assert(safe_kill(1, SIGUSR1) == 0);
+
+ /* SIGKILL should be delivered if the process is not coredumping */
+ will_return(__wrap_fopen, 1);
+ will_return(__wrap_fopen, 0);
+ expect_string(__wrap_fopen, pathname, "/proc/2/status");
+ expect_string(__wrap_fopen, mode, "r");
+
+ will_return(__wrap_kill, true);
+ expect_value(__wrap_kill, pid, 2);
+ expect_value(__wrap_kill, sig, SIGKILL);
+ assert(safe_kill(2, SIGKILL) == 0);
+
+}
+
+int main(int argc, char* argv[])
+{
+ int r;
+ const struct CMUnitTest positive_tests[] = {
+ cmocka_unit_test(is_process_coredumping_positive),
+ cmocka_unit_test(safe_kill_positive),
+ };
+
+ const struct CMUnitTest negative_tests[] = {
+ cmocka_unit_test(is_process_coredumping_negative),
+ cmocka_unit_test(safe_kill_negative),
+ };
+
+ r = cmocka_run_group_tests(positive_tests, NULL, NULL);
+ if (r != 0)
+ return r;
+
+ r = cmocka_run_group_tests(negative_tests, NULL, NULL);
+ if (r != 0)
+ return r;
+
+ return r;
+}
+
+
+
+