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