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>
36 #include <dpl/log/log.h>
37 #include <tzplatform_config.h>
39 #include <smack-common.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 APP_RULES_TEMPLATE_FILE_PATH = tzplatform_mkpath(TZ_SYS_SMACK, "app-rules-template.smack");
48 SmackRules::SmackRules()
50 if (smack_accesses_new(&m_handle) < 0) {
51 LogError("Failed to create smack_accesses handle");
52 throw std::bad_alloc();
56 SmackRules::~SmackRules() {
57 smack_accesses_free(m_handle);
60 bool SmackRules::add(const std::string &subject, const std::string &object,
61 const std::string &permissions)
63 return 0 == smack_accesses_add(m_handle, subject.c_str(), object.c_str(), permissions.c_str());
66 bool SmackRules::clear() const
68 return 0 == smack_accesses_clear(m_handle);
71 bool SmackRules::apply() const
73 return 0 == smack_accesses_apply(m_handle);
76 bool SmackRules::loadFromFile(const std::string &path)
81 fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY));
83 LogError("Failed to open file: " << path);
87 if (smack_accesses_add_from_file(m_handle, fd)) {
88 LogError("Failed to load smack rules from file: " << path);
92 if (close(fd) == -1) {
93 // don't change the return code, the descriptor should be closed despite the error.
94 LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
100 bool SmackRules::saveToFile(const std::string &path) const
105 fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644));
107 LogError("Failed to create file: " << path);
111 if (smack_accesses_save(m_handle, fd)) {
112 LogError("Failed to save rules to file: " << path);
113 unlink(path.c_str());
117 if (close(fd) == -1) {
119 LogError("I/O Error occured while closing the file: " << path << ", error: " << strerror(errno));
120 unlink(path.c_str());
123 // non critical error
124 // don't change the return code, the descriptor should be closed despite the error.
125 LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
133 bool SmackRules::addFromTemplateFile(const std::string &pkgId)
135 std::vector<std::string> templateRules;
137 std::ifstream templateRulesFile(APP_RULES_TEMPLATE_FILE_PATH);
139 if (!templateRulesFile.is_open()) {
140 LogError("Cannot open rules template file: " << APP_RULES_TEMPLATE_FILE_PATH);
144 while (std::getline(templateRulesFile, line)) {
145 templateRules.push_back(line);
148 if (templateRulesFile.bad()) {
149 LogError("Error reading template file: " << APP_RULES_TEMPLATE_FILE_PATH);
153 return addFromTemplate(templateRules, pkgId);
156 bool SmackRules::addFromTemplate(const std::vector<std::string> &templateRules,
157 const std::string &pkgId)
159 for (auto rule : templateRules) {
163 std::stringstream stream(rule);
164 std::string subject, object, permissions;
165 stream >> subject >> object >> permissions;
167 if (stream.fail() || !stream.eof()) {
168 LogError("Invalid rule template: " << rule);
172 bool subjectIsTemplate = (subject == SMACK_APP_LABEL_TEMPLATE);
173 bool objectIsTemplate = (object == SMACK_APP_LABEL_TEMPLATE);
175 if (objectIsTemplate == subjectIsTemplate) {
176 LogError("Invalid rule template. Exactly one app label template expected: " << rule);
180 if (subjectIsTemplate) {
181 if (!generateAppLabel(pkgId, subject)) {
182 LogError("Failed to generate app label from pkgid: " << pkgId);
187 if (objectIsTemplate) {
188 if (!generateAppLabel(pkgId, object)) {
189 LogError("Failed to generate app label from pkgid: " << pkgId);
194 if (!add(subject, object, permissions)) {
195 LogError("Failed to add rule: " << subject << " " << object << " " << permissions);
203 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId)
205 std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", pkgId.c_str()));
209 bool SmackRules::installPackageRules(const std::string &pkgId)
212 SmackRules smackRules;
213 std::string path = getPackageRulesFilePath(pkgId);
215 if (!smackRules.addFromTemplateFile(pkgId)) {
216 LogError("Failed to load smack rules for pkgId " << pkgId);
220 if (smack_smackfs_path() != NULL && !smackRules.apply()) {
221 LogError("Failed to apply application rules to kernel");
225 if (!smackRules.saveToFile(path)) {
231 } catch (const std::bad_alloc &e) {
232 LogError("Out of memory while trying to install smack rules for pkgId " << pkgId);
237 /* FIXME: Remove this function if real pkgId instead of "User" label will be used
238 * in generateAppLabel(). */
239 bool SmackRules::addMissingRulesFix()
244 std::string path(tzplatform_mkpath(TZ_SYS_SMACK, "accesses.d"));
246 dir = opendir(path.c_str());
248 while ((ent = readdir(dir))) {
249 if (ent->d_type == DT_REG) {
250 rules.loadFromFile(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d/", ent->d_name));
251 // Do not check error here. If this fails we can't do anything anyway.
264 bool SmackRules::uninstallPackageRules(const std::string &pkgId)
266 std::string path = getPackageRulesFilePath(pkgId);
267 if (access(path.c_str(), F_OK) == -1) {
268 if (errno == ENOENT) {
269 LogWarning("Smack rules were not installed for pkgId: " << pkgId);
273 LogWarning("Cannot access smack rules path: " << path);
279 if (rules.loadFromFile(path)) {
280 if (smack_smackfs_path() != NULL && !rules.clear()) {
281 LogWarning("Failed to clear smack kernel rules for pkgId: " << pkgId);
282 // don't stop uninstallation
285 LogWarning("Failed to load rules from file: " << path);
286 // don't stop uninstallation
289 if (unlink(path.c_str()) == -1) {
290 LogError("Failed to remove smack rules file: " << path);
294 // FIXME: Reloading all rules:
295 SmackRules::addMissingRulesFix();
298 } catch (const std::bad_alloc &e) {
299 LogError("Out of memory while trying to uninstall smack rules for pkgId: " << pkgId);
304 } // namespace SecurityManager