0294a428d1368e9e4d3d44008f2e38efc35a6176
[platform/core/security/security-manager.git] / src / common / smack-labels.cpp
1 /*
2  *  Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Rafal Krypa <r.krypa@samsung.com>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  */
18 /**
19  * @file        smack-labels.cpp
20  * @author      Jan Cybulski <j.cybulski@samsung.com>
21  * @author      Rafal Krypa <r.krypa@samsung.com>
22  * @version     1.0
23  * @brief       Implementation of functions managing smack labels
24  *
25  */
26
27 #include <sys/stat.h>
28 #include <sys/smack.h>
29 #include <sys/xattr.h>
30 #include <linux/xattr.h>
31 #include <memory>
32 #include <fts.h>
33 #include <cstring>
34 #include <string>
35
36 #include <dpl/log/log.h>
37
38 #include "security-manager.h"
39 #include "smack-labels.h"
40
41 namespace SecurityManager {
42 namespace SmackLabels {
43
44 /* Const defined below is used to label files accessible to apps only for reading */
45 const char *const LABEL_FOR_APP_RO_PATH = "User::Home";
46
47 typedef std::function<bool(const FTSENT*)> LabelDecisionFn;
48
49 static bool labelAll(const FTSENT *ftsent __attribute__((unused)))
50 {
51     return true;
52 }
53
54 static bool labelDirs(const FTSENT *ftsent)
55 {
56     // label only directories
57     return (S_ISDIR(ftsent->fts_statp->st_mode));
58 }
59
60 static bool labelExecs(const FTSENT *ftsent)
61 {
62     // LogDebug("Mode = " << ftsent->fts_statp->st_mode); // this could be helpfull in debugging
63     // label only regular executable files
64     return (S_ISREG(ftsent->fts_statp->st_mode) && (ftsent->fts_statp->st_mode & S_IXUSR));
65 }
66
67 static inline void pathSetSmack(const char *path, const std::string &label,
68         const char *xattr_name)
69 {
70     if (lsetxattr(path, xattr_name, label.c_str(), label.length(), 0)) {
71         LogError("lsetxattr failed.");
72         ThrowMsg(SmackException::FileError, "lsetxattr failed.");
73     }
74 }
75
76 static void dirSetSmack(const std::string &path, const std::string &label,
77         const char *xattr_name, LabelDecisionFn fn)
78 {
79     char *const path_argv[] = {const_cast<char *>(path.c_str()), NULL};
80     FTSENT *ftsent;
81
82     std::unique_ptr<FTS, std::function<void(FTS*)> > fts(
83             fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL),
84             fts_close);
85
86     if (!fts) {
87         LogError("fts_open failed.");
88         ThrowMsg(SmackException::FileError, "fts_open failed.");
89     }
90
91     while ((ftsent = fts_read(fts.get())) != NULL) {
92         /* Check for error (FTS_ERR) or failed stat(2) (FTS_NS) */
93         if (ftsent->fts_info == FTS_ERR || ftsent->fts_info == FTS_NS) {
94             LogError("FTS_ERR error or failed stat(2) (FTS_NS)");
95             ThrowMsg(SmackException::FileError, "FTS_ERR error or failed stat(2) (FTS_NS)");
96         }
97
98         /* avoid to tag directories two times */
99         if (ftsent->fts_info == FTS_D)
100             continue;
101
102         if (fn(ftsent))
103             pathSetSmack(ftsent->fts_path, label, xattr_name);
104     }
105
106     /* If last call to fts_read() set errno, we need to return error. */
107     if ((errno != 0) && (ftsent == NULL)) {
108         LogError("Last errno from fts_read: " << strerror(errno));
109         ThrowMsg(SmackException::FileError, "Last errno from fts_read: " << strerror(errno));
110     }
111 }
112
113 static void labelDir(const std::string &path, const std::string &label,
114         bool set_transmutable, bool set_executables)
115 {
116     // setting access label on everything in given directory and below
117     dirSetSmack(path, label, XATTR_NAME_SMACK, labelAll);
118
119     // setting transmute on dirs
120     if (set_transmutable)
121         dirSetSmack(path, "TRUE", XATTR_NAME_SMACKTRANSMUTE, labelDirs);
122
123     // setting SMACK64EXEC labels
124     if (set_executables)
125         dirSetSmack(path, label, XATTR_NAME_SMACKEXEC, &labelExecs);
126 }
127
128 void setupPath(const std::string &appId, const std::string &path,
129     app_install_path_type pathType)
130 {
131     std::string label;
132     bool label_executables, label_transmute;
133
134     switch (pathType) {
135     case SECURITY_MANAGER_PATH_PRIVATE:
136     case SECURITY_MANAGER_PATH_RW:
137         label = generateAppLabel(appId);
138         label_executables = true;
139         label_transmute = false;
140         break;
141     case SECURITY_MANAGER_PATH_PUBLIC:
142     case SECURITY_MANAGER_PATH_RO:
143         label.assign(LABEL_FOR_APP_RO_PATH);
144         label_executables = false;
145         label_transmute = true;
146         break;
147     case SECURITY_MANAGER_PATH_PUBLIC_RO:
148         label.assign("_");
149         label_executables = false;
150         label_transmute = false;
151         break;
152     default:
153         LogError("Path type not known.");
154         Throw(SmackException::InvalidPathType);
155     }
156     return labelDir(path, label, label_transmute, label_executables);
157 }
158
159 void setupCorrectPath(const std::string &pkgId, const std::string &appId, const std::string &basePath)
160 {
161     std::string pkgPath = basePath + "/" + pkgId;
162     std::string appPath = pkgPath + "/" + appId;
163
164     pathSetSmack(pkgPath.c_str(), generatePkgLabel(pkgId), XATTR_NAME_SMACK);
165     pathSetSmack(appPath.c_str(), generateAppLabel(appId), XATTR_NAME_SMACK);
166     pathSetSmack(appPath.c_str(), "TRUE", XATTR_NAME_SMACKTRANSMUTE);
167 }
168
169 std::string generateAppNameFromLabel(const std::string &label)
170 {
171     static const char prefix[] = "User::App::";
172
173     if (label.compare(0, sizeof(prefix) - 1, prefix))
174         ThrowMsg(SmackException::InvalidLabel, "Cannot extract appId from Smack label " << label);
175
176     return label.substr(sizeof(prefix) - 1);
177 }
178
179 std::string generateAppLabel(const std::string &appId)
180 {
181     std::string label = "User::App::" + appId;
182
183     if (smack_label_length(label.c_str()) <= 0)
184         ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from appId " << appId);
185
186     return label;
187 }
188
189 std::string generatePkgLabel(const std::string &pkgId)
190 {
191     std::string label = "User::Pkg::" + pkgId;
192
193     if (smack_label_length(label.c_str()) <= 0)
194         ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from pkgId " << pkgId);
195
196     return label;
197 }
198
199 } // namespace SmackLabels
200 } // namespace SecurityManager