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-labels.cpp
20 * @author Jan Cybulski <j.cybulski@samsung.com>
21 * @author Rafal Krypa <r.krypa@samsung.com>
23 * @brief Implementation of functions managing smack labels
28 #include <sys/smack.h>
29 #include <sys/xattr.h>
30 #include <linux/xattr.h>
36 #include <dpl/log/log.h>
38 #include "security-manager.h"
39 #include "smack-labels.h"
40 #include "zone-utils.h"
42 namespace SecurityManager {
43 namespace SmackLabels {
45 //! Smack label used for SECURITY_MANAGER_PATH_PUBLIC_RO paths (RO for all apps)
46 const char *const LABEL_FOR_APP_PUBLIC_RO_PATH = "User::Home";
48 typedef std::function<bool(const FTSENT*)> LabelDecisionFn;
50 static bool labelAll(const FTSENT *ftsent __attribute__((unused)))
55 static bool labelDirs(const FTSENT *ftsent)
57 // label only directories
58 return (S_ISDIR(ftsent->fts_statp->st_mode));
61 static bool labelExecs(const FTSENT *ftsent)
63 // LogDebug("Mode = " << ftsent->fts_statp->st_mode); // this could be helpfull in debugging
64 // label only regular executable files
65 return (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR));
68 static inline void pathSetSmack(const char *path, const std::string &label,
69 const char *xattr_name)
71 if (lsetxattr(path, xattr_name, label.c_str(), label.length(), 0)) {
72 LogError("lsetxattr failed.");
73 ThrowMsg(SmackException::FileError, "lsetxattr failed.");
77 static void dirSetSmack(const std::string &path, const std::string &label,
78 const char *xattr_name, LabelDecisionFn fn)
80 char *const path_argv[] = {const_cast<char *>(path.c_str()), NULL};
83 std::unique_ptr<FTS, std::function<void(FTS*)> > fts(
84 fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL),
88 LogError("fts_open failed.");
89 ThrowMsg(SmackException::FileError, "fts_open failed.");
92 while ((ftsent = fts_read(fts.get())) != NULL) {
93 /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
94 if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
95 LogError("FTS_ERR error or failed stat(2) (FTS_NS)");
96 ThrowMsg(SmackException::FileError, "FTS_ERR error or failed stat(2) (FTS_NS)");
99 /* avoid to tag directories two times */
100 if (ftsent->fts_info == FTS_D)
104 pathSetSmack(ftsent->fts_path, label, xattr_name);
107 /* If last call to fts_read() set errno, we need to return error. */
108 if ((errno != 0) && (ftsent == NULL)) {
109 LogError("Last errno from fts_read: " << strerror(errno));
110 ThrowMsg(SmackException::FileError, "Last errno from fts_read: " << strerror(errno));
114 static void labelDir(const std::string &path, const std::string &label,
115 bool set_transmutable, bool set_executables)
117 // setting access label on everything in given directory and below
118 dirSetSmack(path, label, XATTR_NAME_SMACK, labelAll);
120 // setting transmute on dirs
121 if (set_transmutable)
122 dirSetSmack(path, "TRUE", XATTR_NAME_SMACKTRANSMUTE, labelDirs);
124 // setting SMACK64EXEC labels
126 dirSetSmack(path, label, XATTR_NAME_SMACKEXEC, &labelExecs);
129 void setupPath(const std::string &pkgId, const std::string &path, app_install_path_type pathType,
130 const std::string &zoneId)
133 bool label_executables, label_transmute;
136 case SECURITY_MANAGER_PATH_RW:
137 label = zoneSmackLabelGenerate(generatePkgLabel(pkgId), zoneId);
138 label_executables = false;
139 label_transmute = true;
141 case SECURITY_MANAGER_PATH_RO:
142 label = zoneSmackLabelGenerate(generatePkgROLabel(pkgId), zoneId);
143 label_executables = false;
144 label_transmute = false;
146 case SECURITY_MANAGER_PATH_PUBLIC_RO:
147 label.assign(LABEL_FOR_APP_PUBLIC_RO_PATH);
148 label_executables = false;
149 label_transmute = true;
152 LogError("Path type not known.");
153 Throw(SmackException::InvalidPathType);
155 return labelDir(path, label, label_transmute, label_executables);
158 void setupAppBasePath(const std::string &pkgId, const std::string &basePath)
160 std::string pkgPath = basePath + "/" + pkgId;
161 pathSetSmack(pkgPath.c_str(), LABEL_FOR_APP_PUBLIC_RO_PATH, XATTR_NAME_SMACK);
164 std::string generateAppNameFromLabel(const std::string &label)
166 static const char prefix[] = "User::App::";
168 if (label.compare(0, sizeof(prefix) - 1, prefix))
169 ThrowMsg(SmackException::InvalidLabel, "Cannot extract appId from Smack label " << label);
171 return label.substr(sizeof(prefix) - 1);
174 std::string generateAppLabel(const std::string &appId)
176 std::string label = "User::App::" + appId;
178 if (smack_label_length(label.c_str()) <= 0)
179 ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from appId " << appId);
184 std::string generatePkgLabel(const std::string &pkgId)
186 std::string label = "User::Pkg::" + pkgId;
188 if (smack_label_length(label.c_str()) <= 0)
189 ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from pkgId " << pkgId);
194 std::string generatePkgROLabel(const std::string &pkgId)
196 std::string label = "User::Pkg::" + pkgId + "::RO";
198 if (smack_label_length(label.c_str()) <= 0)
199 ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from pkgId " << pkgId);
205 } // namespace SmackLabels
206 } // namespace SecurityManager