From d5559a8207f79896129d734911f385d2d08ac024 Mon Sep 17 00:00:00 2001 From: Rafal Krypa Date: Fri, 6 Feb 2015 18:25:11 +0100 Subject: [PATCH 1/1] Prepare security-manager for master-slave mode This commit prepares security-manager for work in master/slave mode. In order to properly install/uninstall applications inside containers, security-manager inside container (slave) must delegate calls related to SMACK to security-manager outside a container (master). Since entire master/slave mode is a huge change, it is divided into two commits - this is the first one. Logic for master service and changes in service to work as slave are left for second commit. With this change security-manager launched without additional arguments should work as it did. Change-Id: If05cdeb2d2c35c046bf4cb46d884a3689dab57ad --- packaging/security-manager.spec | 6 ++ src/common/include/protocols.h | 2 + src/common/include/service_impl.h | 11 +++ src/common/protocols.cpp | 4 + src/common/service_impl.cpp | 15 ++++ src/server/CMakeLists.txt | 4 +- src/server/main/server-main.cpp | 86 ++++++++++++++++++--- src/server/service/include/master-service.h | 61 +++++++++++++++ src/server/service/include/service.h | 4 +- src/server/service/master-service.cpp | 111 ++++++++++++++++++++++++++++ src/server/service/service.cpp | 26 +++++-- systemd/CMakeLists.txt | 6 ++ systemd/security-manager-master.service.in | 10 +++ systemd/security-manager-master.socket | 13 ++++ systemd/security-manager-slave.service.in | 9 +++ systemd/security-manager-slave.socket | 10 +++ systemd/security-manager.service.in | 2 + systemd/security-manager.socket | 4 + 18 files changed, 363 insertions(+), 21 deletions(-) create mode 100644 src/server/service/include/master-service.h create mode 100644 src/server/service/master-service.cpp create mode 100644 systemd/security-manager-master.service.in create mode 100644 systemd/security-manager-master.socket create mode 100644 systemd/security-manager-slave.service.in create mode 100644 systemd/security-manager-slave.socket diff --git a/packaging/security-manager.spec b/packaging/security-manager.spec index 5269334..d6d259b 100644 --- a/packaging/security-manager.spec +++ b/packaging/security-manager.spec @@ -87,6 +87,8 @@ cp LICENSE %{buildroot}%{_datadir}/license/libsecurity-manager-client mkdir -p %{buildroot}/%{_unitdir}/sockets.target.wants ln -s ../security-manager.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager.socket +ln -s ../security-manager-master.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager-master.socket +ln -s ../security-manager-slave.socket %{buildroot}/%{_unitdir}/sockets.target.wants/security-manager-slave.socket %clean rm -rf %{buildroot} @@ -136,7 +138,11 @@ fi %{_libdir}/libsecurity-manager-commons.so.* %attr(-,root,root) %{_unitdir}/security-manager.* +%attr(-,root,root) %{_unitdir}/security-manager-master.* +%attr(-,root,root) %{_unitdir}/security-manager-slave.* %attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager.* +%attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager-master.* +%attr(-,root,root) %{_unitdir}/sockets.target.wants/security-manager-slave.* %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db %config(noreplace) %attr(0600,root,root) %{TZ_SYS_DB}/.security-manager.db-journal %{_datadir}/license/%{name} diff --git a/src/common/include/protocols.h b/src/common/include/protocols.h index 9f3b11b..8360a26 100644 --- a/src/common/include/protocols.h +++ b/src/common/include/protocols.h @@ -120,6 +120,8 @@ struct user_req { namespace SecurityManager { extern char const * const SERVICE_SOCKET; +extern char const * const MASTER_SERVICE_SOCKET; +extern char const * const SLAVE_SERVICE_SOCKET; enum class SecurityModuleCall { diff --git a/src/common/include/service_impl.h b/src/common/include/service_impl.h index 827496a..fa999b6 100644 --- a/src/common/include/service_impl.h +++ b/src/common/include/service_impl.h @@ -35,6 +35,17 @@ namespace SecurityManager { namespace ServiceImpl { /** + * Retrieves ID (UID and PID) of peer connected to socket + * + * @param[in] Socket file descriptor + * @param[out] UID of connected peer. Function does not modify the variable if ID retrieval fails. + * @param[out] PID of connected peer. Function does not modify the variable if ID retrieval fails. + * + * @return True if peer ID was successfully retrieved, false otherwise. + */ +bool getPeerID(int sock, uid_t &uid, pid_t &pid); + +/** * Process application installation request. * * @param[in] req installation request diff --git a/src/common/protocols.cpp b/src/common/protocols.cpp index 798b9d6..eac619a 100644 --- a/src/common/protocols.cpp +++ b/src/common/protocols.cpp @@ -32,6 +32,10 @@ namespace SecurityManager { char const * const SERVICE_SOCKET = SOCKET_PATH_PREFIX "security-manager.socket"; +char const * const MASTER_SERVICE_SOCKET = + SOCKET_PATH_PREFIX "security-manager-master.socket"; +char const * const SLAVE_SERVICE_SOCKET = + SOCKET_PATH_PREFIX "security-manager-slave.socket"; } // namespace SecurityManager diff --git a/src/common/service_impl.cpp b/src/common/service_impl.cpp index 7fd621c..20ee7a9 100644 --- a/src/common/service_impl.cpp +++ b/src/common/service_impl.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -159,6 +160,20 @@ static inline bool isSubDir(const char *parent, const char *subdir) return (*subdir == '/'); } +bool getPeerID(int sock, uid_t &uid, pid_t &pid) +{ + struct ucred cr; + socklen_t len = sizeof(cr); + + if (!getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cr, &len)) { + uid = cr.uid; + pid = cr.pid; + return true; + } + + return false; +} + static bool getUserAppDir(const uid_t &uid, std::string &userAppDir) { struct tzplatform_context *tz_ctx = nullptr; diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 753eb96..8890aa3 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -3,7 +3,7 @@ PKG_CHECK_MODULES(SERVER_DEP libsystemd-daemon ) -FIND_PACKAGE(Boost REQUIRED) +FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options) FIND_PACKAGE(Threads REQUIRED) INCLUDE_DIRECTORIES(SYSTEM @@ -27,6 +27,7 @@ SET(SERVER_SOURCES ${SERVER_PATH}/main/server-main.cpp ${SERVER_PATH}/service/base-service.cpp ${SERVER_PATH}/service/service.cpp + ${SERVER_PATH}/service/master-service.cpp ) ADD_EXECUTABLE(${TARGET_SERVER} ${SERVER_SOURCES}) @@ -39,6 +40,7 @@ TARGET_LINK_LIBRARIES(${TARGET_SERVER} ${TARGET_COMMON} ${CMAKE_THREAD_LIBS_INIT} ${SERVER_DEP_LIBRARIES} + ${Boost_LIBRARIES} ) INSTALL(TARGETS ${TARGET_SERVER} DESTINATION ${BIN_INSTALL_DIR}) diff --git a/src/server/main/server-main.cpp b/src/server/main/server-main.cpp index c9609e2..f8e1f71 100644 --- a/src/server/main/server-main.cpp +++ b/src/server/main/server-main.cpp @@ -28,22 +28,30 @@ #include #include +#include +#include + #include #include #include +#include + +namespace po = boost::program_options; IMPLEMENT_SAFE_SINGLETON(SecurityManager::Log::LogSystem); -#define REGISTER_SOCKET_SERVICE(manager, service) \ - registerSocketService(manager, #service) +#define REGISTER_SOCKET_SERVICE(manager, service, allocator) \ + registerSocketService(manager, #service, allocator) template -bool registerSocketService(SecurityManager::SocketManager &manager, const std::string& serviceName) +bool registerSocketService(SecurityManager::SocketManager &manager, + const std::string& serviceName, + const std::function& serviceAllocator) { T *service = NULL; try { - service = new T(); + service = serviceAllocator(); service->Create(); manager.RegisterSocketService(service); return true; @@ -62,12 +70,59 @@ bool registerSocketService(SecurityManager::SocketManager &manager, const std::s return false; } -int main(void) { - +int main(int argc, char* argv[]) +{ UNHANDLED_EXCEPTION_HANDLER_BEGIN { + // initialize logging SecurityManager::Singleton::Instance().SetTag("SECURITY_MANAGER"); + // parse arguments + bool masterMode = false, slaveMode = false; + po::options_description optDesc("Allowed options"); + + optDesc.add_options() + ("help,h", "Print this help message") + ("master,m", "Enable master mode") + ("slave,s", "Enable slave mode") + ; + + po::variables_map vm; + po::basic_parsed_options parsed = + po::command_line_parser(argc, argv).options(optDesc).allow_unregistered().run(); + + std::vector unrecognizedOptions = + po::collect_unrecognized(parsed.options, po::include_positional); + + if (!unrecognizedOptions.empty()) { + std::cerr << "Unrecognized options: "; + + for (auto& uo : unrecognizedOptions) { + std::cerr << ' ' << uo; + } + + std::cerr << std::endl << std::endl; + std::cerr << optDesc << std::endl; + + return EXIT_FAILURE; + } + + po::store(parsed, vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << optDesc << std::endl; + return EXIT_SUCCESS; + } + + masterMode = vm.count("master") > 0; + slaveMode = vm.count("slave") > 0; + + if (masterMode && slaveMode) { + LogError("Cannot be both master and slave!"); + return EXIT_FAILURE; + } + SecurityManager::FileLocker serviceLock(SecurityManager::SERVICE_LOCK_FILE, true); @@ -77,15 +132,24 @@ int main(void) { sigaddset(&mask, SIGPIPE); if (-1 == pthread_sigmask(SIG_BLOCK, &mask, NULL)) { LogError("Error in pthread_sigmask"); - return 1; + return EXIT_FAILURE; } LogInfo("Start!"); SecurityManager::SocketManager manager; - if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::Service)) { - LogError("Unable to create socket service. Exiting."); - return EXIT_FAILURE; + if (masterMode) { + if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::MasterService, + []() { return new SecurityManager::MasterService(); } )) { + LogError("Unable to create master socket service. Exiting."); + return EXIT_FAILURE; + } + } else { + if (!REGISTER_SOCKET_SERVICE(manager, SecurityManager::Service, + [&slaveMode]() { return new SecurityManager::Service(slaveMode); } )) { + LogError("Unable to create socket service. Exiting."); + return EXIT_FAILURE; + } } manager.MainLoop(); @@ -94,5 +158,5 @@ int main(void) { return EXIT_FAILURE; } UNHANDLED_EXCEPTION_HANDLER_END - return 0; + return EXIT_SUCCESS; } diff --git a/src/server/service/include/master-service.h b/src/server/service/include/master-service.h new file mode 100644 index 0000000..170bfd9 --- /dev/null +++ b/src/server/service/include/master-service.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Rafal Krypa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file master-service.h + * @author Lukasz Kostyra + * @author Rafal Krypa + * @brief Implementation of security-manager master service + */ + +#ifndef _SECURITY_MANAGER_MASTER_SERVICE_ +#define _SECURITY_MANAGER_MASTER_SERVICE_ + +#include "base-service.h" + +namespace SecurityManager { + +class MasterServiceException +{ +public: + DECLARE_EXCEPTION_TYPE(SecurityManager::Exception, Base) + DECLARE_EXCEPTION_TYPE(Base, InvalidAction) +}; + +class MasterService : + public SecurityManager::BaseService +{ +public: + MasterService(); + ServiceDescriptionVector GetServiceDescription(); + +private: + + /** + * Handle request from a client + * + * @param conn Socket connection information + * @param buffer Raw received data buffer + * @param interfaceID identifier used to distinguish source socket + * @return true on success + */ + bool processOne(const ConnectionID &conn, MessageBuffer &buffer, InterfaceID interfaceID); +}; + +} // namespace SecurityManager + +#endif // _SECURITY_MANAGER_MASTER_SERVICE_ diff --git a/src/server/service/include/service.h b/src/server/service/include/service.h index 883c989..765d0d0 100644 --- a/src/server/service/include/service.h +++ b/src/server/service/include/service.h @@ -40,10 +40,12 @@ class Service : public SecurityManager::BaseService { public: - Service(); + Service(const bool isSlave); ServiceDescriptionVector GetServiceDescription(); private: + const bool m_isSlave; + /** * Handle request from a client * diff --git a/src/server/service/master-service.cpp b/src/server/service/master-service.cpp new file mode 100644 index 0000000..2afae00 --- /dev/null +++ b/src/server/service/master-service.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Rafal Krypa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +/* + * @file master-service.cpp + * @author Lukasz Kostyra + * @author Rafal Krypa + * @brief Implementation of security-manager master service. + */ + +#include + +#include +#include + +#include "protocols.h" +#include "master-service.h" +#include "service_impl.h" + +namespace SecurityManager { + +const InterfaceID IFACE = 1; + +MasterService::MasterService() +{ +} + +GenericSocketService::ServiceDescriptionVector MasterService::GetServiceDescription() +{ + return ServiceDescriptionVector { + {MASTER_SERVICE_SOCKET, "security-manager-master", IFACE}, + }; +} + +bool MasterService::processOne(const ConnectionID &conn, MessageBuffer &buffer, + InterfaceID interfaceID) +{ + LogDebug("Iteration begin. Interface = " << interfaceID); + + //waiting for all data + if (!buffer.Ready()) { + return false; + } + + MessageBuffer send; + bool retval = false; + + uid_t uid; + pid_t pid; + + if (!ServiceImpl::getPeerID(conn.sock, uid, pid)) { + LogError("Closing socket because of error: unable to get peer's uid and pid"); + m_serviceManager->Close(conn); + return false; + } + + if (IFACE == interfaceID) { + Try { + // deserialize API call type + int call_type_int; + Deserialization::Deserialize(buffer, call_type_int); + SecurityModuleCall call_type = static_cast(call_type_int); + + switch (call_type) { + default: + LogError("Invalid call: " << call_type_int); + Throw(MasterServiceException::InvalidAction); + } + // if we reach this point, the protocol is OK + retval = true; + } Catch (MessageBuffer::Exception::Base) { + LogError("Broken protocol."); + } Catch (MasterServiceException::Base) { + LogError("Broken protocol."); + } catch (const std::exception &e) { + LogError("STD exception " << e.what()); + } catch (...) { + LogError("Unknown exception"); + } + } + else { + LogError("Wrong interface"); + } + + if (retval) { + //send response + m_serviceManager->Write(conn, send.Pop()); + } else { + LogError("Closing socket because of error"); + m_serviceManager->Close(conn); + } + + return retval; +} + + +} // namespace SecurityManager diff --git a/src/server/service/service.cpp b/src/server/service/service.cpp index e0925b1..522356f 100644 --- a/src/server/service/service.cpp +++ b/src/server/service/service.cpp @@ -37,19 +37,29 @@ namespace SecurityManager { const InterfaceID IFACE = 1; -Service::Service() +Service::Service(const bool isSlave): + m_isSlave(isSlave) { } GenericSocketService::ServiceDescriptionVector Service::GetServiceDescription() { - return ServiceDescriptionVector { - {SERVICE_SOCKET, /* path */ - "*", /* smackLabel label (not used, we rely on systemd) */ - IFACE, /* InterfaceID */ - false, /* useSendMsg */ - true}, /* systemdOnly */ - }; + if (m_isSlave) + return ServiceDescriptionVector { + {SLAVE_SERVICE_SOCKET, /* path */ + "*", /* smackLabel label (not used, we rely on systemd) */ + IFACE, /* InterfaceID */ + false, /* useSendMsg */ + true}, /* systemdOnly */ + }; + else + return ServiceDescriptionVector { + {SERVICE_SOCKET, /* path */ + "*", /* smackLabel label (not used, we rely on systemd) */ + IFACE, /* InterfaceID */ + false, /* useSendMsg */ + true}, /* systemdOnly */ + }; } static bool getPeerID(int sock, uid_t &uid, pid_t &pid, std::string &smackLabel) diff --git a/systemd/CMakeLists.txt b/systemd/CMakeLists.txt index 90c0ec1..02814a5 100644 --- a/systemd/CMakeLists.txt +++ b/systemd/CMakeLists.txt @@ -1,8 +1,14 @@ CONFIGURE_FILE(security-manager.service.in security-manager.service @ONLY) +CONFIGURE_FILE(security-manager-master.service.in security-manager-master.service @ONLY) +CONFIGURE_FILE(security-manager-slave.service.in security-manager-slave.service @ONLY) INSTALL(FILES security-manager.service security-manager.socket + security-manager-master.service + security-manager-master.socket + security-manager-slave.service + security-manager-slave.socket DESTINATION ${SYSTEMD_INSTALL_DIR} ) diff --git a/systemd/security-manager-master.service.in b/systemd/security-manager-master.service.in new file mode 100644 index 0000000..ef14a57 --- /dev/null +++ b/systemd/security-manager-master.service.in @@ -0,0 +1,10 @@ +[Unit] +Description=Start the security manager master +ConditionVirtualization=!lxc +ConditionPathExists=/usr/share/.zones/enabled + +[Service] +Type=notify +ExecStart=@BIN_INSTALL_DIR@/security-manager --master + +Sockets=security-manager-master.socket diff --git a/systemd/security-manager-master.socket b/systemd/security-manager-master.socket new file mode 100644 index 0000000..d41eae0 --- /dev/null +++ b/systemd/security-manager-master.socket @@ -0,0 +1,13 @@ +[Socket] +ListenStream=/run/security-manager-master.socket +SocketMode=0700 +SmackLabelIPIn=System +SmackLabelIPOut=System +Service=security-manager-master.service + +[Unit] +ConditionVirtualization=!lxc +ConditionPathExists=/usr/share/.zones/enabled + +[Install] +WantedBy=sockets.target diff --git a/systemd/security-manager-slave.service.in b/systemd/security-manager-slave.service.in new file mode 100644 index 0000000..6eb7505 --- /dev/null +++ b/systemd/security-manager-slave.service.in @@ -0,0 +1,9 @@ +[Unit] +Description=Start the security manager slave +ConditionVirtualization=lxc + +[Service] +Type=notify +ExecStart=@BIN_INSTALL_DIR@/security-manager --slave + +Sockets=security-manager-slave.socket diff --git a/systemd/security-manager-slave.socket b/systemd/security-manager-slave.socket new file mode 100644 index 0000000..8d0a2c6 --- /dev/null +++ b/systemd/security-manager-slave.socket @@ -0,0 +1,10 @@ +[Socket] +ListenStream=/run/security-manager-slave.socket +Symlinks=/run/security-manager.socket +SocketMode=0777 +SmackLabelIPIn=* +SmackLabelIPOut=@ +Service=security-manager-slave.service + +[Unit] +ConditionVirtualization=lxc diff --git a/systemd/security-manager.service.in b/systemd/security-manager.service.in index 23fd1b2..f15ab90 100644 --- a/systemd/security-manager.service.in +++ b/systemd/security-manager.service.in @@ -1,5 +1,7 @@ [Unit] Description=Start the security manager +ConditionVirtualization=!lxc +ConditionPathExists=!/usr/share/.zones/enabled [Service] Type=notify diff --git a/systemd/security-manager.socket b/systemd/security-manager.socket index af1c1da..95411e8 100644 --- a/systemd/security-manager.socket +++ b/systemd/security-manager.socket @@ -7,5 +7,9 @@ SmackLabelIPOut=@ # TODO: move to separate systemd service Service=security-manager.service +[Unit] +ConditionVirtualization=!lxc +ConditionPathExists=!/usr/share/.zones/enabled + [Install] WantedBy=sockets.target -- 2.7.4