Extend AppInstallHelper with checker methods
[platform/core/test/security-tests.git] / src / security-manager-tests / common / sm_commons.cpp
1 /*
2  * Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include <cstring>
18 #include <fcntl.h>
19 #include <ftw.h>
20 #include <string>
21 #include <sys/capability.h>
22 #include <sys/prctl.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <cstdlib>
26
27 #include <utility>
28 #include <vector>
29 #include <unordered_map>
30
31 #include <security-manager-types.h>
32 #include <app-runtime.h>
33 #include <privilege_info.h>
34 #include <scoped_process_label.h>
35
36 #include <dpl/test/test_runner.h>
37 #include <memory.h>
38 #include <sm_api.h>
39 #include <sm_commons.h>
40
41 #include <tests_common.h>
42 #include "tzplatform.h"
43 #include <template_parser.h>
44 #include <temp_test_user.h>
45
46 using namespace SecurityManagerTest;
47
48 #define ALLOW 0
49 #define DENY -1
50
51 // Common DB/nftw checks
52
53 // nftw doesn't allow passing user data to functions. Work around by using global variable
54 static std::string nftw_expected_label;
55 bool nftw_expected_transmute;
56 bool nftw_expected_exec;
57
58 static int nftw_check_sm_labels_app_dir(const char *fpath, const struct stat *sb,
59                               const char* correctLabel, bool transmute_test, bool exec_test)
60 {
61     int result;
62     CStringPtr labelPtr;
63     char* label = nullptr;
64
65     /* ACCESS */
66     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
67     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
68     labelPtr.reset(label);
69     RUNNER_ASSERT_MSG(label != nullptr, "ACCESS label on " << fpath << " is not set");
70     result = strcmp(correctLabel, label);
71     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect"
72             " (should be '" << correctLabel << "' and is '" << label << "')");
73
74
75     /* EXEC */
76     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
77     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
78     labelPtr.reset(label);
79
80     if (S_ISREG(sb->st_mode) && (sb->st_mode & S_IXUSR) && exec_test) {
81         RUNNER_ASSERT_MSG(label != nullptr, "EXEC label on " << fpath << " is not set");
82         result = strcmp(correctLabel, label);
83         RUNNER_ASSERT_MSG(result == 0, "Incorrect EXEC label on executable file " << fpath);
84     } else
85         RUNNER_ASSERT_MSG(label == nullptr, "EXEC label on " << fpath << " is set");
86
87
88     /* TRANSMUTE */
89     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
90     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
91     labelPtr.reset(label);
92
93     if (S_ISDIR(sb->st_mode) && transmute_test == true) {
94         RUNNER_ASSERT_MSG(label != nullptr, "TRANSMUTE label on " << fpath << " is not set at all");
95         RUNNER_ASSERT_MSG(strcmp(label,"TRUE") == 0,
96                 "TRANSMUTE label on " << fpath << " is not set properly: '"<<label<<"'");
97     } else {
98         RUNNER_ASSERT_MSG(label == nullptr, "TRANSMUTE label on " << fpath << " is set");
99     }
100
101     return 0;
102 }
103
104 static int nftw_check_sm_labels(const char *fpath, const struct stat *sb,
105                                int /*typeflag*/, struct FTW* /*ftwbuf*/)
106 {
107     return nftw_check_sm_labels_app_dir(fpath, sb,
108         nftw_expected_label.c_str(), nftw_expected_transmute, nftw_expected_exec);
109 }
110
111 int nftw_check_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
112                                   int /*typeflag*/, struct FTW* /*ftwbuf*/)
113 {
114     int result;
115     CStringPtr labelPtr;
116     char* label = nullptr;
117
118     /* ACCESS */
119     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
120     labelPtr.reset(label);
121     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
122     result = strcmp("canary_label", labelPtr.get());
123     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is overwritten");
124
125     /* EXEC */
126     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
127     labelPtr.reset(label);
128     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
129     result = strcmp("canary_label", labelPtr.get());
130     RUNNER_ASSERT_MSG(result == 0, "EXEC label on " << fpath << " is overwritten");
131
132     /* TRANSMUTE */
133     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
134     labelPtr.reset(label);
135     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
136     RUNNER_ASSERT_MSG(labelPtr.get() == nullptr, "TRANSMUTE label on " << fpath << " is set");
137
138     return 0;
139 }
140
141 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
142                        int /*typeflag*/, struct FTW* /*ftwbuf*/)
143 {
144     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_ACCESS);
145     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_EXEC);
146     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
147
148     return 0;
149 }
150
151 void check_path(const std::string &path, const std::string &label, bool transmute, bool execute) {
152     nftw_expected_label = label;
153     nftw_expected_transmute = transmute;
154     nftw_expected_exec = execute;
155
156     // check labels
157     int result = nftw(path.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
158     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
159 }
160
161 CapsSetsUniquePtr setCaps(const char *cap_string)
162 {
163     CapsSetsUniquePtr caps(cap_init());
164     caps.reset(cap_from_text(cap_string));
165     RUNNER_ASSERT_MSG(caps, "can't convert capabilities from text");
166     int result = cap_set_proc(caps.get());
167     RUNNER_ASSERT_MSG(result == 0, "can't set capabilities. Result: " << result);
168     return caps;
169 }
170
171 static int getOppositeAccessType(int accessType) {
172     return accessType ^ (R_OK | W_OK | X_OK);
173 }
174
175 static const std::unordered_map<int, const char* const> accessTypeToString {
176     std::make_pair(0, "F_OK"),
177     std::make_pair(1, "X_OK"),
178     std::make_pair(2, "W_OK"),
179     std::make_pair(3, "W_OK|X_OK"),
180     std::make_pair(4, "R_OK"),
181     std::make_pair(5, "R_OK|X_OK"),
182     std::make_pair(6, "R_OK|W_OK"),
183     std::make_pair(7, "R_OK|W_OK|X_OK")
184 };
185
186 void accessCheck(const std::string &id, const std::string &path, int accessType,
187                  int expected)
188 {
189     RUNNER_ASSERT_MSG(::access(path.c_str(), accessType) == expected,
190                       "access from " << id << " to path " << path
191                        << (expected == 0 ? " not granted" : " unnecessarily granted")
192                        << " (" << accessTypeToString.at(accessType) << ")");
193 }
194
195 void accessTest(const std::string &id, const std::string &testPath, int accessType) {
196     int oppositeAccessType = getOppositeAccessType(accessType);
197
198     if (accessType != 0) {
199         accessCheck(id, testPath, accessType, ALLOW);
200     }
201     if (oppositeAccessType != 0) {
202         static const std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
203         for (auto singleAccessType : singleAccessTypes) {
204             if (oppositeAccessType & singleAccessType) {
205                 accessCheck(id, testPath, singleAccessType, DENY);
206             }
207         }
208     }
209 }
210
211 void runAccessTest(const std::string &label, uid_t uid, gid_t gid,
212                    const std::string &testPath, int accessType) {
213     auto fun = [&](){
214         ScopedProcessLabel spl(label, false);
215         RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(uid, gid),
216                                 "drop_root_privileges failed.");
217
218         accessTest(label, testPath, accessType);
219     };
220
221     runInChildParentWait(fun);
222 }
223
224 void runAccessTest(const AppInstallHelper &app, const std::string &testPath, int accessType) {
225     auto fun = [&](){
226         Api::setProcessLabel(app.getAppId());
227         RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(app.getUID(), app.getGID()),
228                                 "drop_root_privileges failed.");
229         accessTest(app.getAppId(), testPath, accessType);
230     };
231
232     runInChildParentWait(fun);
233 }
234
235 static const std::vector<std::string> SM_SYSTEM_LABELS = {"System", "System::Privileged", "User"};
236
237 void runSystemAccessTest(uid_t uid, gid_t gid, const std::string &testPath, int accessType) {
238     for (const auto &label : SM_SYSTEM_LABELS)
239         runAccessTest(label, uid, gid, testPath, accessType);
240 }
241
242 bool isAskuserDisabled() {
243     static bool isAskuserDisabled = false;
244     static bool isChecked = false;
245
246     if (isChecked)
247         return isAskuserDisabled;
248
249     std::string sysShare = TzPlatformConfig::getPath(TZ_SYS_SHARE);
250     std::string askDisableFile = sysShare + "/askuser_disable";
251
252     isAskuserDisabled = (access(askDisableFile.c_str(), F_OK) != -1);
253     isChecked = true;
254     return isAskuserDisabled;
255 }
256
257 bool isPrivilegePrivacy(const std::string &priv) {
258     return (1 == privilege_info_is_privacy(priv.c_str()));
259 }
260
261 int countPrivacyPrivileges(const PrivilegeVector &privs) {
262     return std::count_if(privs.begin(), privs.end(), isPrivilegePrivacy);
263 }
264
265 int countPrivacyPrivileges(const std::vector<std::string> &privs) {
266     return std::count_if(privs.begin(), privs.end(), isPrivilegePrivacy);
267 }
268
269 int setLauncherSecurityAttributes(uid_t uid, gid_t gid)
270 {
271     // Add launcher capabilities (cap_dac_override, cap_setgid, cap_sys_admin, cap_mac_admin),
272     // launcher is user process, we must drop root privileges (cap_setgid, cap_setuid are needed).
273     // By default, the permitted capability set is cleared when credentials change is made
274     // (if a process drops a capability from its permitted set, it can never reacquire that capability),
275     // setting the "keep capabilities" flag prevents it from being cleared.
276     // Effective capability set is always cleared when credential change is made, we need to add them again.
277
278     setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep cap_setuid+ep");
279     int ret = prctl(PR_SET_KEEPCAPS, 1, 0, 0);
280     if (ret != 0)
281         return ret;
282
283     ret = drop_root_privileges(uid, gid);
284     if (ret != 0)
285         return ret;
286
287     setCaps("cap_dac_override+ep cap_setgid+ep cap_sys_admin+ep cap_mac_admin+ep");
288     return ret;
289 }
290 int setLauncherSecurityAttributes(TemporaryTestUser &user)
291 {
292     return setLauncherSecurityAttributes(user.getUid(), user.getGid());
293 }
294