2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
5 * @file security_server_tests_client_smack.cpp
6 * @author Bartlomiej Grzelewski (b.grzelewski@samsung.com)
8 * @brief Test cases for security-server-client-smack.
12 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/smack.h>
24 #include <dpl/log/log.h>
25 #include <dpl/test/test_runner.h>
26 #include <dpl/test/test_runner_child.h>
27 #include "security_server_mockup.h"
29 #include <security-server.h>
31 #include "tests_common.h"
35 const char *subject_label = "mylabel"; \
36 RUNNER_ASSERT_MSG(-1 != system("touch /opt/home/root/pid_cycle"), \
37 "Cannot prepare environment for test."); \
38 RUNNER_ASSERT_MSG(0 == smack_set_label_for_self(subject_label), \
39 "Cannot prepare environment for test."); \
40 RUNNER_ASSERT_MSG(-1 != setgid(1), \
41 "Cannot prepare environment for test."); \
42 RUNNER_ASSERT_MSG(-1 != setuid(1), \
43 "Cannot prepare environment for test"); \
48 * Environment preparation should only differ in setting label. On NOSMACK system
49 * smack_set_label_for_self returns error because of no access to /proc/self/attr/current.
51 #define ENVIRONMENT_NOSMACK \
53 int fd = open("/opt/home/root/pid_cycle", O_CREAT|O_APPEND, 0444);\
54 RUNNER_ASSERT_MSG(fd >= 0, \
55 "Couldn't create pid_cycle file. errno: " << strerror(errno));\
57 RUNNER_ASSERT_MSG(-1 != setgid(1), \
58 "Cannot prepare environment for test."); \
59 RUNNER_ASSERT_MSG(-1 != setuid(1), \
60 "Cannot prepare environment for test"); \
64 * Unique_ptr typedef for NOSMACK version of tc06 test
66 void closesockfdptr(int* sockfd_ptr)
70 typedef std::unique_ptr<int, std::function<void(int*)> > SockFDUniquePtr;
73 * Dropping root privileges
74 * returns 0 on success, 1 on error
76 int drop_root_privileges()
79 /* process is running as root, drop privileges */
80 if (setgid(5000) != 0)
82 if (setuid(5000) != 0)
92 RUNNER_TEST_GROUP_INIT(SECURITY_SERVER_TESTS_CLIENT_SMACK)
95 * test: Check cookie size returned by security_server_get_cookie_size.
96 * description: Cookie used by security-server is 20 bytes long.
97 * Any other size of cookies should be treated as error.
98 * expected: Function security_server_get_cookie_size returns 20.
100 RUNNER_CHILD_TEST_SMACK(tc01_security_server_get_cookie_size)
104 int ret = security_server_get_cookie_size();
105 RUNNER_ASSERT_MSG(20 == ret, "ret = " << ret);
109 * test: security_server_request_cookie
110 * description: Function security_server_request_cookie will return
111 * 20 bytes long cookie.
112 * expected: function will set up cookie in the array and return
113 * SECURITY_SERVER_API_SUCCESS.
115 RUNNER_CHILD_TEST_SMACK(tc02_security_server_request_cookie_normal_case)
120 int ret = security_server_request_cookie(cookie, 20);
121 LogDebug("ret = " << ret);
122 RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS == ret);
126 * test: security_server_request_cookie
127 * description: Function security_server_request_cookie will return
128 * 20 bytes long cookie.
129 * expected: function will set up cookie in the array and return
130 * SECURITY_SERVER_API_SUCCESS.
132 RUNNER_CHILD_TEST_SMACK(tc03_security_server_request_cookie_too_small_buffer_size)
137 int ret = security_server_request_cookie(cookie, 10);
138 LogDebug("ret = " << ret);
139 RUNNER_ASSERT(SECURITY_SERVER_API_ERROR_BUFFER_TOO_SMALL == ret);
143 * test: tc04_security_server_get_gid
144 * description: Checking for security_server_get_gid
145 * with nonexisting gid and existing one
146 * expected: security_server_get_gid should return
147 * SECURITY_SERVER_ERROR_NO_SUCH_OBJECT with first call
148 * and group id with second call
150 RUNNER_CHILD_TEST_SMACK(tc04_security_server_get_gid)
154 int ret = security_server_get_gid("abc123xyz_pysiaczek");
155 LogDebug("ret = " << ret);
156 RUNNER_ASSERT_MSG(SECURITY_SERVER_API_ERROR_NO_SUCH_OBJECT == ret, "Ret: " << ret);
157 ret = security_server_get_gid("root");
158 LogDebug("ret = " << ret);
159 RUNNER_ASSERT_MSG(0 == ret, "Ret: " << ret);
163 * test: tc05_check_privilege_by_cookie
164 * description: Function security_server_check_privilege_by_cookie should
165 * return status of access rights of cookie owner. In this case cookie owner
166 * is the same process that ask for the rights.
167 * expected: Function call with access rights set to "r" should return SUCCESS,
168 * with "rw" should return ACCESS DENIED.
170 RUNNER_CHILD_TEST_SMACK(tc05_check_privilege_by_cookie)
173 const char *object_label = "tc05objectlabel";
174 const char *access_rights = "r";
175 const char *access_rights_ext = "rw";
176 const char *subject_label = "tc05subjectlabel";
178 smack_accesses *handle;
180 RUNNER_ASSERT(0 == smack_accesses_new(&handle));
182 RUNNER_ASSERT(0 == smack_accesses_add(handle,
187 RUNNER_ASSERT(0 == smack_accesses_apply(handle));
189 smack_accesses_free(handle);
191 RUNNER_ASSERT(0 == smack_set_label_for_self(subject_label));
193 RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS ==
194 security_server_request_cookie(cookie,20));
196 RUNNER_ASSERT_MSG(drop_root_privileges() == 0, "uid = " << getuid());
198 RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS ==
199 security_server_check_privilege_by_cookie(
204 RUNNER_ASSERT(SECURITY_SERVER_API_ERROR_ACCESS_DENIED ==
205 security_server_check_privilege_by_cookie(
212 * test: security_server_check_privilege_by_sockfd
213 * description: This test will create dummy server that will accept connection
214 * and die. The client will try to check access rights using connection descriptor.
215 * expected: Function call with access rights set to "r" should return SUCCESS,
216 * with "rw" should return ACCESS DENIED.
218 RUNNER_TEST_SMACK(tc06_check_privilege_by_sockfd)
220 const char *object_label = "tc06objectlabel";
221 const char *access_rights = "r";
222 const char *access_rights_ext = "rw";
223 const char *subject_label = "tc06subjectlabel";
228 smack_accesses *handle;
229 RUNNER_ASSERT(0 == smack_accesses_new(&handle));
230 RUNNER_ASSERT(0 == smack_accesses_add(handle,
234 RUNNER_ASSERT(0 == smack_accesses_apply(handle));
235 smack_accesses_free(handle);
239 RUNNER_ASSERT(-1 != pid);
243 if (0 != smack_set_label_for_self(subject_label)) {
244 LogDebug("child, failed");
248 LogDebug("child, create_new_socket");
249 int sockfd = create_new_socket();
252 label = security_server_get_smacklabel_sockfd(sockfd);
253 RUNNER_ASSERT_MSG(label != NULL, "security_server_get_smacklabel_sockfd failed");
254 RUNNER_ASSERT_MSG(strcmp(label,"") == 0, "label is \"" << label << "\"");
257 RUNNER_ASSERT_MSG(drop_root_privileges() == 0, "uid = " << getuid());
259 LogDebug("child, listen");
260 if (listen(sockfd, 5) < 0) {
261 LogDebug("child, exit");
265 label = security_server_get_smacklabel_sockfd(sockfd);
266 RUNNER_ASSERT_MSG(label != NULL, "security_server_get_smacklabel_sockfd failed");
267 RUNNER_ASSERT_MSG(strcmp(label,"") == 0, "label is \"" << label << "\"");
271 LogDebug("child, accept");
272 struct sockaddr_un client_addr;
273 socklen_t client_len = sizeof(client_addr);
275 while (0 <= (csockfd = accept(sockfd,(struct sockaddr*)&client_addr, &client_len))) {
276 LogDebug("child, loop");
281 label = security_server_get_smacklabel_sockfd(sockfd);
282 RUNNER_ASSERT_MSG(label != NULL, "security_server_get_smacklabel_sockfd failed");
283 RUNNER_ASSERT_MSG(strcmp(label,subject_label) == 0, "label is \"" << label << "\"" << "subject_label is \"" << subject_label << "\"" );
290 LogDebug("Parent, sleep 2");
292 int sockfd = connect_to_testserver();
294 label = security_server_get_smacklabel_sockfd(sockfd);
295 RUNNER_ASSERT_MSG(label != NULL, "security_server_get_smacklabel_sockfd failed");
296 RUNNER_ASSERT_MSG(strcmp(label,subject_label) == 0, "label is \"" << label << "\"" << "subject_label is \"" << subject_label << "\"" );
299 LogDebug("Parent: sockfd: " << sockfd);
301 result1 = security_server_check_privilege_by_sockfd(
305 result2 = security_server_check_privilege_by_sockfd(
310 LogDebug("Parent: Close desc");
312 LogDebug("Parent: killing child");
317 waitpid(pid, &status, 0);
319 RUNNER_ASSERT_MSG(SECURITY_SERVER_API_SUCCESS == result1, "result = " << result1);
320 RUNNER_ASSERT_MSG(SECURITY_SERVER_API_ERROR_ACCESS_DENIED == result2, "result = " << result2);
324 * test: security_server_check_privilege_by_sockfd
325 * description: This test will create dummy server that will accept connection
326 * and die. The client will try to check access rights using connection descriptor.
327 * Because we read a smack label not from socket directly, but from from pid of process
328 * on the other end of socket - that's why smack label will be updated.
329 * In this test client is running under root and server is not - to test the extreme case.
330 * expected: Function call with access rights set to "r" should return SUCCESS,
331 * with "rw" should return ACCESS DENIED.
333 RUNNER_TEST_SMACK(tc07_check_privilege_by_sockfd)
335 const char *object_label = "tc07objectlabel";
336 const char *access_rights = "r";
337 const char *access_rights_ext = "rw";
338 const char *subject_label = "tc07subjectlabel";
342 int kill_result = -1;
344 smack_accesses *handle;
345 RUNNER_ASSERT(0 == smack_accesses_new(&handle));
346 RUNNER_ASSERT(0 == smack_accesses_add(handle,
350 RUNNER_ASSERT(0 == smack_accesses_apply(handle));
351 smack_accesses_free(handle);
354 RUNNER_ASSERT(-1 != pid);
358 LogDebug("child, create_new_socket");
359 int sockfd = create_new_socket();
361 if (0 != smack_set_label_for_self(subject_label)) {
362 LogDebug("child, failed");
366 RUNNER_ASSERT_MSG(drop_root_privileges() == 0, "uid = " << getuid());
368 LogDebug("child, listen");
369 if (listen(sockfd, 5) < 0) {
370 LogDebug("child, exit");
373 LogDebug("child, accept");
375 struct sockaddr_un client_addr;
376 socklen_t client_len = sizeof(client_addr);
378 while (0 <= (csockfd = accept(sockfd,(struct sockaddr*)&client_addr, &client_len))) {
379 LogDebug("child, loop");
387 RUNNER_ASSERT_MSG(drop_root_privileges() == 0, "uid = " << getuid());
389 LogDebug("Parent, sleep 2");
391 int sockfd = connect_to_testserver();
392 LogDebug("Parent: sockfd: " << sockfd);
394 result1 = security_server_check_privilege_by_sockfd(
398 result2 = security_server_check_privilege_by_sockfd(
403 LogDebug("Parent: Close desc");
405 LogDebug("Parent: killing child");
406 // we cannot kill child - because of dropping privileges
407 kill_result = kill(pid, SIGKILL);
410 if (kill_result == 0) {
412 waitpid(pid, &status, 0);
417 RUNNER_ASSERT_MSG(SECURITY_SERVER_API_SUCCESS == result1, "result1 = " << result1);
418 RUNNER_ASSERT_MSG(SECURITY_SERVER_API_ERROR_ACCESS_DENIED == result2, " result2 = " << result2);
421 ///////////////////////////
422 /////NOSMACK ENV TESTS/////
423 ///////////////////////////
426 * First four test cases are the same as their SMACK versions. The only difference is environment
427 * preparation (described near ENVIRONMENT_NOSMACK macro).
429 RUNNER_CHILD_TEST_NOSMACK(tc01_security_server_get_cookie_size_nosmack)
433 int ret = security_server_get_cookie_size();
434 RUNNER_ASSERT_MSG(ret == 20, "ret = " << ret);
437 RUNNER_CHILD_TEST_NOSMACK(tc02_security_server_request_cookie_normal_case_nosmack)
442 int ret = security_server_request_cookie(cookie, 20);
443 RUNNER_ASSERT_MSG(ret == SECURITY_SERVER_API_SUCCESS, "ret = " << ret);
446 RUNNER_CHILD_TEST_NOSMACK(tc03_security_server_request_cookie_too_small_buffer_size_nosmack)
451 int ret = security_server_request_cookie(cookie, 10);
452 RUNNER_ASSERT_MSG(ret == SECURITY_SERVER_API_ERROR_BUFFER_TOO_SMALL, "ret = " << ret);
455 RUNNER_CHILD_TEST_NOSMACK(tc04_security_server_get_gid_nosmack)
459 int ret = security_server_get_gid("definitely_not_existing_object");
460 RUNNER_ASSERT_MSG(ret == SECURITY_SERVER_API_ERROR_NO_SUCH_OBJECT, "ret = " << ret);
461 ret = security_server_get_gid("root");
462 RUNNER_ASSERT_MSG(ret == 0, "ret = " << ret);
466 * NOSMACK version of tc05 test.
468 * Correct behaviour of smack_accesses_apply and smack_set_label_for_self was checked by libsmack
469 * tests. We assume, that those tests pass. Additionally security_server_check_privilege_by_cookie
470 * should return SUCCESS no matter what access_rights we give to this function.
472 RUNNER_CHILD_TEST_NOSMACK(tc05_check_privilege_by_cookie_nosmack)
475 const char* object_label = "tc05objectlabel";
477 RUNNER_ASSERT(security_server_request_cookie(cookie,20) == SECURITY_SERVER_API_SUCCESS);
479 RUNNER_ASSERT_MSG(drop_root_privileges() == 0, "uid = " << getuid());
481 RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS ==
482 security_server_check_privilege_by_cookie(cookie, object_label, "r"));
484 //On NOSMACK env security server should return success on any accesses, even those that are
486 RUNNER_ASSERT(SECURITY_SERVER_API_SUCCESS ==
487 security_server_check_privilege_by_cookie(cookie, object_label, "rw"));
491 * NOSMACK version of tc06 test.
493 * Differences between this and SMACK version (server):
494 * - Skipped setting access_rights
495 * - Skipped setting label for server
496 * - get_smacklabel_sockfd is called only once for server, almost right after fork and creation
497 * of socket (because it should do nothing when SMACK is off)
498 * - After get_smacklabel_sockfd privileges are dropped and server is prepared to accept connections
501 * For client the only difference are expected results from check_privilege_by_sockfd - both should
504 RUNNER_TEST_NOSMACK(tc06_check_privilege_by_sockfd_nosmack)
506 const char* object_label = "tc06objectlabel";
513 RUNNER_ASSERT(pid >= 0);
515 if (pid == 0) { //child process - server
518 int sockfd = create_new_socket();
520 exit(1); //failed to create server; return 1
522 SockFDUniquePtr sockfd_ptr(&sockfd, closesockfdptr);
524 //check if get_smacklabel_sockfd works correctly
525 label = security_server_get_smacklabel_sockfd(sockfd);
527 exit(2); //label is NULL, get_smacklabel_sockfd failed; return 2
529 ret = strcmp(label, "");
532 exit(3); //label is not an empty string; return 3
534 ret = drop_root_privileges();
536 exit(4); //failed to drop root privileges; return 4
538 if (listen(sockfd, 5) < 0)
539 exit(5); //listen failed; return 5
541 struct sockaddr_un client_addr;
542 socklen_t client_len = sizeof(client_addr);
545 if((csockfd = accept(sockfd,(struct sockaddr*)&client_addr, &client_len)) <= 0)
546 exit(6); //accept failed; return 6
548 //wait a little bit for parent to do it's job
551 //if everything works, cleanup and return 0
558 int sockfd = connect_to_testserver();
559 RUNNER_ASSERT_MSG(sockfd >= 0, "Failed to connect to server.");
561 SockFDUniquePtr sockfd_ptr(&sockfd, closesockfdptr);
563 label = security_server_get_smacklabel_sockfd(sockfd);
564 RUNNER_ASSERT_MSG(label != NULL, "get_smacklabel_sockfd failed.");
566 ret = strcmp(label, "");
568 RUNNER_ASSERT_MSG(ret == 0, "label is \"" << label << "\", should be empty");
570 result1 = security_server_check_privilege_by_sockfd(sockfd, object_label, "r");
571 result2 = security_server_check_privilege_by_sockfd(sockfd, object_label, "rw");
577 waitpid(pid, &status, 0);
579 //check how our child process returned
580 switch(WEXITSTATUS(status))
582 case 1: RUNNER_ASSERT_MSG(false, "Child failed to create server.");
583 case 2: RUNNER_ASSERT_MSG(false, "Child error - get_smacklabel_sockfd failed.");
584 case 3: RUNNER_ASSERT_MSG(false, "Child error - label is not an empty string.");
585 case 4: RUNNER_ASSERT_MSG(false, "Child failed to drop root privileges.");
586 case 5: RUNNER_ASSERT_MSG(false, "Child error - listen failed.");
587 case 6: RUNNER_ASSERT_MSG(false, "Child error - accept failed.");
591 RUNNER_ASSERT_MSG(result1 == SECURITY_SERVER_API_SUCCESS, "result = " << result1);
592 RUNNER_ASSERT_MSG(result2 == SECURITY_SERVER_API_SUCCESS, "result = " << result2);
596 * NOSMACK version of tc07 test.
598 RUNNER_TEST_NOSMACK(tc07_check_privilege_by_sockfd_nosmack)
600 const char* object_label = "tc07objectlabel";
606 RUNNER_ASSERT(-1 != pid);
608 if (pid == 0) { //child process
611 int sockfd = create_new_socket();
613 exit(1); //failed to create server, return 1
615 SockFDUniquePtr sockfd_ptr(&sockfd, closesockfdptr);
618 ret = drop_root_privileges();
620 exit(2); //failed to drop root privileges; return 2
622 //Prepare for accepting
623 if (listen(sockfd, 5) < 0)
624 exit(3); //listen failed; return 3
626 struct sockaddr_un client_addr;
627 socklen_t client_len = sizeof(client_addr);
631 if((csockfd = accept(sockfd,(struct sockaddr*)&client_addr, &client_len)) <= 0)
632 exit(4); //accept failed; return 4
634 //wait a little bit for parent to do it's job
637 //cleanup and kill child
640 } else { //parent process
641 //Drop root privileges
642 int ret = drop_root_privileges();
643 RUNNER_ASSERT_MSG(ret == 0,
644 "Failed to drop root privileges. Result: " << ret << ", uid = " << getuid());
646 //Wait for server to set up
649 //Connect and check privileges
650 int sockfd = connect_to_testserver();
651 RUNNER_ASSERT_MSG(sockfd >= 0, "Failed to create socket fd.");
653 result1 = security_server_check_privilege_by_sockfd(sockfd, object_label, "r");
654 result2 = security_server_check_privilege_by_sockfd(sockfd, object_label, "rw");
661 waitpid(pid, &status, 0);
663 switch(WEXITSTATUS(status))
665 case 1: RUNNER_ASSERT_MSG(false, "Child failed to create server.");
666 case 2: RUNNER_ASSERT_MSG(false, "Child failed to drop root privileges.");
667 case 3: RUNNER_ASSERT_MSG(false, "Child failed to listen to sockfd.");
668 case 4: RUNNER_ASSERT_MSG(false, "Child failed to accept connection from server.");
672 //Both results (just like in the previous test case) should return success.
673 RUNNER_ASSERT_MSG(SECURITY_SERVER_API_SUCCESS == result1, "result1 = " << result1);
674 RUNNER_ASSERT_MSG(SECURITY_SERVER_API_SUCCESS == result2, "result2 = " << result2);
681 int main(int argc, char *argv[])
684 DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);