Fix labeling of SECURITY_MANAGER_PATH_RW paths
[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 #include "zone-utils.h"
41
42 namespace SecurityManager {
43 namespace SmackLabels {
44
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";
47
48 typedef std::function<bool(const FTSENT*)> LabelDecisionFn;
49
50 static bool labelAll(const FTSENT *ftsent __attribute__((unused)))
51 {
52     return true;
53 }
54
55 static bool labelDirs(const FTSENT *ftsent)
56 {
57     // label only directories
58     return (S_ISDIR(ftsent->fts_statp->st_mode));
59 }
60
61 static bool labelExecs(const FTSENT *ftsent)
62 {
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));
66 }
67
68 static inline void pathSetSmack(const char *path, const std::string &label,
69         const char *xattr_name)
70 {
71     if (lsetxattr(path, xattr_name, label.c_str(), label.length(), 0)) {
72         LogError("lsetxattr failed.");
73         ThrowMsg(SmackException::FileError, "lsetxattr failed.");
74     }
75 }
76
77 static void dirSetSmack(const std::string &path, const std::string &label,
78         const char *xattr_name, LabelDecisionFn fn)
79 {
80     char *const path_argv[] = {const_cast<char *>(path.c_str()), NULL};
81     FTSENT *ftsent;
82
83     std::unique_ptr<FTS, std::function<void(FTS*)> > fts(
84             fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL),
85             fts_close);
86
87     if (!fts) {
88         LogError("fts_open failed.");
89         ThrowMsg(SmackException::FileError, "fts_open failed.");
90     }
91
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)");
97         }
98
99         /* avoid to tag directories two times */
100         if (ftsent->fts_info == FTS_D)
101             continue;
102
103         if (fn(ftsent))
104             pathSetSmack(ftsent->fts_path, label, xattr_name);
105     }
106
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));
111     }
112 }
113
114 static void labelDir(const std::string &path, const std::string &label,
115         bool set_transmutable, bool set_executables)
116 {
117     // setting access label on everything in given directory and below
118     dirSetSmack(path, label, XATTR_NAME_SMACK, labelAll);
119
120     // setting transmute on dirs
121     if (set_transmutable)
122         dirSetSmack(path, "TRUE", XATTR_NAME_SMACKTRANSMUTE, labelDirs);
123
124     // setting SMACK64EXEC labels
125     if (set_executables)
126         dirSetSmack(path, label, XATTR_NAME_SMACKEXEC, &labelExecs);
127 }
128
129 void setupPath(const std::string &pkgId, const std::string &path, app_install_path_type pathType,
130         const std::string &zoneId)
131 {
132     std::string label;
133     bool label_executables, label_transmute;
134
135     switch (pathType) {
136     case SECURITY_MANAGER_PATH_RW:
137         label = zoneSmackLabelGenerate(generatePkgLabel(pkgId), zoneId);
138         label_executables = false;
139         label_transmute = true;
140         break;
141     case SECURITY_MANAGER_PATH_RO:
142         label = zoneSmackLabelGenerate(generatePkgROLabel(pkgId), zoneId);
143         label_executables = false;
144         label_transmute = false;
145         break;
146     case SECURITY_MANAGER_PATH_PUBLIC_RO:
147         label.assign(LABEL_FOR_APP_PUBLIC_RO_PATH);
148         label_executables = false;
149         label_transmute = true;
150         break;
151     default:
152         LogError("Path type not known.");
153         Throw(SmackException::InvalidPathType);
154     }
155     return labelDir(path, label, label_transmute, label_executables);
156 }
157
158 void setupAppBasePath(const std::string &pkgId, const std::string &basePath)
159 {
160     std::string pkgPath = basePath + "/" + pkgId;
161     pathSetSmack(pkgPath.c_str(), LABEL_FOR_APP_PUBLIC_RO_PATH, XATTR_NAME_SMACK);
162 }
163
164 std::string generateAppNameFromLabel(const std::string &label)
165 {
166     static const char prefix[] = "User::App::";
167
168     if (label.compare(0, sizeof(prefix) - 1, prefix))
169         ThrowMsg(SmackException::InvalidLabel, "Cannot extract appId from Smack label " << label);
170
171     return label.substr(sizeof(prefix) - 1);
172 }
173
174 std::string generateAppLabel(const std::string &appId)
175 {
176     std::string label = "User::App::" + appId;
177
178     if (smack_label_length(label.c_str()) <= 0)
179         ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from appId " << appId);
180
181     return label;
182 }
183
184 std::string generatePkgLabel(const std::string &pkgId)
185 {
186     std::string label = "User::Pkg::" + pkgId;
187
188     if (smack_label_length(label.c_str()) <= 0)
189         ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from pkgId " << pkgId);
190
191     return label;
192 }
193
194 std::string generatePkgROLabel(const std::string &pkgId)
195 {
196     std::string label = "User::Pkg::" + pkgId + "::RO";
197
198     if (smack_label_length(label.c_str()) <= 0)
199         ThrowMsg(SmackException::InvalidLabel, "Invalid Smack label generated from pkgId " << pkgId);
200
201     return label;
202 }
203
204
205 } // namespace SmackLabels
206 } // namespace SecurityManager