Add security_manager_shm_open 20/74520/17
authorBartlomiej Grzelewski <b.grzelewski@samsung.com>
Mon, 13 Jun 2016 10:06:19 +0000 (12:06 +0200)
committerRafal Krypa <r.krypa@samsung.com>
Tue, 29 Nov 2016 15:58:06 +0000 (16:58 +0100)
This function will create file that may be used
by shm_open and mmap functions. If the file
exists noting is done.

Change-Id: Ifdfdf15df96fb67faa4340d113445527c77ba60f

12 files changed:
src/client/client-security-manager.cpp
src/common/CMakeLists.txt
src/common/config.cpp
src/common/credentials.cpp
src/common/include/config.h
src/common/include/credentials.h
src/common/include/protocols.h
src/common/include/service_impl.h
src/common/service_impl.cpp
src/include/app-runtime.h
src/server/service/include/service.h
src/server/service/service.cpp

index c398146596bf1a68b7460034ebf1c65927fe8034..82c2407f820cc495500ff6d802857a6804c2c1f0 100644 (file)
 #include <unistd.h>
 #include <grp.h>
 #include <dirent.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/xattr.h>
 #include <sys/smack.h>
 #include <sys/capability.h>
 #include <sys/syscall.h>
+#include <sys/mman.h>
 #include <signal.h>
 
 #include <dpl/log/log.h>
@@ -1515,3 +1517,64 @@ int security_manager_paths_register(const path_req *p_req)
         return retval;
     });
 }
+
+SECURITY_MANAGER_API
+int security_manager_shm_open(const char *name, int oflag, mode_t mode, const char *app_name)
+{
+    using namespace SecurityManager;
+    return try_catch([&]() -> int {
+        if (!name || !app_name) {
+            errno = EINVAL;
+            return -1;
+        }
+
+        int fd = shm_open(name, oflag, mode);
+        if (fd < 0)
+            return -1;
+
+        auto scopeClose = makeUnique(&fd, [](int *ptr) -> void { if (*ptr >= 0) close(*ptr); });
+
+        MessageBuffer send, recv;
+        Serialization::Serialize(send,
+                                 (int)SecurityModuleCall::SHM_APP_NAME,
+                                 std::string(name),
+                                 std::string(app_name));
+
+        int retval = sendToServer(SERVICE_SOCKET, send.Pop(), recv);
+        if (retval != SECURITY_MANAGER_SUCCESS) {
+            // Let's propagate errno
+            LogError("Error in sendToServer. Error code: " << retval);
+            return -1;
+        }
+
+        Deserialization::Deserialize(recv, retval);
+        switch(retval) {
+        case SECURITY_MANAGER_SUCCESS:
+            scopeClose.release();
+            return fd;
+        case SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED:
+            LogError("Error: operation not permitted");
+            errno = EPERM;
+            break;
+        case SECURITY_MANAGER_ERROR_ACCESS_DENIED:
+            LogError("Error access denied");
+            errno = EACCES;
+            break;
+        case SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT:
+        case SECURITY_MANAGER_ERROR_INPUT_PARAM:
+            LogError("Error input param");
+            errno = EINVAL;
+            break;
+        case SECURITY_MANAGER_ERROR_MEMORY:
+            LogError("Error memory allocation");
+            errno = ENOMEM;
+            break;
+        default:
+            LogError("Error internal security-manager error");
+            errno = ECONNABORTED;
+            break;
+        }
+        return -1;
+    });
+}
+
index bff232c10d74b288ea87193560ae3aec5f5fa1d3..a91ed2dfb76b1d0c2004220fef3ac4c7df30aa52 100644 (file)
@@ -88,6 +88,7 @@ TARGET_LINK_LIBRARIES(${TARGET_COMMON}
     ${COMMON_DEP_LIBRARIES}
     ${DLOG_DEP_LIBRARIES}
     -lcrypt
+    rt
     )
 
 INSTALL(TARGETS ${TARGET_COMMON} DESTINATION ${LIB_INSTALL_DIR})
index fa12770d34693b8480c3db3df11bd0894a5f30b5..2f38867c6b40297ebd4f4ed1b61e3e50c1066b64 100644 (file)
@@ -36,6 +36,7 @@ const std::string PRIVILEGE_USER_ADMIN       = "http://tizen.org/privilege/inter
 const std::string PRIVILEGE_POLICY_USER      = "http://tizen.org/privilege/notexist";
 const std::string PRIVILEGE_POLICY_ADMIN     = "http://tizen.org/privilege/internal/usermanagement";
 const std::string PRIVILEGE_APPSHARING_ADMIN = "http://tizen.org/privilege/notexist";
+const std::string PRIVILEGE_SHM              = "http://tizen.org/privilege/internal/shm";
 
 const std::string APPS_LABELS_FILE = "apps-labels";
 const std::string SKEL_DIR = "/etc/skel";
index 9bf8d708d404296178ca34e710221e6e596dfb6a..c0640a754250f6610c2891da4690e21602f6a455 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <unistd.h>
+#include <sys/stat.h>
 #include <sys/socket.h>
 
 #include "smack-check.h"
@@ -45,4 +46,13 @@ Credentials Credentials::getCredentialsFromSocket(int sock)
     return Credentials(cr.pid, cr.uid, cr.gid, SmackLabels::getSmackLabelFromSocket(sock));
 }
 
+Credentials Credentials::getCredentialsFromFd(int fd)
+{
+    struct stat buf;
+    if (-1 == fstat(fd, &buf))
+        ThrowMsg(Exception::FdError, "Failed to read credentials from filefd " << fd);
+
+    return Credentials(-1, buf.st_uid, buf.st_gid, SmackLabels::getSmackLabelFromFd(fd));
+}
+
 } // namespace SecurityManager
index ab3c78f21ce09bee5a12f400ba425e70093ba8ad..f8ac57a3d393975b5daa934b1fa330297e4ed5f7 100644 (file)
@@ -40,6 +40,7 @@ extern const std::string PRIVILEGE_USER_ADMIN;
 extern const std::string PRIVILEGE_POLICY_USER;
 extern const std::string PRIVILEGE_POLICY_ADMIN;
 extern const std::string PRIVILEGE_APPSHARING_ADMIN;
+extern const std::string PRIVILEGE_SHM;
 
 /* Files used in permitted label managment */
 extern const std::string APPS_LABELS_FILE;
index ea0b0b20afe98213a106d13c0181c8fdef8e4e99..f8a7dce58fbdab40788238279ee47f6918cde3f7 100644 (file)
@@ -39,11 +39,13 @@ public:
     Credentials() = delete;
     static Credentials getCredentialsFromSelf(void);
     static Credentials getCredentialsFromSocket(int socket);
+    static Credentials getCredentialsFromFd(int fd);
 
     class Exception {
     public:
         DECLARE_EXCEPTION_TYPE(SecurityManager::Exception, Base)
         DECLARE_EXCEPTION_TYPE(Base, SocketError)
+        DECLARE_EXCEPTION_TYPE(Base, FdError)
     };
 
 private:
index c93fb14acf95cd3f636107746459906fb1fd46a9..fcf13141235dfbe9093b184cabd785102f04725b 100644 (file)
@@ -87,6 +87,7 @@ enum class SecurityModuleCall
     PATHS_REGISTER,
     GROUPS_FOR_UID,
     LABEL_FOR_PROCESS,
+    SHM_APP_NAME,
     NOOP = 0x90,
 };
 
index 9a7f7e737e27c314e4c4d1fb5f2c225a88dae893..84177fb53f8f1c95f2396b236aa47284deb3b7c9 100644 (file)
@@ -234,6 +234,19 @@ public:
      * @return API return code, as defined in protocols.h
      */
     int labelForProcess(const std::string &appName, std::string &label);
+    /*
+     * Request for access to shared memory segment for
+     * appName application.
+     *
+     * @param[in] creds credentials of the requesting process
+     * @param[in] name shared memory identifier
+     * @param[in] appName application identifier
+     *
+     * @return API return code, as defined in protocols.h
+     */
+    int shmAppName(const Credentials &creds,
+                   const std::string &shmName,
+                   const std::string &appName);
 private:
     bool authenticate(const Credentials &creds, const std::string &privilege);
 
@@ -299,7 +312,6 @@ private:
     Cynara m_cynara;
     PrivilegeDb m_priviligeDb;
     CynaraAdmin m_cynaraAdmin;
-
 };
 
 } /* namespace SecurityManager */
index a8ac5896fc403823adff22458993b020f28765c1..54a27fdb08d4750d5d061b6b8d5d73439e1fe7d9 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/xattr.h>
 #include <limits.h>
 #include <pwd.h>
+#include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -1648,4 +1649,60 @@ int ServiceImpl::labelForProcess(const std::string &appName, std::string &label)
     return SECURITY_MANAGER_SUCCESS;
 }
 
+int ServiceImpl::shmAppName(const Credentials &creds, const std::string &shmName, const std::string &appName)
+{
+    try {
+        if (shmName.empty() || appName.empty())
+            return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+
+        if (!PrivilegeDb::getInstance().AppNameExists(appName)) {
+            LogError("Unknown application id: " << appName);
+            return SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT;
+        }
+
+        if (!authenticate(creds, Config::PRIVILEGE_SHM)) {
+            LogError("Request from uid=" << creds.uid << ", Smack=" << creds.label << " for shm denied");
+            return SECURITY_MANAGER_ERROR_AUTHENTICATION_FAILED;
+        }
+
+        std::string label = getAppProcessLabel(appName);
+
+        int fd = shm_open(shmName.c_str(), O_RDWR, 0);
+        if (fd < 0) {
+            LogError("Error in shm_open");
+            return SECURITY_MANAGER_ERROR_INPUT_PARAM;
+        }
+
+        auto scopeClose = makeUnique(&fd, [](int *ptr) -> void { if (*ptr >= 0) close(*ptr);});
+
+        Credentials fdCreds = Credentials::getCredentialsFromFd(fd);
+
+        if (fdCreds.label == label) {
+            // Nothing to do. The file already has proper label.
+            // Client called this function twice?
+            LogDebug("Noting to do. File have already label: " << label << " The client probably called this api twice.");
+            return SECURITY_MANAGER_SUCCESS;
+        }
+
+        if ((creds.label != fdCreds.label) || (creds.uid != fdCreds.uid)) {
+            LogDebug("Client (smack: " << creds.label <<", pid: " << creds.pid
+                << ") does not have permission to access shared memory file (segment name: "
+                << shmName << ").");
+            return SECURITY_MANAGER_ERROR_ACCESS_DENIED;
+        }
+
+        SmackLabels::setSmackLabelForFd(fd, label);
+    } catch (const CynaraException::Base &e) {
+        LogError("Error while querying Cynara for permissions: " << e.DumpToString());
+        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    } catch (const SmackException::Base &e) {
+        LogError("Error while set/get smack label in /dev/shm: " << e.DumpToString());
+        return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+    } catch (const std::bad_alloc &e) {
+        LogError("Memory allocation failed: " << e.what());
+        return SECURITY_MANAGER_ERROR_MEMORY;
+    }
+    return SECURITY_MANAGER_SUCCESS;
+}
+
 } /* namespace SecurityManager */
index ee4d2de5221dbbe1645bcbec80c639fc3a3b23dc..6e1f03b3493b4861d6f87c00188c20902407355b 100644 (file)
@@ -205,6 +205,20 @@ int security_manager_identify_app_from_cynara_client(const char *client, char **
 int security_manager_app_has_privilege(const char *app_id, const char *privilege,
                                        uid_t uid, int *result);
 
+/**
+ * This function creates descriptor that may be used as shared memory segment
+ * with app_id application.
+ *
+ * \param[in]  name       This value is passed to shm_open as first parameter (man 3 shm_open for details)
+ * \param[in]  oflag      This value is passed to shm_open as second parameter (man 3 shm_open for details)
+ * \param[in]  mode       This value is passed to shm_open as third parameter (man 3 shm_open for details)
+ * \param[in]  app_id     Identifier of application that will gain access to shared memory segment
+ * \return file descriptor or -1 on error. If -1 is returned then errno will be set. Errno == ECONNABORTED
+ *                        means that the security-manager server failed and did not return any information
+ *                        about error.
+ */
+int security_manager_shm_open(const char *name, int oflag, mode_t mode, const char *app_id);
+
 #ifdef __cplusplus
 }
 #endif
index aed44d8bf0821183ab2ebac1826091db89ea1ca3..a1eeb4dc7e24c8f60fe621a45d734e206b02be06 100644 (file)
@@ -194,6 +194,15 @@ private:
      * @param  send   Raw data buffer to be sent
      */
     void processLabelForProcess(MessageBuffer &buffer, MessageBuffer &send);
+
+    /**
+     * Process shared memory access request
+     *
+     * @param  recv   Raw received data buffer
+     * @param  send   Raw data buffer to be sent
+     * @param  creds  credentials of the requesting process
+     */
+    void processShmAppName(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds);
 };
 
 } // namespace SecurityManager
index 043224246bca8e2e715b8b57b93aa94b12791229..fe4f865b99c5b190c424fe918ecd5d8e0d9fa548 100644 (file)
@@ -147,6 +147,9 @@ bool Service::processOne(const ConnectionID &conn, MessageBuffer &buffer,
                 case SecurityModuleCall::LABEL_FOR_PROCESS:
                     processLabelForProcess(buffer, send);
                     break;
+                case SecurityModuleCall::SHM_APP_NAME:
+                    processShmAppName(buffer, send, creds);
+                    break;
                 default:
                     LogError("Invalid call: " << call_type_int);
                     Throw(ServiceException::InvalidAction);
@@ -406,4 +409,13 @@ void Service::processLabelForProcess(MessageBuffer &buffer, MessageBuffer &send)
     if (ret == SECURITY_MANAGER_SUCCESS)
         Serialization::Serialize(send, label);
 }
+
+void Service::processShmAppName(MessageBuffer &recv, MessageBuffer &send, const Credentials &creds)
+{
+    std::string shmName, appName;
+    Deserialization::Deserialize(recv, shmName, appName);
+    int ret = serviceImpl.shmAppName(creds, shmName, appName);
+    Serialization::Serialize(send, ret);
+}
+
 } // namespace SecurityManager