2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Rafal Krypa <r.krypa@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
19 * @file smack-rules.cpp
20 * @author Jacek Bukarewicz <j.bukarewicz@samsung.com>
22 * @brief Implementation of a class managing smack rules
27 #include <sys/types.h>
29 #include <sys/smack.h>
36 #include <dpl/log/log.h>
37 #include <tzplatform_config.h>
39 #include "smack-labels.h"
40 #include "smack-rules.h"
41 #include "zone-utils.h"
43 namespace SecurityManager {
45 const char *const SMACK_APP_LABEL_TEMPLATE = "~APP~";
46 const char *const SMACK_PKG_LABEL_TEMPLATE = "~PKG~";
47 const char *const APP_RULES_TEMPLATE_FILE_PATH = tzplatform_mkpath4(TZ_SYS_SHARE, "security-manager", "policy", "app-rules-template.smack");
48 const char *const SMACK_APP_IN_PACKAGE_PERMS = "rwxat";
50 SmackRules::SmackRules()
52 if (smack_accesses_new(&m_handle) < 0) {
53 LogError("Failed to create smack_accesses handle");
54 throw std::bad_alloc();
58 SmackRules::~SmackRules() {
59 smack_accesses_free(m_handle);
62 void SmackRules::add(const std::string &subject, const std::string &object,
63 const std::string &permissions)
65 if (smack_accesses_add(m_handle, subject.c_str(), object.c_str(), permissions.c_str()))
66 ThrowMsg(SmackException::LibsmackError, "smack_accesses_add");
69 void SmackRules::addModify(const std::string &subject, const std::string &object,
70 const std::string &allowPermissions, const std::string &denyPermissions)
72 if (smack_accesses_add_modify(m_handle, subject.c_str(), object.c_str(), allowPermissions.c_str(), denyPermissions.c_str()))
73 ThrowMsg(SmackException::LibsmackError, "smack_accesses_add_modify");
76 void SmackRules::clear() const
78 if (smack_accesses_clear(m_handle))
79 ThrowMsg(SmackException::LibsmackError, "smack_accesses_clear");
82 void SmackRules::apply() const
84 if (smack_accesses_apply(m_handle))
85 ThrowMsg(SmackException::LibsmackError, "smack_accesses_apply");
89 void SmackRules::loadFromFile(const std::string &path)
93 fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY));
95 LogError("Failed to open file: " << path);
96 ThrowMsg(SmackException::FileError, "Failed to open file: " << path);
99 if (smack_accesses_add_from_file(m_handle, fd)) {
100 LogError("Failed to load smack rules from file: " << path);
101 ThrowMsg(SmackException::LibsmackError, "Failed to load smack rules from file: " << path);
104 if (close(fd) == -1) {
105 // don't change the return code, the descriptor should be closed despite the error.
106 LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
110 void SmackRules::saveToFile(const std::string &path) const
114 fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644));
116 LogError("Failed to create file: " << path);
117 ThrowMsg(SmackException::FileError, "Failed to create file: " << path);
120 if (smack_accesses_save(m_handle, fd)) {
121 LogError("Failed to save rules to file: " << path);
122 unlink(path.c_str());
123 ThrowMsg(SmackException::LibsmackError, "Failed to save rules to file: " << path);
126 if (close(fd) == -1) {
128 LogError("I/O Error occured while closing the file: " << path << ", error: " << strerror(errno));
129 unlink(path.c_str());
130 ThrowMsg(SmackException::FileError, "I/O Error occured while closing the file: " << path << ", error: " << strerror(errno));
132 // non critical error
133 // don't change the return code, the descriptor should be closed despite the error.
134 LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
140 void SmackRules::addFromTemplateFile(const std::string &appId, const std::string &pkgId,
141 const std::string &zoneId)
143 std::vector<std::string> templateRules;
145 std::ifstream templateRulesFile(APP_RULES_TEMPLATE_FILE_PATH);
147 if (!templateRulesFile.is_open()) {
148 LogError("Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH);
149 ThrowMsg(SmackException::FileError, "Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH);
152 while (std::getline(templateRulesFile, line)) {
153 templateRules.push_back(line);
156 if (templateRulesFile.bad()) {
157 LogError("Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH);
158 ThrowMsg(SmackException::FileError, "Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH);
161 addFromTemplate(templateRules, appId, pkgId, zoneId);
164 void SmackRules::addFromTemplate(const std::vector<std::string> &templateRules,
165 const std::string &appId, const std::string &pkgId, const std::string &zoneId)
167 for (auto rule : templateRules) {
171 std::stringstream stream(rule);
172 std::string subject, object, permissions;
173 stream >> subject >> object >> permissions;
175 if (stream.fail() || !stream.eof()) {
176 LogError("Invalid rule template: " << rule);
177 ThrowMsg(SmackException::FileError, "Invalid rule template: " << rule);
180 if (subject == SMACK_APP_LABEL_TEMPLATE)
181 subject = SmackLabels::generateAppLabel(appId);
183 if (subject == SMACK_PKG_LABEL_TEMPLATE)
184 subject = SmackLabels::generatePkgLabel(pkgId);
186 if (object == SMACK_APP_LABEL_TEMPLATE)
187 object = SmackLabels::generateAppLabel(appId);
189 if (object == SMACK_PKG_LABEL_TEMPLATE)
190 object = SmackLabels::generatePkgLabel(pkgId);
192 if (!zoneId.empty()) {
193 // FIXME replace with vasum calls. See zone-utils.h
194 subject = zoneSmackLabelGenerate(subject, zoneId);
195 object = zoneSmackLabelGenerate(object, zoneId);
198 add(subject, object, permissions);
202 void SmackRules::generatePackageCrossDeps(const std::vector<std::string> &pkgContents,
203 const std::string &zoneId)
205 LogDebug ("Generating cross-package rules");
207 std::string subjectLabel, objectLabel;
208 std::string appsInPackagePerms = SMACK_APP_IN_PACKAGE_PERMS;
210 for (const auto &subject : pkgContents) {
211 for (const auto &object : pkgContents) {
212 if (object == subject)
215 subjectLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(subject), zoneId);
216 objectLabel = zoneSmackLabelGenerate(SmackLabels::generateAppLabel(object), zoneId);
217 LogDebug ("Trying to add rule subject: " << subjectLabel << " object: " << objectLabel << " perms: " << appsInPackagePerms);
218 add(subjectLabel, objectLabel, appsInPackagePerms);
223 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId)
225 std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("pkg_" + pkgId).c_str()));
229 std::string SmackRules::getApplicationRulesFilePath(const std::string &appId)
231 std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("app_" + appId).c_str()));
235 void SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId,
236 const std::vector<std::string> &pkgContents)
238 installApplicationRules(appId, pkgId, pkgContents, std::string());
241 void SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId,
242 const std::vector<std::string> &pkgContents, const std::string &zoneId)
244 SmackRules smackRules;
245 std::string appPath = getApplicationRulesFilePath(appId);
247 smackRules.addFromTemplateFile(appId, pkgId, zoneId);
249 if (smack_smackfs_path() != NULL)
252 smackRules.saveToFile(appPath);
253 updatePackageRules(pkgId, pkgContents, zoneId);
256 void SmackRules::updatePackageRules(const std::string &pkgId,
257 const std::vector<std::string> &pkgContents, const std::string &zoneId)
259 SmackRules smackRules;
260 std::string pkgPath = getPackageRulesFilePath(pkgId);
262 smackRules.generatePackageCrossDeps(pkgContents, zoneId);
264 if (smack_smackfs_path() != NULL)
267 smackRules.saveToFile(pkgPath);
270 void SmackRules::uninstallPackageRules(const std::string &pkgId)
272 uninstallRules(getPackageRulesFilePath(pkgId));
275 void SmackRules::uninstallApplicationRules(const std::string &appId,
276 const std::string &pkgId, std::vector<std::string> pkgContents, const std::string &zoneId)
278 uninstallRules(getApplicationRulesFilePath(appId));
279 updatePackageRules(pkgId, pkgContents, zoneId);
282 void SmackRules::uninstallRules(const std::string &path)
284 if (access(path.c_str(), F_OK) == -1) {
285 if (errno == ENOENT) {
286 LogWarning("Smack rules not found in file: " << path);
290 LogWarning("Cannot access smack rules path: " << path);
291 ThrowMsg(SmackException::FileError, "Cannot access smack rules path: " << path);
296 rules.loadFromFile(path);
297 if (smack_smackfs_path())
299 } catch (const SmackException::Base &e) {
300 LogWarning("Failed to clear smack kernel rules from file: " << path);
301 // don't stop uninstallation
304 if (unlink(path.c_str()) == -1) {
305 LogWarning("Failed to remove smack rules file: " << path);
306 ThrowMsg(SmackException::FileError, "Failed to remove smack rules file: " << path);
310 } // namespace SecurityManager