From: Jacek Bukarewicz Date: Tue, 27 May 2014 12:46:06 +0000 (+0200) Subject: Installation/uninstallation of package-specific smack rules X-Git-Tag: submit/rv/20140618.160634~12 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ed1e558fb166d8019512b6c02e899d1a1544e756;p=platform%2Fcore%2Fsecurity%2Fsecurity-server.git Installation/uninstallation of package-specific smack rules On installation rules are generated from predefined template, applied to the kernel and saved to disk so they are loaded on system boot. On uninstallation package-specific rules are revoked from kernel and removed from disk. Change-Id: Ib3ce4ecf909c4fe3c6bc1f5a77e24737b7acf918 --- diff --git a/app-rules-template.smack b/app-rules-template.smack new file mode 100644 index 0000000..543e80c --- /dev/null +++ b/app-rules-template.smack @@ -0,0 +1,6 @@ +System ~APP~ rwx +~APP~ System wx +~APP~ System::Shared rx +~APP~ System::Run rwxat +~APP~ System::Log rwxa +~APP~ _ l diff --git a/packaging/security-server.spec b/packaging/security-server.spec index a0f15f1..cbbc9df 100644 --- a/packaging/security-server.spec +++ b/packaging/security-server.spec @@ -103,6 +103,8 @@ cp LICENSE %{buildroot}/usr/share/license/libsecurity-server-client cp LICENSE %{buildroot}/usr/share/license/libsecurity-manager-client mkdir -p %{buildroot}/etc/security/ cp security-server-audit.conf %{buildroot}/etc/security/ +mkdir -p %{buildroot}/etc/smack/ +cp app-rules-template.smack %{buildroot}/etc/smack/ %make_install mkdir -p %{buildroot}/usr/lib/systemd/system/multi-user.target.wants @@ -174,7 +176,6 @@ fi %attr(-,root,root) /usr/lib/systemd/system/security-server-cookie-check.socket %attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-server-app-privilege-by-name.socket %attr(-,root,root) /usr/lib/systemd/system/security-server-app-privilege-by-name.socket -%attr(-,root,root) /etc/security/security-server-audit.conf %attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-server-password-check.socket %attr(-,root,root) /usr/lib/systemd/system/security-server-password-check.socket %attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-server-password-set.socket @@ -183,7 +184,8 @@ fi %attr(-,root,root) /usr/lib/systemd/system/security-server-password-reset.socket %attr(-,root,root) /usr/lib/systemd/system/sockets.target.wants/security-manager-installer.socket %attr(-,root,root) /usr/lib/systemd/system/security-manager-installer.socket - +%attr(-,root,root) /etc/security/security-server-audit.conf +%attr(-,root,root) /etc/smack/app-rules-template.smack %{_datadir}/license/%{name} %files -n libsecurity-server-client diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc9c23b..02dbcf6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ SET(SECURITY_SERVER_SOURCES ${SERVER2_PATH}/service/password-manager.cpp ${SERVER2_PATH}/service/password-file-buffer.cpp ${SERVER2_PATH}/service/smack-common.cpp + ${SERVER2_PATH}/service/smack-rules.cpp ${SERVER2_PATH}/service/installer.cpp ) diff --git a/src/server/service/installer.cpp b/src/server/service/installer.cpp index 16b270c..b02e22d 100644 --- a/src/server/service/installer.cpp +++ b/src/server/service/installer.cpp @@ -17,7 +17,8 @@ */ /* * @file installer.cpp - * @author Michal Witanowski (m.witanowski@samsung.com) + * @author Michal Witanowski + * @author Jacek Bukarewicz * @brief Implementation of installer service for libprivilege-control encapsulation. */ @@ -29,6 +30,7 @@ #include "protocols.h" #include "security-server.h" #include "security-manager.h" +#include "smack-rules.h" namespace SecurityServer { @@ -237,10 +239,20 @@ bool InstallerService::processAppInstall(MessageBuffer &buffer, MessageBuffer &s } } + // TODO: This should be done only for the first application in the package + if (!SecurityManager::SmackRules::installPackageRules(req.pkgId)) { + LogError("Failed to apply package-specific smack rules"); + goto error_label; + } + // finish database transaction result = perm_end(); LogDebug("perm_end() returned " << result); if (PC_OPERATION_SUCCESS != result) { + // TODO: Uncomment once proper pkgId -> smack label mapping is implemented (currently all + // applications are mapped to user label and removal of such rules would be harmful) + //SecurityManager::SmackRules::uninstallPackageRules(req.pkgId); + // error in libprivilege-control Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR); return false; @@ -285,6 +297,18 @@ bool InstallerService::processAppUninstall(MessageBuffer &buffer, MessageBuffer return false; } + // TODO: Uncomment once proper pkgId -> smack label mapping is implemented (currently all + // applications are mapped to user label and removal of such rules would be harmful) + // TODO: This should be performed only for the last application in the package + // TODO: retrieve pkgId as it's not available in the request + //if (!SecurityManager::SmackRules::uninstallPackageRules(pkgId)) { + // LogError("Error on uninstallation of package-specific smack rules"); + // result = perm_rollback(); + // LogDebug("perm_rollback() returned " << result); + // Serialization::Serialize(send, SECURITY_SERVER_API_ERROR_SERVER_ERROR); + // return false; + //} + // finish database transaction result = perm_end(); LogDebug("perm_end() returned " << result); diff --git a/src/server/service/smack-rules.cpp b/src/server/service/smack-rules.cpp new file mode 100644 index 0000000..24e9add --- /dev/null +++ b/src/server/service/smack-rules.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (c) 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 smack-rules.cpp + * @author Jacek Bukarewicz + * @version 1.0 + * @brief Implementation of a class managing smack rules + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "smack-rules.h" +#include "security-manager-common.h" + +namespace SecurityManager { + +const char *const SMACK_APP_LABEL_TEMPLATE = "~APP~"; +const char *const APP_RULES_TEMPLATE_FILE_PATH = "/etc/smack/app-rules-template.smack"; +const char *const APP_RULES_DIRECTORY = "/etc/smack/accesses.d/"; + +SmackRules::SmackRules() +{ + if (smack_accesses_new(&m_handle) < 0) { + LogError("Failed to create smack_accesses handle"); + throw std::bad_alloc(); + } +} + +SmackRules::~SmackRules() { + smack_accesses_free(m_handle); +} + +bool SmackRules::add(const std::string &subject, const std::string &object, + const std::string &permissions) +{ + return 0 == smack_accesses_add(m_handle, subject.c_str(), object.c_str(), permissions.c_str()); +} + +bool SmackRules::clear() const +{ + return 0 == smack_accesses_clear(m_handle); +} + +bool SmackRules::apply() const +{ + return 0 == smack_accesses_apply(m_handle); +} + +bool SmackRules::loadFromFile(const std::string &path) +{ + int fd; + bool ret = true; + + fd = open(path.c_str(), O_RDONLY); + if (fd == -1) { + LogError("Failed to open file: %s" << path); + return false; + } + + if (smack_accesses_add_from_file(m_handle, fd)) { + LogError("Failed to load smack rules from file: %s" << path); + ret = false; + } + + close(fd); + return ret; +} + +bool SmackRules::saveToFile(const std::string &path) const +{ + int fd; + bool ret = true; + + fd = open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd == -1) { + LogError("Failed to create file: %s" << path); + return false; + } + + if (smack_accesses_save(m_handle, fd)) { + LogError("Failed to save rules to file: %s" << path); + unlink(path.c_str()); + ret = false; + } + + close(fd); + return ret; +} + + +bool SmackRules::addFromTemplateFile(const std::string &pkgId) +{ + std::vector templateRules; + std::string line; + std::ifstream templateRulesFile(APP_RULES_TEMPLATE_FILE_PATH); + + if (!templateRulesFile.is_open()) { + LogError("Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH); + return false; + } + + while (std::getline(templateRulesFile, line)) { + templateRules.push_back(line); + } + + if (templateRulesFile.bad()) { + LogError("Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH); + return false; + } + + return addFromTemplate(templateRules, pkgId); +} + +bool SmackRules::addFromTemplate(const std::vector &templateRules, + const std::string &pkgId) +{ + std::string tokens[3]; + std::string &subject = tokens[0]; + std::string &object = tokens[1]; + std::string &permissions = tokens[2]; + + for (auto rule = templateRules.begin(); rule != templateRules.end(); ++rule) { + if (rule->length() == 0) + continue; + + if (!tokenizeRule(*rule, tokens, sizeof(tokens) / sizeof(*tokens))) { + return false; + } + + bool subjectIsTemplate = (subject == SMACK_APP_LABEL_TEMPLATE); + bool objectIsTemplate = (object == SMACK_APP_LABEL_TEMPLATE); + + if (objectIsTemplate == subjectIsTemplate) { + LogError("Invalid rule template. Exactly one app label template expected: " << *rule); + return false; + } + + if (subjectIsTemplate) { + if (!SecurityManager::generateAppLabel(pkgId, subject)) { + LogError("Failed to generate app label from pkgid: " << pkgId); + return false; + } + } + + if (objectIsTemplate) { + if (!SecurityManager::generateAppLabel(pkgId, object)) { + LogError("Failed to generate app label from pkgid: " << pkgId); + return false; + } + } + + if (!add(subject, object, permissions)) { + LogError("Failed to add rule: " << subject << " " << object << " " << permissions); + return false; + } + } + + return true; +} + + +bool SmackRules::tokenizeRule(const std::string &rule, std::string tokens[], int size) +{ + size_t startPos; + size_t endPos = 0; + const char delimiters[] = " \t\n\r"; + + for (int i = 0; i < size; i++) { + startPos = rule.find_first_not_of(delimiters, endPos); + if (startPos == std::string::npos) { + LogError("Unexpected end of rule: " << rule); + return false; + } + + endPos = rule.find_first_of(delimiters, startPos); + tokens[i] = rule.substr(startPos, endPos - startPos); + } + + if (endPos != std::string::npos && + rule.find_first_not_of(delimiters, endPos) != std::string::npos) { + LogError("Too many tokens found in rule: " << rule); + return false; + } + + return true; +} + +std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId) +{ + std::string path(APP_RULES_DIRECTORY); + path.append(pkgId); + path.append(".smack"); + return path; +} + +bool SmackRules::installPackageRules(const std::string &pkgId) { + try { + SmackRules smackRules; + std::string path = getPackageRulesFilePath(pkgId); + + if (!smackRules.addFromTemplateFile(pkgId)) { + LogError("Failed to load smack rules for pkgId " << pkgId); + return false; + } + + if (!smackRules.apply()) { + LogError("Failed to apply application rules to kernel"); + return false; + } + + if (!smackRules.saveToFile(path)) { + smackRules.clear(); + return false; + } + + return true; + } catch (const std::bad_alloc &e) { + LogError("Out of memory while trying to install smack rules for pkgId " << pkgId); + return false; + } +} + +bool SmackRules::uninstallPackageRules(const std::string &pkgId) { + std::string path = getPackageRulesFilePath(pkgId); + if (access(path.c_str(), F_OK) == -1) { + if (errno == ENOENT) { + LogWarning("Smack rules were not installed for pkgId: " << pkgId); + return true; + } + + LogWarning("Cannot access smack rules path: " << path); + return false; + } + + try { + SmackRules rules; + if (rules.loadFromFile(path)) { + if (!rules.clear()) { + LogWarning("Failed to clear smack kernel rules for pkgId: " << pkgId); + // don't stop uninstallation + } + } else { + LogWarning("Failed to load rules from file: " << path); + // don't stop uninstallation + } + + if (unlink(path.c_str()) == -1) { + LogError("Failed to remove smack rules file: " << path); + return false; + } + + return true; + } catch (const std::bad_alloc &e) { + LogError("Out of memory while trying to uninstall smack rules for pkgId: " << pkgId); + return false; + } +} + +} // namespace SecurityManager + diff --git a/src/server/service/smack-rules.h b/src/server/service/smack-rules.h new file mode 100644 index 0000000..bf50a4d --- /dev/null +++ b/src/server/service/smack-rules.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 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 smack-rules.h + * @author Jacek Bukarewicz + * @version 1.0 + * @brief Header file of a class managing smack rules + * + */ +#ifndef _SMACK_RULES_H_ +#define _SMACK_RULES_H_ + +#include +#include + +struct smack_accesses; + +namespace SecurityManager { + +class SmackRules +{ +public: + SmackRules(); + virtual ~SmackRules(); + + bool add(const std::string &subject, const std::string &object, + const std::string &permissions); + bool loadFromFile(const std::string &path); + bool addFromTemplate(const std::vector &templateRules, const std::string &pkgId); + bool addFromTemplateFile(const std::string &pkgId); + + bool apply() const; + bool clear() const; + bool saveToFile(const std::string &path) const; + + /** + * Install package-specific smack rules. + * + * Function creates smack rules using predefined template. Rules are applied + * to the kernel and saved on persistent storage so they are loaded on system boot. + * + * @param[in] pkgId - package identifier + * @return true on success, false on error + */ + static bool installPackageRules(const std::string &pkgId); + /** + * Uninstall package-specific smack rules. + * + * Function loads package-specific smack rules, revokes them from the kernel + * and removes from persistent storage. + * + * @param[in] pkgId - package identifier + * @return true if smack rule file has been uninstalled or didn't exist + * false otherwise + */ + static bool uninstallPackageRules(const std::string &pkgId); +private: + static bool tokenizeRule(const std::string &rule, std::string tokens[], int size); + static std::string getPackageRulesFilePath(const std::string &pkgId); + + smack_accesses *m_handle; +}; + +} // namespace SecurityManager + +#endif /* _SMACK_RULES_H_ */