Drop privileges when started by kernel 52/217352/4
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>
Thu, 7 Nov 2019 10:41:59 +0000 (11:41 +0100)
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>
Thu, 21 Nov 2019 11:53:41 +0000 (12:53 +0100)
Change-Id: I3fa61c9f7b89f3fe7b8c7a8bedd8e852bdccf404

packaging/crash-worker.spec
src/crash-manager/CMakeLists.txt
src/crash-manager/main.c

index 894ba34..587f6f2 100644 (file)
@@ -31,6 +31,8 @@ BuildRequires:  pkgconfig(libunwind-generic)
 BuildRequires:  libelf-devel libelf
 BuildRequires:  libebl-devel libebl
 BuildRequires:  libdw-devel libdw
+BuildRequires:  libcap-devel
+
 %if %{with doc}
 BuildRequires:  doxygen
 %endif
index b38a084..591a3ad 100644 (file)
@@ -43,7 +43,7 @@ SET_TARGET_PROPERTIES(libcrash-manager PROPERTIES OUTPUT_NAME crash-manager)
 TARGET_LINK_LIBRARIES(libcrash-manager ${crash-manager_pkgs_LDFLAGS})
 
 ADD_EXECUTABLE(${PROJECT_NAME} ${CRASH_MANAGER_SRCS})
-TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${crash-manager_pkgs_LDFLAGS} -pie -lrt libcrash-manager)
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${crash-manager_pkgs_LDFLAGS} -pie -lcap -lrt libcrash-manager)
 
 set(CRASH_POPUP crash-popup-launch)
 ADD_EXECUTABLE(${CRASH_POPUP} ${CRASH_POPUP}.c)
index 53211e8..ed7c9af 100644 (file)
@@ -1,9 +1,18 @@
 #include <getopt.h>
+#include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "shared/log.h"
+#include "shared/util.h"
 #include "crash-manager.h"
 
+#define USER_NAME "crash_worker"
+
 static void print_help(const char *name)
 {
        printf("Syntax: %s [OPTIONS]\n"
@@ -124,9 +133,86 @@ static bool parse_args(struct crash_info *cinfo, int argc, char *argv[])
 #undef GET_NUMBER
 }
 
+static bool set_caps(const cap_flag_t flag)
+{
+       bool res = false;
+       cap_t caps;
+       cap_value_t cap_list[5] = {
+               CAP_DAC_READ_SEARCH,
+               CAP_DAC_OVERRIDE,
+               CAP_KILL,
+               CAP_SYS_PTRACE,
+               CAP_SYSLOG
+       };
+
+       caps = cap_get_proc();
+       if (caps == NULL) {
+               _E("cap_get_proc() error: %m");
+               goto exit;
+       }
+
+       if (cap_set_flag(caps, flag, ARRAY_SIZE(cap_list), cap_list, CAP_SET) == -1) {
+               _E("cap_set_flag() error: %m");
+               goto exit;
+       }
+
+       if (cap_set_proc(caps) == -1) {
+               _E("cap_set_proc() error: %m");
+               goto exit;
+       }
+
+       res = true;
+exit:
+       if (caps != NULL && cap_free(caps) == -1) {
+               _E("cap_free() error: %m");
+               res = false;
+       }
+       return res;
+}
+
+static bool drop_privileges(const char *user_name)
+{
+       struct passwd *user_info = getpwnam(user_name);
+       if (!user_info) {
+               _E("getpwnam() error: %m");
+               return false;
+       }
+
+       if (!set_caps(CAP_PERMITTED))
+               return false;
+
+       /*
+        * setuid() clears capabilities, so we need to set PR_SET_KEEPCAPS and
+        * restore them after that
+        */
+       if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
+               _E("prctl(PR_SET_KEEPCAPS) error: %m");
+               return false;
+       }
+
+       if (setuid(user_info->pw_uid) == -1) {
+               _E("setuid() error: %m\n");
+               return false;
+       }
+
+       if (!set_caps(CAP_EFFECTIVE))
+               return false;
+
+       if (!set_caps(CAP_INHERITABLE))
+               return false;
+
+       return true;
+}
 
 int main(int argc, char *argv[])
 {
+       int res;
+
+       if (!drop_privileges(USER_NAME)) {
+               res = EXIT_FAILURE;
+               goto exit;
+       }
+
        struct crash_info cinfo;
 
        /*
@@ -141,9 +227,10 @@ int main(int argc, char *argv[])
        if (!parse_args(&cinfo, argc, argv))
                return EXIT_FAILURE;
 
-       int res = crash_manager_direct(&cinfo) ? EXIT_SUCCESS : EXIT_FAILURE;
+       res = crash_manager_direct(&cinfo) ? EXIT_SUCCESS : EXIT_FAILURE;
 
        crash_manager_free(&cinfo);
+exit:
        _I("Exiting with exit code %d", res);
        return res;
 }