Make security-manager run without root 80/324780/3
authorFilip Skrzeczkowski <f.skrzeczkow@samsung.com>
Mon, 26 May 2025 10:21:59 +0000 (12:21 +0200)
committerFilip Skrzeczkowski <f.skrzeczkow@samsung.com>
Tue, 27 May 2025 14:21:28 +0000 (16:21 +0200)
Change-Id: I31c44c7e57f324aa08f393a4051b453928e45eb4

src/server/main/server-main.cpp

index b5ec89faaea5eedfbdc647011d86be4a29e3d3c3..bb3ac743397827460c02327e5ba4e1a0f131d2b5 100644 (file)
  * @version     1.0
  * @brief       Implementation of security-manager on basis of security-server
  */
+#include <grp.h>
 #include <stdlib.h>
 #include <signal.h>
+#include <linux/capability.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
 
+#include <dpl/errno_string.h>
 #include <dpl/log/log.h>
 #include <dpl/singleton.h>
 
@@ -38,6 +43,7 @@
 #include <mount-namespace.h>
 #include <socket-manager.h>
 #include <service-file-locker.h>
+#include <utils.h>
 
 #include <service.h>
 #include <worker.h>
@@ -102,6 +108,33 @@ int security_manager(Channel channel)
     return 0;
 }
 
+// Changes the UID to non-root while retaining all capabilities
+void dropRoot()
+{
+    if (-1 == prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0))
+        LogAndThrowErrno(SecurityManager::Exception, "Error in prctl");
+
+    // Save current caps
+    std::unique_ptr<std::remove_pointer_t<cap_t>, decltype(&cap_free)>
+        caps(cap_get_proc(), cap_free);
+    if (!caps)
+        LogAndThrowErrno(SecurityManager::Exception, "Error in cap_get_proc");
+
+    // Set the system_share group to get +x in app directories
+    gid_t group = getGidByName("system_share");
+    if (setgroups(1, &group))
+        LogAndThrowErrno(SecurityManager::Exception, "Failed to set supplementary group " << group);
+
+    // Change uid to non-root
+    uid_t uid = getUidByName("security_fw");
+    if (-1 == setuid(uid))
+        LogAndThrowErrno(SecurityManager::Exception, "Failed to set uid " << uid);
+
+    // Reclaim lost caps
+    if(-1 == cap_set_proc(caps.get()))
+        LogAndThrowErrno(SecurityManager::Exception, "Error in cap_set_proc ");
+}
+
 int main()
 {
     UNHANDLED_EXCEPTION_HANDLER_BEGIN
@@ -119,6 +152,14 @@ int main()
             return EXIT_FAILURE;
         }
 
+        try {
+            dropRoot();
+        }
+        catch (const SecurityManager::Exception &exception) {
+            LogError("Error while dropping root");
+            return EXIT_FAILURE;
+        }
+
         if (!MountNS::isPrivacyPrivilegeMountNamespaceEnabled()) {
             // Lagacy systems without privacy privilege mount namespace.
             // In this case security-manager will run without WORKER