Fix for synchronization of per-thread mount namespace setup 99/212399/7
authorTomasz Swierczek <t.swierczek@samsung.com>
Wed, 21 Aug 2019 06:48:15 +0000 (08:48 +0200)
committerTomasz Swierczek <t.swierczek@samsung.com>
Fri, 23 Aug 2019 10:11:39 +0000 (10:11 +0000)
According to manual (1):

A process may not be reassociated with a new mount namespace
if it is multithreaded.

Also, unshare system call (2) is only creating new namespace
for the caller thread. This means that application candidate
processes that have more than 1 thread are doomed to always have
some threads still in the main mount namespace, without
enforcement of privilege policy connected to mount namespaces.
This renders the mount-namespace-based access control a bad solution.

This patch introduces a special API call to be used by app launchers
just to prepare app candidate processes. This API call doesn't take
any arguments - it just checks if mount-namespaces are enabled
and if yes, just calls unshare(), checking beforehand if the process
has only one thread.

(1) : http://man7.org/linux/man-pages/man2/setns.2.html
(2) : http://man7.org/linux/man-pages/man1/unshare.1.html

Change-Id: I82aefca3d5eb4915041df99ff0313896cbc769cb

src/client/client-security-manager.cpp
src/include/app-runtime.h

index dac0f6b455ac43e784d64c8d05fccac1fc0506a7..cc3d7bd6c5a5ba1443710c3e71a8c9497089ac22 100644 (file)
@@ -807,16 +807,29 @@ static int setupMountNamespace(const std::string &appProcessLabel, std::vector<s
     return SECURITY_MANAGER_SUCCESS;
 }
 
-static inline int security_manager_create_namespace_internal(const std::string &app_label)
+SECURITY_MANAGER_API
+int security_manager_prepare_app_candidate(void)
+{
+    return try_catch([&]() -> int {
+        LogDebug("security_manager_prepare_app_candidate() called");
+        if (!MountNS::isMountNamespaceEnabled())
+            return SECURITY_MANAGER_SUCCESS;
+
+        FS::FileNameVector files = FS::getSubDirectoriesFromDirectory("/proc/self/task");
+        if (files.size() > 3) { // 3 because we have ., we have .. and we should have only one thread here
+            LogError("Too many threads in current process, can't switch to new namespace safely in multithreaded program");
+            return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+        }
+        return MountNS::createMountNamespace();
+    });
+}
+
+static inline int security_manager_setup_namespace_internal(const std::string &app_label)
 {
     if (!MountNS::isMountNamespaceEnabled())
         return SECURITY_MANAGER_SUCCESS;
 
-    int ret = MountNS::createMountNamespace();
-    if (ret != SECURITY_MANAGER_SUCCESS)
-        return ret;
-
-    ret = MountNS::makeMountSlave("/");
+    int ret = MountNS::makeMountSlave("/");
     if (ret != SECURITY_MANAGER_SUCCESS)
         return ret;
 
@@ -873,7 +886,7 @@ int security_manager_prepare_app(const char *app_name)
             return ret;
         }
 
-        ret = security_manager_create_namespace_internal(app_label);
+        ret = security_manager_setup_namespace_internal(app_label);
         if (ret != SECURITY_MANAGER_SUCCESS) {
             LogError("Unable to setup namespace for application " << app_name);
             return ret;
index c51e6269c8f83c21067ede9e1c224cea9d97fed9..96c7b46dd75d2ccd642c038aaf93647dd5575b4a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ *  Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *  Contact: Rafal Krypa <r.krypa@samsung.com>
  *
@@ -76,14 +76,30 @@ int security_manager_drop_process_privileges(void);
 
 /**
  * A convenience function for launchers for preparing security context for an
- * application process. It should be called after fork in the new process, before
- * running the application in it.
- * It is aimed to cover most common cases and will internally call other, more
- * specialized security-manager functions for launchers.
- * Currently it just calls:
- * - security_manager_set_process_label_from_appid
- * - security_manager_set_process_groups_from_appid
- * - security_manager_drop_process_privileges
+ * application candidate process. It is aimed to cover these actions that
+ * are generic to all kinds of applications and MUST be called
+ * in single-threaded environment, after fork(), before the application launcher
+ * calls exec() on app candidate process binary (custom app loader).
+ *
+ * On systems with configured mount namespaces for privilege access control
+ * (non-empty file privilege-mount.list), this currently only sets up the new
+ * mount namespace.
+ *
+ * On systems without mount namespaces-controlled privileges, this is currently
+ * a no-op.
+ *
+ * \return API return code or error code
+ */
+int security_manager_prepare_app_candidate(void);
+
+/**
+ * A convenience function for launchers for preparing security context for an
+ * application process. It should be called before running actual application code.
+ *
+ * This function has to be called in a process where security_manager_prepare_app_candidate() was
+ * already called and all existing threads are already in the same namespaces.
+ *
+ * This function can be called in multithreaded environment.
  *
  * \param[in] app_id  Application identifier
  * \return API return code or error code