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-labels.h"
40 #include "smack-rules.h"
42 namespace SecurityManager {
44 const char *const SMACK_APP_LABEL_TEMPLATE = "~APP~";
45 const char *const SMACK_PKG_LABEL_TEMPLATE = "~PKG~";
46 const char *const APP_RULES_TEMPLATE_FILE_PATH = tzplatform_mkpath(TZ_SYS_SMACK, "app-rules-template.smack");
47 const char *const SMACK_APP_IN_PACKAGE_PERMS = "rwxat";
49 SmackRules::SmackRules()
51 if (smack_accesses_new(&m_handle) < 0) {
52 LogError("Failed to create smack_accesses handle");
53 throw std::bad_alloc();
57 SmackRules::~SmackRules() {
58 smack_accesses_free(m_handle);
61 bool SmackRules::add(const std::string &subject, const std::string &object,
62 const std::string &permissions)
64 return 0 == smack_accesses_add(m_handle, subject.c_str(), object.c_str(), permissions.c_str());
67 bool SmackRules::addModify(const std::string &subject, const std::string &object,
68 const std::string &allowPermissions, const std::string &denyPermissions)
70 return 0 == smack_accesses_add_modify(m_handle, subject.c_str(), object.c_str(), allowPermissions.c_str(), denyPermissions.c_str());
73 bool SmackRules::clear() const
75 return 0 == smack_accesses_clear(m_handle);
78 bool SmackRules::apply() const
80 return 0 == smack_accesses_apply(m_handle);
83 bool SmackRules::loadFromFile(const std::string &path)
88 fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY));
90 LogError("Failed to open file: " << path);
94 if (smack_accesses_add_from_file(m_handle, fd)) {
95 LogError("Failed to load smack rules from file: " << path);
99 if (close(fd) == -1) {
100 // don't change the return code, the descriptor should be closed despite the error.
101 LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
107 bool SmackRules::saveToFile(const std::string &path) const
112 fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0644));
114 LogError("Failed to create file: " << path);
118 if (smack_accesses_save(m_handle, fd)) {
119 LogError("Failed to save rules to file: " << path);
120 unlink(path.c_str());
124 if (close(fd) == -1) {
126 LogError("I/O Error occured while closing the file: " << path << ", error: " << strerror(errno));
127 unlink(path.c_str());
130 // non critical error
131 // don't change the return code, the descriptor should be closed despite the error.
132 LogWarning("Error while closing the file: " << path << ", error: " << strerror(errno));
140 bool 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);
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);
161 return addFromTemplate(templateRules, appId, pkgId);
164 bool 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);
180 if (subject == SMACK_APP_LABEL_TEMPLATE) {
181 if (!generateAppLabel(appId, subject)) {
182 LogError("Failed to generate app label from appId: " << appId);
187 if (subject == SMACK_PKG_LABEL_TEMPLATE) {
188 if (!generatePkgLabel(pkgId, object)) {
189 LogError("Failed to generate pkg label from pkgid: " << pkgId);
194 if (object == SMACK_APP_LABEL_TEMPLATE) {
195 if (!generateAppLabel(appId, object)) {
196 LogError("Failed to generate app label from appId: " << appId);
201 if (object == SMACK_PKG_LABEL_TEMPLATE) {
202 if (!generatePkgLabel(pkgId, object)) {
203 LogError("Failed to generate pkg label from pkgId: " << pkgId);
208 if (!add(subject, object, permissions)) {
209 LogError("Failed to add rule: " << subject << " " << object << " " << permissions);
217 bool SmackRules::generatePackageCrossDeps(const std::vector<std::string> &pkgContents)
219 LogDebug ("Generating cross-package rules");
221 std::string subjectLabel, objectLabel;
222 std::string appsInPackagePerms = SMACK_APP_IN_PACKAGE_PERMS;
224 for (const auto &subject : pkgContents) {
225 for (const auto &object : pkgContents) {
226 if (object == subject)
229 if (generateAppLabel(subject, subjectLabel) && generateAppLabel(object, objectLabel)) {
230 LogDebug ("Trying to add rule subject: " << subjectLabel << " object: " << objectLabel
231 << " perms: " << appsInPackagePerms);
232 if (!add (subjectLabel, objectLabel, appsInPackagePerms)) {
233 LogError ("Can't add in-package rule for subject: "
234 << subject << " and object: " << object);
239 LogError ("Failed to created smack labels for subject: "
240 << subject << " and object: " << object);
249 std::string SmackRules::getPackageRulesFilePath(const std::string &pkgId)
251 std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("pkg_" + pkgId).c_str()));
255 std::string SmackRules::getApplicationRulesFilePath(const std::string &appId)
257 std::string path(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d", ("app_" + appId).c_str()));
261 bool SmackRules::installApplicationRules(const std::string &appId, const std::string &pkgId,
262 const std::vector<std::string> &pkgContents) {
264 SmackRules smackRules;
265 std::string appPath = getApplicationRulesFilePath(appId);
267 if (!smackRules.addFromTemplateFile(appId, pkgId)) {
268 LogError("Failed to load smack rules for appId: " << appId << " with pkgId: " << pkgId);
272 if (smack_smackfs_path() != NULL && !smackRules.apply()) {
273 LogError("Failed to apply application rules to kernel [app]");
277 if (!smackRules.saveToFile(appPath)) {
282 if (!updatePackageRules(pkgId, pkgContents))
288 } catch (const std::bad_alloc &e) {
289 LogError("Out of memory while trying to install smack rules for appId: "
290 << appId << "in pkgId: " << pkgId);
295 bool SmackRules::updatePackageRules(const std::string &pkgId, const std::vector<std::string> &pkgContents)
298 SmackRules smackRules;
299 std::string pkgPath = getPackageRulesFilePath(pkgId);
301 if (!smackRules.generatePackageCrossDeps(pkgContents))
303 LogError("Failed to create application in-package cross dependencies");
307 if (smack_smackfs_path() != NULL && !smackRules.apply()) {
308 LogError("Failed to apply application rules to kernel [pkg]");
312 if (!smackRules.saveToFile(pkgPath)) {
318 } catch (const std::bad_alloc &e) {
319 LogError("Out of memory while trying to install smack rules for pkgId: " << pkgId);
324 /* FIXME: Remove this function if real pkgId instead of "User" label will be used
325 * in generateAppLabel(). */
326 bool SmackRules::addMissingRulesFix()
331 std::string path(tzplatform_mkpath(TZ_SYS_SMACK, "accesses.d"));
333 dir = opendir(path.c_str());
335 while ((ent = readdir(dir))) {
336 if (ent->d_type == DT_REG) {
337 rules.loadFromFile(tzplatform_mkpath3(TZ_SYS_SMACK, "accesses.d/", ent->d_name));
338 // Do not check error here. If this fails we can't do anything anyway.
351 bool SmackRules::uninstallPackageRules(const std::string &pkgId)
353 if (!uninstallRules(getPackageRulesFilePath(pkgId)))
355 LogError("Failed to uninstall application rules for pkgId: " << pkgId);
362 bool SmackRules::uninstallApplicationRules(const std::string &appId,
363 const std::string &pkgId, std::vector<std::string> pkgContents)
365 if (!uninstallRules (getApplicationRulesFilePath(appId)))
367 LogError("Failed to uninstall application rules for appId: " << appId);
371 if (!updatePackageRules(pkgId, pkgContents))
373 LogError("failed to update package rules for appId: " << appId
374 << " pkgId: " << pkgId);
378 // FIXME: Reloading all rules:
379 SmackRules::addMissingRulesFix();
384 bool SmackRules::uninstallRules(const std::string &path)
386 if (access(path.c_str(), F_OK) == -1) {
387 if (errno == ENOENT) {
388 LogWarning("Smack rules not found in file: " << path);
392 LogWarning("Cannot access smack rules path: " << path);
398 if (rules.loadFromFile(path)) {
399 if (smack_smackfs_path() != NULL && !rules.clear()) {
400 LogWarning("Failed to clear smack kernel rules from file: " << path);
401 // don't stop uninstallation
404 LogWarning("Failed to load rules from file: " << path);
405 // don't stop uninstallation
408 if (unlink(path.c_str()) == -1) {
409 LogError("Failed to remove smack rules file: " << path);
412 } catch (const std::bad_alloc &e) {
413 LogError("Out of memory while trying to uninstall smack rules from path: " << path);
419 } // namespace SecurityManager