Generic solution for onlycap issues
[platform/core/test/security-tests.git] / src / security-manager-tests / common / sm_commons.cpp
1 /*
2  * Copyright (c) 2016 - 2019 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 <algorithm>
18 #include <cstring>
19 #include <fcntl.h>
20 #include <ftw.h>
21 #include <grp.h>
22 #include <string>
23 #include <sys/capability.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <unordered_map>
28 #include <cstdlib>
29
30 #include <unordered_set>
31 #include <vector>
32
33 #include <security-manager-types.h>
34 #include <app-runtime.h>
35 #include <sys/smack.h>
36 #include <privilege_info.h>
37 #include <scoped_process_label.h>
38
39 #include <cynara_test_client.h>
40 #include <dpl/test/test_runner.h>
41 #include <memory.h>
42 #include <sm_api.h>
43 #include <sm_commons.h>
44 #include <synchronization_pipe.h>
45 #include <sm_request.h>
46 #include <tests_common.h>
47 #include <policy_configuration.h>
48 #include "tzplatform.h"
49 #include <label_generator.h>
50
51 using namespace SecurityManagerTest;
52
53 // Common DB/nftw checks
54
55 // nftw doesn't allow passing user data to functions. Work around by using global variable
56 static std::string nftw_expected_label;
57 bool nftw_expected_transmute;
58 bool nftw_expected_exec;
59
60 static int nftw_check_sm_labels_app_dir(const char *fpath, const struct stat *sb,
61                               const char* correctLabel, bool transmute_test, bool exec_test)
62 {
63     int result;
64     CStringPtr labelPtr;
65     char* label = nullptr;
66
67     /* ACCESS */
68     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
69     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
70     labelPtr.reset(label);
71     RUNNER_ASSERT_MSG(label != nullptr, "ACCESS label on " << fpath << " is not set");
72     result = strcmp(correctLabel, label);
73     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect"
74             " (should be '" << correctLabel << "' and is '" << label << "')");
75
76
77     /* EXEC */
78     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
79     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
80     labelPtr.reset(label);
81
82     if (S_ISREG(sb->st_mode) && (sb->st_mode & S_IXUSR) && exec_test) {
83         RUNNER_ASSERT_MSG(label != nullptr, "EXEC label on " << fpath << " is not set");
84         result = strcmp(correctLabel, label);
85         RUNNER_ASSERT_MSG(result == 0, "Incorrect EXEC label on executable file " << fpath);
86     } else
87         RUNNER_ASSERT_MSG(label == nullptr, "EXEC label on " << fpath << " is set");
88
89
90     /* TRANSMUTE */
91     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
92     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
93     labelPtr.reset(label);
94
95     if (S_ISDIR(sb->st_mode) && transmute_test == true) {
96         RUNNER_ASSERT_MSG(label != nullptr, "TRANSMUTE label on " << fpath << " is not set at all");
97         RUNNER_ASSERT_MSG(strcmp(label,"TRUE") == 0,
98                 "TRANSMUTE label on " << fpath << " is not set properly: '"<<label<<"'");
99     } else {
100         RUNNER_ASSERT_MSG(label == nullptr, "TRANSMUTE label on " << fpath << " is set");
101     }
102
103     return 0;
104 }
105
106 static int nftw_check_sm_labels(const char *fpath, const struct stat *sb,
107                                int /*typeflag*/, struct FTW* /*ftwbuf*/)
108 {
109     return nftw_check_sm_labels_app_dir(fpath, sb,
110         nftw_expected_label.c_str(), nftw_expected_transmute, nftw_expected_exec);
111 }
112
113 int nftw_check_labels_non_app_dir(const char *fpath, const struct stat* /*sb*/,
114                                   int /*typeflag*/, struct FTW* /*ftwbuf*/)
115 {
116     int result;
117     CStringPtr labelPtr;
118     char* label = nullptr;
119
120     /* ACCESS */
121     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
122     labelPtr.reset(label);
123     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
124     result = strcmp("canary_label", labelPtr.get());
125     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is overwritten");
126
127     /* EXEC */
128     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
129     labelPtr.reset(label);
130     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
131     result = strcmp("canary_label", labelPtr.get());
132     RUNNER_ASSERT_MSG(result == 0, "EXEC label on " << fpath << " is overwritten");
133
134     /* TRANSMUTE */
135     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
136     labelPtr.reset(label);
137     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
138     RUNNER_ASSERT_MSG(labelPtr.get() == nullptr, "TRANSMUTE label on " << fpath << " is set");
139
140     return 0;
141 }
142
143 int nftw_remove_labels(const char *fpath, const struct stat* /*sb*/,
144                        int /*typeflag*/, struct FTW* /*ftwbuf*/)
145 {
146     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_ACCESS);
147     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_EXEC);
148     smack_lsetlabel(fpath, nullptr, SMACK_LABEL_TRANSMUTE);
149
150     return 0;
151 }
152
153 void check_app_permissions(const std::string &app_id, const std::string &pkg_id,
154                            const std::string &user, const privileges_t &allowed_privs,
155                            const privileges_t &denied_privs, bool isHybrid)
156 {
157     (void) pkg_id;
158     std::string smackLabel = generateProcessLabel(app_id, pkg_id, isHybrid);
159
160     CynaraTestClient::Client ctc;
161
162     for (auto &priv : allowed_privs) {
163         ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_ALLOWED);
164     }
165
166     for (auto &priv : denied_privs) {
167         ctc.check(smackLabel.c_str(), "", user, priv.c_str(), CYNARA_API_ACCESS_DENIED);
168     }
169 }
170
171 void sm_app_has_privileges(const AppInstallHelper &app,
172                            const std::vector<std::string> &privileges,
173                            int expectedResult)
174 {
175     for (auto const &privilege : privileges) {
176         int result;
177         Api::appHasPrivilege(app.getAppId(), privilege, app.getUID(), result);
178         RUNNER_ASSERT_MSG(result == expectedResult, "Application " << app.getAppId()
179                           << " has unexpected access to " << privilege << ", is : "
180                           << " should be : " << expectedResult );
181     }
182 }
183
184 static void check_app(const std::string &appId, const std::string &pkgId, bool shouldBeInstalled)
185 {
186     char *retPkgId;
187     int ret = security_manager_get_app_pkgid(&retPkgId, appId.c_str());
188
189     if (shouldBeInstalled) {
190         RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_SUCCESS, "The given appId is not installed.");
191
192         if (ret == SECURITY_MANAGER_SUCCESS) {
193             CStringPtr retPkgIdPtr(retPkgId);
194             RUNNER_ASSERT_MSG(strcmp(pkgId.c_str(), retPkgId) == 0,
195                               "The given appId does not belong to the given pkgId.");
196         }
197     } else {
198         RUNNER_ASSERT_MSG(ret == SECURITY_MANAGER_ERROR_NO_SUCH_OBJECT, "The given appId is installed.");
199     }
200 }
201
202 void check_app_after_install(const std::string &app_id, const std::string &pkg_id)
203 {
204     check_app(app_id, pkg_id, true);
205 }
206
207 static void check_app_gids(const std::string &app_id, const std::vector<gid_t> &allowed_gids)
208 {
209     int ret;
210     gid_t main_gid = getgid();
211     std::unordered_set<gid_t> reference_gids(allowed_gids.begin(), allowed_gids.end());
212
213     // Reset supplementary groups
214     ret = setgroups(0, NULL);
215     RUNNER_ASSERT_MSG(ret != -1, "Unable to set supplementary groups");
216
217     Api::setProcessGroups(app_id);
218
219     ret = getgroups(0, nullptr);
220     RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
221
222     std::vector<gid_t> actual_gids(ret);
223     ret = getgroups(ret, actual_gids.data());
224     RUNNER_ASSERT_MSG(ret != -1, "Unable to get supplementary groups");
225
226     for (const auto &gid : actual_gids) {
227         RUNNER_ASSERT_MSG(gid == main_gid || reference_gids.count(gid) > 0,
228             "Application shouldn't get access to group " << gid);
229         reference_gids.erase(gid);
230     }
231
232     RUNNER_ASSERT_MSG(reference_gids.empty(), "Application didn't get access to some groups");
233 }
234
235 static const char *const ANY_USER_REPRESENTATION = "anyuser";/*this may be actually any string*/
236
237 void check_app_after_install(const std::string &app_id, const std::string &pkg_id,
238                              const privileges_t &allowed_privs,
239                              const privileges_t &denied_privs,
240                              bool isHybrid)
241 {
242     check_app(app_id, pkg_id, true);
243
244     /* Privileges should be granted to all users if root installs app */
245     check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, allowed_privs, denied_privs, isHybrid);
246
247     PolicyConfiguration policy;
248     const PolicyConfiguration::GroupVector allowed_groups = policy.privToGroup(allowed_privs);
249     RUNNER_ASSERT_MSG(allowed_groups.size() == allowed_privs.size(),
250                       "Some privileges given were not found in the policy");
251
252     std::vector<gid_t> allowed_gids;
253     for (const auto &groupName : allowed_groups) {
254         errno = 0;
255         struct group* grp = getgrnam(groupName.c_str());
256         RUNNER_ASSERT_ERRNO_MSG(grp, "Group: " << groupName << " not found");
257         allowed_gids.push_back(grp->gr_gid);
258     }
259
260     check_app_gids(app_id, allowed_gids);
261 }
262
263 void check_path(const std::string &path, const std::string &label, bool transmute, bool execute) {
264     nftw_expected_label = label;
265     nftw_expected_transmute = transmute;
266     nftw_expected_exec = execute;
267
268     // check labels
269     int result = nftw(path.c_str(), &nftw_check_sm_labels, FTW_MAX_FDS, FTW_PHYS);
270     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for " << path);
271 }
272
273 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id)
274 {
275     check_app(app_id, pkg_id, false);
276 }
277
278 void check_app_after_uninstall(const std::string &app_id, const std::string &pkg_id,
279                                const privileges_t &privileges, bool isHybrid)
280 {
281     check_app(app_id, pkg_id, false);
282
283     /* Privileges should not be granted anymore to any user */
284     check_app_permissions(app_id, pkg_id, ANY_USER_REPRESENTATION, {}, privileges, isHybrid);
285 }
286
287 std::string access_opposite(std::string &access) {
288     static const std::map<char, int> access_mapping = {{'r', 0}, {'w', 1}, {'x', 2}, {'a', 3},
289                                                        {'t', 4}, {'l', 5}};
290     // May write implies may lock
291     if (access.find('w') != std::string::npos && access.find('l') == std::string::npos) {
292         access.append("l");
293     }
294     std::string access_opposite = "rwxatl";
295     for (char c : access) {
296         access_opposite[access_mapping.at(c)] = '-';
297     }
298     auto it = std::remove_if(access_opposite.begin(), access_opposite.end(), [](char c) {return c == '-';});
299     access_opposite.erase(it, access_opposite.end());
300     return access_opposite;
301 }
302
303 void check_exact_smack_accesses(const std::string &subject, const std::string &object,
304                                 const std::string &access) {
305     std::string access_str(access);
306     auto no_access = access_opposite(access_str);
307     for (char c : access_str) {
308         int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
309         RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
310                           << ">, <" << c << "> errno=" << strerror(errno));
311         RUNNER_ASSERT_MSG(ret == 1, "Access " << c << " from " << subject << " to "
312                           << object << " not given");
313     }
314
315     for (char c : no_access) {
316         int ret = smack_have_access(subject.c_str(), object.c_str(), std::string(1, c).c_str());
317         RUNNER_ASSERT_MSG(ret >= 0, "smack_have_access failed: <" << subject << ">, <" << object
318                           << ">, <" << c << "> errno=" << strerror(errno));
319         RUNNER_ASSERT_MSG(ret == 0, "Access " << c << " from " << subject << " to "
320                           << object << " unnecessarily given");
321     }
322 }
323
324 CapsSetsUniquePtr setCaps(const char *cap_string)
325 {
326     CapsSetsUniquePtr caps(cap_init());
327     caps.reset(cap_from_text(cap_string));
328     RUNNER_ASSERT_MSG(caps, "can't convert capabilities from text");
329     int result = cap_set_proc(caps.get());
330     RUNNER_ASSERT_MSG(result == 0, "can't set capabilities. Result: " << result);
331     return caps;
332 }
333
334 static int getOppositeAccessType(int accessType) {
335     return accessType ^ (R_OK | W_OK | X_OK);
336 }
337
338 static const std::unordered_map<int, const char* const> accessTypeToString {
339     std::make_pair(0, "F_OK"),
340     std::make_pair(1, "X_OK"),
341     std::make_pair(2, "W_OK"),
342     std::make_pair(3, "W_OK|X_OK"),
343     std::make_pair(4, "R_OK"),
344     std::make_pair(5, "R_OK|X_OK"),
345     std::make_pair(6, "R_OK|W_OK"),
346     std::make_pair(7, "R_OK|W_OK|X_OK")
347 };
348
349 void accessCheck(const std::string &id, const std::string &path, int accessType,
350                  int expected)
351 {
352     RUNNER_ASSERT_MSG(::access(path.c_str(), accessType) == expected,
353                       "access from " << id << " to path " << path
354                        << (expected == 0 ? " not granted" : " unnecessarily granted")
355                        << " (" << accessTypeToString.at(accessType) << ")");
356 }
357
358 void runAccessTest(const std::string &label, uid_t uid, gid_t gid,
359                    const std::string &testPath, int accessType) {
360     auto fun = [&](){
361         int oppositeAccessType = getOppositeAccessType(accessType);
362         ScopedProcessLabel spl(label, false);
363         RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(uid, gid),
364                                 "drop_root_privileges failed.");
365
366         if (accessType != 0)
367             accessCheck(label, testPath, accessType, 0);
368         if (oppositeAccessType != 0) {
369             std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
370             for (auto singleAccessType : singleAccessTypes)
371                 if (oppositeAccessType & singleAccessType)
372                     accessCheck(label, testPath, singleAccessType, -1);
373         }
374     };
375
376     runInChildParentWait(fun);
377 }
378
379 void runAccessTest(const AppInstallHelper &app, const std::string &testPath, int accessType) {
380     auto fun = [&](){
381         int oppositeAccessType = getOppositeAccessType(accessType);
382         Api::setProcessLabel(app.getAppId());
383         RUNNER_ASSERT_ERRNO_MSG(0 == drop_root_privileges(app.getUID(), app.getGID()),
384                                 "drop_root_privileges failed.");
385         if (accessType != 0)
386             accessCheck(app.getAppId(), testPath, accessType, 0);
387         if (oppositeAccessType != 0) {
388             std::vector<int> singleAccessTypes = {R_OK, W_OK, X_OK};
389             for (auto singleAccessType : singleAccessTypes)
390                 if (oppositeAccessType & singleAccessType)
391                     accessCheck(app.getAppId(), testPath, singleAccessType, -1);
392         }
393     };
394
395     runInChildParentWait(fun);
396 }
397
398 static const std::vector<std::string> SM_SYSTEM_LABELS = {"System", "System::Privileged", "User"};
399
400 void runSystemAccessTest(uid_t uid, gid_t gid, const std::string &testPath, int accessType) {
401     for (const auto &label : SM_SYSTEM_LABELS)
402         runAccessTest(label, uid, gid, testPath, accessType);
403 }
404
405 bool isAskuserDisabled() {
406     static bool isAskuserDisabled = false;
407     static bool isChecked = false;
408
409     if (isChecked)
410         return isAskuserDisabled;
411
412     std::string sysShare = TzPlatformConfig::getPath(TZ_SYS_SHARE);
413     std::string askDisableFile = sysShare + "/askuser_disable";
414
415     isAskuserDisabled = (access(askDisableFile.c_str(), F_OK) != -1);
416     isChecked = true;
417     return isAskuserDisabled;
418 }
419
420 bool isPrivilegePrivacy(const std::string &priv) {
421     return (1 == privilege_info_is_privacy(priv.c_str()));
422 }
423
424 int countPrivacyPrivileges(const PrivilegeVector &privs) {
425     return std::count_if(privs.begin(), privs.end(), isPrivilegePrivacy);
426 }
427
428 int countPrivacyPrivileges(const std::vector<std::string> &privs) {
429     return std::count_if(privs.begin(), privs.end(), isPrivilegePrivacy);
430 }
431