Test for app_give_access, app_revoke_access function.
[platform/core/test/security-tests.git] / tests / libprivilege-control-tests / test_cases.cpp
1 /*
2  * Copyright (c) 2012 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 /*
18  * @file        test_cases.cpp
19  * @author      Jan Olszak (j.olszak@samsung.com)
20  * @author      Rafal Krypa (r.krypa@samsung.com)
21  * @version     1.0
22  * @brief       libprivilege-control test runer
23  */
24
25 #include <string>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <vector>
29 #include <errno.h>
30 #include <memory>
31 #include <ftw.h>
32 #include <dpl/test/test_runner.h>
33 #include <dpl/test/test_runner_child.h>
34 #include <dpl/log/log.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/mman.h>
38 #include <sys/xattr.h>
39 #include <sys/smack.h>
40 #include <privilege-control.h>
41
42
43 #define SMACK_RULES_DIR  "/etc/smack/accesses.d/"
44 #define TEST_APP_DIR "/etc/smack/test_privilege_control_DIR/app_dir"
45 #define TEST_NON_APP_DIR "/etc/smack/test_privilege_control_DIR/non_app_dir"
46 #define APPID_ADD  "test_APP_ID_add"
47 #define APPID_REVOKE  "test_APP_ID_revoke"
48 #define APPID_DIR  "test_APP_ID_dir"
49 #define APPID_SHARED_DIR  "test_APP_ID_shared_dir"
50 #define CANARY_LABEL "tiny_yellow_canary"
51
52 #define APP_SET_PRIV  "test_APP"
53 #define APP_SET_PRIV_PATH "/etc/smack/test_privilege_control_DIR/test_set_app_privilege/test_APP"
54 #define APP_SET_PRIV_PATH_REAL "/etc/smack/test_privilege_control_DIR/test_set_app_privilege/test_APP_REAL"
55
56 const char *PRIVS[] = { "WRT", "test_privilege_control_rules", NULL };
57
58 #define APP_GID 5000
59 #define APP_UID 5000
60 #define APP_USER_NAME "app"
61 #define APP_HOME_DIR "/opt/home/app"
62
63 // How many open file descriptors should ftw() function use?
64 #define FTW_MAX_FDS 16
65
66 // Rules from test_privilege_control_rules.smack
67 const std::vector< std::vector<std::string> > rulesAdd = {
68         { APPID_ADD, "test_book_1", "r" },
69         { APPID_ADD, "test_book_2", "w" },
70         { APPID_ADD, "test_book_3", "x" },
71         { APPID_ADD, "test_book_4", "rw" },
72         { APPID_ADD, "test_book_5", "rx" },
73         { APPID_ADD, "test_book_6", "wx" },
74         { APPID_ADD, "test_book_7", "rwx" },
75         { "test_subject_1", APPID_ADD, "r" },
76         { "test_subject_2", APPID_ADD, "w" },
77         { "test_subject_3", APPID_ADD, "x" },
78         { "test_subject_4", APPID_ADD, "rw" },
79         { "test_subject_5", APPID_ADD, "rx" },
80         { "test_subject_6", APPID_ADD, "wx" },
81         { "test_subject_7", APPID_ADD, "rwx" },
82         { APPID_ADD, APPID_SHARED_DIR, "rwxat"}};
83
84
85 // Rules from test_privilege_control_rules.smack
86 const std::vector< std::vector<std::string> > rulesRevoke = {
87         { APPID_REVOKE, "test_book_1", "r" },
88         { APPID_REVOKE, "test_book_2", "w" },
89         { APPID_REVOKE, "test_book_3", "x" },
90         { APPID_REVOKE, "test_book_4", "rw" },
91         { APPID_REVOKE, "test_book_5", "rx" },
92         { APPID_REVOKE, "test_book_6", "wx" },
93         { APPID_REVOKE, "test_book_7", "rwx" },
94         { "test_subject_1", APPID_REVOKE, "r" },
95         { "test_subject_2", APPID_REVOKE, "w" },
96         { "test_subject_3", APPID_REVOKE, "x" },
97         { "test_subject_4", APPID_REVOKE, "rw" },
98         { "test_subject_5", APPID_REVOKE, "rx" },
99         { "test_subject_6", APPID_REVOKE, "wx" },
100         { "test_subject_7", APPID_REVOKE, "rwx" }};
101
102 /**
103  * Check if every rule is true.
104  * @return 1 if ALL rules in SMACK, 0 if ANY rule isn't
105  */
106 int test_have_all_accesses(const std::vector< std::vector<std::string> >& rules){
107     int result;
108     for(uint i =0; i<rules.size();++i ){
109         result = smack_have_access(rules[i][0].c_str(),rules[i][1].c_str(),rules[i][2].c_str());
110         if (result !=1)
111             return result;
112     }
113     return 1;
114 }
115
116 /**
117  * Check if every rule is true.
118  * @return 1 if ANY rule in SMACK, 0 if
119  */
120 int test_have_any_accesses(const std::vector< std::vector<std::string> >& rules){
121     int result;
122     for(uint i =0; i<rules.size();++i ){
123         result = smack_have_access(rules[i][0].c_str(),rules[i][1].c_str(),rules[i][2].c_str());
124         if (result ==1)
125             return 1;
126     }
127     return 0;
128 }
129
130 RUNNER_TEST_GROUP_INIT(libprivilegecontrol)
131
132 static int nftw_remove_labels(const char *fpath, const struct stat *sb,
133                                 int typeflag, struct FTW *ftwbuf)
134 {
135         smack_lsetlabel(fpath, NULL, SMACK_LABEL_ACCESS);
136         smack_lsetlabel(fpath, NULL, SMACK_LABEL_EXEC);
137         smack_lsetlabel(fpath, NULL, SMACK_LABEL_TRANSMUTE);
138
139         return 0;
140 }
141
142 static int nftw_set_labels_non_app_dir(const char *fpath, const struct stat *sb,
143                                 int typeflag, struct FTW *ftwbuf)
144 {
145         smack_lsetlabel(fpath, CANARY_LABEL, SMACK_LABEL_ACCESS);
146         smack_lsetlabel(fpath, CANARY_LABEL, SMACK_LABEL_EXEC);
147         smack_lsetlabel(fpath, NULL, SMACK_LABEL_TRANSMUTE);
148
149         return 0;
150 }
151
152 static int nftw_check_labels_non_app_dir(const char *fpath, const struct stat *sb,
153                                 int typeflag, struct FTW *ftwbuf)
154 {
155     int result;
156     char* label;
157
158     /* ACCESS */
159     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
160     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
161     result = strcmp(CANARY_LABEL, label);
162     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is overwritten");
163
164     /* EXEC */
165     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
166     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
167     result = strcmp(CANARY_LABEL, label);
168     RUNNER_ASSERT_MSG(result == 0, "EXEC label on " << fpath << " is overwritten");
169
170     /* TRANSMUTE */
171     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
172     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
173     RUNNER_ASSERT_MSG(label == NULL, "TRANSMUTE label on " << fpath << " is set");
174
175     return 0;
176 }
177
178 static int nftw_check_labels_app_dir(const char *fpath, const struct stat *sb,
179                                 int typeflag, struct FTW *ftwbuf)
180 {
181     int result;
182     char* label;
183
184     /* ACCESS */
185     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
186     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
187     RUNNER_ASSERT_MSG(label != NULL, "ACCESS label on " << fpath << " is not set");
188     result = strcmp(APPID_DIR, label);
189     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect");
190
191     /* EXEC */
192     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
193     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
194     if (S_ISREG(sb->st_mode) && (sb->st_mode & S_IXUSR)) {
195         RUNNER_ASSERT_MSG(label != NULL, "EXEC label on " << fpath << " is not set");
196         result = strcmp(APPID_DIR, label);
197         RUNNER_ASSERT_MSG(result == 0, "EXEC label on executable file " << fpath << " is incorrect");
198     } else
199         RUNNER_ASSERT_MSG(label == NULL, "EXEC label on " << fpath << " is set");
200
201     /* TRANSMUTE */
202     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
203     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
204     RUNNER_ASSERT_MSG(label == NULL, "TRANSMUTE label on " << fpath << " is set");
205
206     return 0;
207 }
208
209 static int nftw_check_labels_app_shared_dir(const char *fpath, const struct stat *sb,
210                                 int typeflag, struct FTW *ftwbuf)
211 {
212     int result;
213     char* label;
214
215     /* ACCESS */
216     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_ACCESS);
217     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
218     RUNNER_ASSERT_MSG(label != NULL, "ACCESS label on " << fpath << " is not set");
219     result = strcmp(APPID_SHARED_DIR, label);
220     RUNNER_ASSERT_MSG(result == 0, "ACCESS label on " << fpath << " is incorrect");
221
222     /* EXEC */
223     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_EXEC);
224     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
225     RUNNER_ASSERT_MSG(label == NULL, "EXEC label on " << fpath << " is set");
226
227     /* TRANSMUTE */
228     result = smack_lgetlabel(fpath, &label, SMACK_LABEL_TRANSMUTE);
229     RUNNER_ASSERT_MSG(result == 0, "Could not get label for the path");
230     if (S_ISDIR(sb->st_mode)) {
231         RUNNER_ASSERT_MSG(label != NULL, "TRANSMUTE label on " << fpath << " is not set");
232         result = strcmp("TRUE", label);
233         RUNNER_ASSERT_MSG(result == 0, "TRANSMUTE label on " << fpath << " is not set");
234     } else
235         RUNNER_ASSERT_MSG(label == NULL, "TRANSMUTE label on " << fpath << " is set");
236
237     return 0;
238 }
239
240 /**
241  * Test setting labels for all files and folders in given path.
242  */
243 RUNNER_TEST(privilege_control01_app_label_dir)
244 {
245     int result;
246
247     result = nftw(TEST_APP_DIR, &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
248     RUNNER_ASSERT_MSG(result == 0, "Unable to clean up Smack labels in " << TEST_APP_DIR);
249
250     result = nftw(TEST_NON_APP_DIR, &nftw_set_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
251     RUNNER_ASSERT_MSG(result == 0, "Unable to clean up Smack labels in " << TEST_NON_APP_DIR);
252
253     result = app_label_dir(APPID_DIR, TEST_APP_DIR);
254     RUNNER_ASSERT_MSG(result == 0, "app_label_dir() failed");
255
256     result = nftw(TEST_APP_DIR, &nftw_check_labels_app_dir, FTW_MAX_FDS, FTW_PHYS);
257     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for app dir");
258
259     result = nftw(TEST_NON_APP_DIR, &nftw_check_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
260     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for non-app dir");
261 }
262
263 RUNNER_TEST(privilege_control02_app_label_shared_dir)
264 {
265     int result;
266
267     result = nftw(TEST_APP_DIR, &nftw_remove_labels, FTW_MAX_FDS, FTW_PHYS);
268     RUNNER_ASSERT_MSG(result == 0, "Unable to clean up Smack labels in " << TEST_APP_DIR);
269
270     result = nftw(TEST_NON_APP_DIR, &nftw_set_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
271     RUNNER_ASSERT_MSG(result == 0, "Unable to clean up Smack labels in " << TEST_NON_APP_DIR);
272
273     result = app_label_shared_dir(APPID_ADD, APPID_SHARED_DIR, TEST_APP_DIR);
274     RUNNER_ASSERT_MSG(result == 0, "app_label_shared_dir() failed");
275
276     result = nftw(TEST_APP_DIR, &nftw_check_labels_app_shared_dir, FTW_MAX_FDS, FTW_PHYS);
277     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for shared app dir");
278
279     result = nftw(TEST_NON_APP_DIR, &nftw_check_labels_non_app_dir, FTW_MAX_FDS, FTW_PHYS);
280     RUNNER_ASSERT_MSG(result == 0, "Unable to check Smack labels for non-app dir");
281 }
282
283
284 /**
285  * Add permisions from  test_privilege_control_rules template
286  */
287 RUNNER_TEST(privilege_control03_add_permissions)
288 {
289     char* path;
290
291     int result = app_add_permissions(APPID_ADD, PRIVS);
292     RUNNER_ASSERT_MSG(result == PC_OPERATION_SUCCESS,
293             " Error adding app permissions. Errno: " << result);
294
295     // Check if the accesses are realy applied..
296     result = test_have_all_accesses(rulesAdd);
297     RUNNER_ASSERT_MSG(result==1, "Permissions not added.");
298
299     ///Investigate created SMACK rules files..
300     RUNNER_ASSERT_MSG(asprintf(&path, SMACK_RULES_DIR "%s", APPID_ADD) != -1,
301             "Error in asprintf");
302
303     //// File exists?
304     FILE *pFile = fopen(path, "rb");
305     RUNNER_ASSERT_MSG(pFile != NULL,
306             "SMACK file NOT created!. Errno: " << errno);
307
308     //// Is it empty?
309     fseek(pFile, 0L, SEEK_END);
310     int smack_file_length = ftell(pFile);
311     RUNNER_ASSERT_MSG(smack_file_length>0,
312             "SMACK file empty, but privileges list was not empty.. Errno: " << errno);
313
314     // Clean up
315     result = app_revoke_permissions(APPID_ADD);
316     RUNNER_ASSERT_MSG(result == PC_OPERATION_SUCCESS,
317             "Error revoking app permissions. Errno: " << result);
318
319     if (pFile != NULL)
320         fclose(pFile);
321
322 }
323
324 /**
325  * Revoke permissions from the list. Should be executed as privileged user.
326  */
327 RUNNER_TEST(privilege_control04_revoke_permissions)
328 {
329     int result;
330
331     // Prepare permissions that we want to revoke
332     result = app_add_permissions(APPID_REVOKE, PRIVS);
333     RUNNER_ASSERT_MSG(result == PC_OPERATION_SUCCESS,
334             " Error adding app permissions. Errno: " << result);
335
336     // Revoke permissions
337     result = app_revoke_permissions(APPID_REVOKE);
338     RUNNER_ASSERT_MSG(result == PC_OPERATION_SUCCESS,
339             "Error revoking app permissions. Errno: " << result);
340
341     // Are all the permissions revoked?
342     result = test_have_all_accesses(rulesRevoke);
343     RUNNER_ASSERT_MSG(result!=1, "Not all permisions revoked.");
344
345     // Investigate SMACK rules file
346     char* path;
347     RUNNER_ASSERT_MSG(asprintf(&path, SMACK_RULES_DIR "%s", APPID_REVOKE) != -1,
348             "Error in asprintf");
349
350     //// Is the smack file deleted?
351     FILE *pFile = fopen(path, "rb");
352     RUNNER_ASSERT_MSG(pFile == NULL,
353             "SMACK file NOT deleted after revoking ALL privileges. Errno: " << errno);
354
355     RUNNER_ASSERT_MSG(errno == ENOENT,
356             "SMACK file NOT deleted after revoking ALL privileges. Errno: " << errno);
357
358     if (pFile != NULL)
359         fclose(pFile);
360 }
361
362 /**
363  * Set APP privileges.
364  */
365 RUNNER_CHILD_TEST(privilege_control05_set_app_privilege)
366 {
367     int result;
368     char* labelApp = "test_pc_label";
369     char* labelAppSymlink = "test_pc_label_symlink";
370
371     // Preset exec label
372     smack_lsetlabel(APP_SET_PRIV_PATH_REAL, labelApp, SMACK_LABEL_EXEC);
373     smack_lsetlabel(APP_SET_PRIV_PATH, labelAppSymlink, SMACK_LABEL_EXEC);
374
375     // Set APP privileges
376     result = set_app_privilege(APP_SET_PRIV, NULL, APP_SET_PRIV_PATH);
377     RUNNER_ASSERT_MSG(result == PC_OPERATION_SUCCESS, "Error in set_app_privilege. Error: " << result);
378
379     // Check if SMACK label really set
380     char * label;
381     result = smack_new_label_from_self(&label);
382     RUNNER_ASSERT_MSG(result == 0, "Error getting current process label");
383     RUNNER_ASSERT_MSG(label != NULL, "Process label is not set");
384     result = strcmp(labelApp, label);
385     RUNNER_ASSERT_MSG(result == 0, "Process label " << label << " is incorrect");
386
387     // Check if DAC privileges really set
388     RUNNER_ASSERT_MSG(getuid() == APP_UID, "Wrong UID");
389     RUNNER_ASSERT_MSG(getgid() == APP_GID, "Wrong GID");
390
391     result = strcmp(getenv("HOME"), APP_HOME_DIR);
392     RUNNER_ASSERT_MSG(result == 0, "Wrong HOME DIR");
393
394     result = strcmp(getenv("USER"), APP_USER_NAME);
395     RUNNER_ASSERT_MSG(result == 0, "Wrong user USER NAME");
396 }
397
398 RUNNER_TEST(privilege_control06_app_give_access)
399 {
400     const char *subject = "lkjq345v34sfa";
401     const char *object = "lk9290f92lkjz";
402     smack_accesses *tmp = NULL;
403
404     RUNNER_ASSERT(0 == smack_accesses_new(&tmp));
405
406     std::unique_ptr<smack_accesses,std::function<void(smack_accesses*)>>
407         smack(tmp, smack_accesses_free);
408
409     RUNNER_ASSERT(0 == smack_accesses_add(smack.get(), subject, object, "r--a-"));
410     RUNNER_ASSERT(0 == smack_accesses_apply(smack.get()));
411
412     app_give_access(subject, object, "wt");
413
414     RUNNER_ASSERT(1 == smack_have_access(subject, object, "rwat"));
415     RUNNER_ASSERT(0 == smack_have_access(subject, object, "x"));
416
417     app_revoke_access(subject, object);
418
419     RUNNER_ASSERT(1 == smack_have_access(subject, object, "ra"));
420     RUNNER_ASSERT(0 == smack_have_access(subject, object, "w"));
421     RUNNER_ASSERT(0 == smack_have_access(subject, object, "x"));
422     RUNNER_ASSERT(0 == smack_have_access(subject, object, "t"));
423
424     RUNNER_ASSERT(0 == smack_accesses_add(smack.get(), subject, object, "-"));
425     RUNNER_ASSERT(0 == smack_accesses_apply(smack.get()));
426 }