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>
30 #include <sys/smack.h>
37 #include <dpl/log/log.h>
38 #include <tzplatform_config.h>
40 #include "smack-labels.h"
41 #include "smack-rules.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,
141 const std::string &pkgId)
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);
164 void SmackRules::addFromTemplate(const std::vector<std::string> &templateRules,
165 const std::string &appId, const std::string &pkgId)
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 add(subject, object, permissions);
196 void SmackRules::generatePackageCrossDeps(const std::vector<std::string> &pkgContents)
198 LogDebug ("Generating cross-package rules");
200 std::string subjectLabel, objectLabel;
201 std::string appsInPackagePerms = SMACK_APP_IN_PACKAGE_PERMS;
203 for (const auto &subject : pkgContents) {
204 for (const auto &object : pkgContents) {
205 if (object == subject)
208 subjectLabel = SmackLabels::generateAppLabel(subject);
209 objectLabel = SmackLabels::generateAppLabel(object);
210 LogDebug ("Trying to add rule subject: " << subjectLabel << " object: " << objectLabel << " perms: " << appsInPackagePerms);
211 add(subjectLabel, objectLabel, appsInPackagePerms);
216 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId)
218 std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("pkg_" + pkgId).c_str()));
222 std::string SmackRules::getApplicationRulesFilePath(const std::string &appId)
224 std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("app_" + appId).c_str()));
228 void SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId,
229 const std::vector<std::string> &pkgContents)
231 SmackRules smackRules;
232 std::string appPath = getApplicationRulesFilePath(appId);
234 smackRules.addFromTemplateFile(appId, pkgId);
236 if (smack_smackfs_path() != NULL)
239 smackRules.saveToFile(appPath);
240 updatePackageRules(pkgId, pkgContents);
243 void SmackRules::updatePackageRules(const std::string &pkgId, const std::vector<std::string> &pkgContents)
245 SmackRules smackRules;
246 std::string pkgPath = getPackageRulesFilePath(pkgId);
248 smackRules.generatePackageCrossDeps(pkgContents);
250 if (smack_smackfs_path() != NULL)
253 smackRules.saveToFile(pkgPath);
256 /* FIXME: Remove this function if real pkgId instead of "User" label will be used
257 * in generateAppLabel(). */
258 void SmackRules::addMissingRulesFix()
262 std::string path(tzplatform_mkpath(TZ_SYS_SMACK, "accesses.d"));
263 std::unique_ptr<DIR, std::function<int(DIR*)>> dir(opendir(path.c_str()), closedir);
265 ThrowMsg(SmackException::FileError, "opendir");
267 while ((ent = readdir(dir.get()))) {
269 if (ent->d_type == DT_REG) {
270 rules.loadFromFile(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d/", ent->d_name));
271 // Do not check error here. If this fails we can't do anything anyway.
277 void SmackRules::uninstallPackageRules(const std::string &pkgId)
279 uninstallRules(getPackageRulesFilePath(pkgId));
282 void SmackRules::uninstallApplicationRules(const std::string &appId,
283 const std::string &pkgId, std::vector<std::string> pkgContents)
285 uninstallRules(getApplicationRulesFilePath(appId));
286 updatePackageRules(pkgId, pkgContents);
288 // FIXME: Reloading all rules:
289 SmackRules::addMissingRulesFix();
292 void SmackRules::uninstallRules(const std::string &path)
294 if (access(path.c_str(), F_OK) == -1) {
295 if (errno == ENOENT) {
296 LogWarning("Smack rules not found in file: " << path);
300 LogWarning("Cannot access smack rules path: " << path);
301 ThrowMsg(SmackException::FileError, "Cannot access smack rules path: " << path);
306 rules.loadFromFile(path);
307 if (smack_smackfs_path())
309 } catch (const SmackException::Base &e) {
310 LogWarning("Failed to clear smack kernel rules from file: " << path);
311 // don't stop uninstallation
314 if (unlink(path.c_str()) == -1) {
315 LogWarning("Failed to remove smack rules file: " << path);
316 ThrowMsg(SmackException::FileError, "Failed to remove smack rules file: " << path);
320 } // namespace SecurityManager