xref: /src/tests/sys/capsicum/mqueue.cc (revision 670b568ec1c36464c6d55e400382c290b0391ccf)
1e5a5dd6cSEnji Cooper // Tests for POSIX message queue functionality.
2e5a5dd6cSEnji Cooper 
3e5a5dd6cSEnji Cooper #include <time.h>
4e5a5dd6cSEnji Cooper #include <fcntl.h>
5e5a5dd6cSEnji Cooper #include <sys/stat.h>
6e5a5dd6cSEnji Cooper #include <mqueue.h>
7e5a5dd6cSEnji Cooper 
8e5a5dd6cSEnji Cooper #include <string>
9e5a5dd6cSEnji Cooper 
10e5a5dd6cSEnji Cooper #include "capsicum.h"
11e5a5dd6cSEnji Cooper #include "syscalls.h"
12e5a5dd6cSEnji Cooper #include "capsicum-test.h"
13e5a5dd6cSEnji Cooper 
14e5a5dd6cSEnji Cooper // Run a test case in a forked process, possibly cleaning up a
15e5a5dd6cSEnji Cooper // message after completion
16e5a5dd6cSEnji Cooper #define FORK_TEST_ON_MQ(test_case_name, test_name, test_mq)    \
17e5a5dd6cSEnji Cooper     static void test_case_name##_##test_name##_ForkTest();     \
18e5a5dd6cSEnji Cooper     TEST(test_case_name, test_name ## Forked) {                \
19e5a5dd6cSEnji Cooper       _RUN_FORKED_FN(test_case_name##_##test_name##_ForkTest,  \
20e5a5dd6cSEnji Cooper                      #test_case_name, #test_name);             \
21e5a5dd6cSEnji Cooper       const char *mqname = test_mq;                            \
22e5a5dd6cSEnji Cooper       if (mqname) mq_unlink_(mqname);                          \
23e5a5dd6cSEnji Cooper     }                                                          \
24e5a5dd6cSEnji Cooper     static void test_case_name##_##test_name##_ForkTest()
25e5a5dd6cSEnji Cooper 
26e5a5dd6cSEnji Cooper static bool invoked;
seen_it_done_it(int)2733d7e3eeSEnji Cooper void seen_it_done_it(int) {
28e5a5dd6cSEnji Cooper   invoked = true;
29e5a5dd6cSEnji Cooper }
30e5a5dd6cSEnji Cooper 
31b6973c8fSAlex Richardson FORK_TEST_ON_MQ(PosixMqueue, CapModeIfMqOpenAvailable, "/cap_mq") {
32e5a5dd6cSEnji Cooper   int mq = mq_open_("/cap_mq", O_RDWR|O_CREAT, 0644, NULL);
33e5a5dd6cSEnji Cooper   // On FreeBSD, turn on message queue support with:
34e5a5dd6cSEnji Cooper   //  - 'kldload mqueuefs'
35e5a5dd6cSEnji Cooper   //  - 'options P1003_1B_MQUEUE' in kernel build config.
36e5a5dd6cSEnji Cooper   if (mq < 0 && errno == ENOSYS) {
37b6973c8fSAlex Richardson     GTEST_SKIP() << "mq_open -> -ENOSYS";
38e5a5dd6cSEnji Cooper   }
39e5a5dd6cSEnji Cooper   EXPECT_OK(mq);
40e5a5dd6cSEnji Cooper   cap_rights_t r_read;
41e5a5dd6cSEnji Cooper   cap_rights_init(&r_read, CAP_READ);
42e5a5dd6cSEnji Cooper   cap_rights_t r_write;
43e5a5dd6cSEnji Cooper   cap_rights_init(&r_write, CAP_WRITE);
44e5a5dd6cSEnji Cooper   cap_rights_t r_poll;
45e5a5dd6cSEnji Cooper   cap_rights_init(&r_poll, CAP_EVENT);
46e5a5dd6cSEnji Cooper 
47e5a5dd6cSEnji Cooper   int cap_read_mq = dup(mq);
48e5a5dd6cSEnji Cooper   EXPECT_OK(cap_read_mq);
49e5a5dd6cSEnji Cooper   EXPECT_OK(cap_rights_limit(cap_read_mq, &r_read));
50e5a5dd6cSEnji Cooper   int cap_write_mq = dup(mq);
51e5a5dd6cSEnji Cooper   EXPECT_OK(cap_write_mq);
52e5a5dd6cSEnji Cooper   EXPECT_OK(cap_rights_limit(cap_write_mq, &r_write));
53e5a5dd6cSEnji Cooper   int cap_poll_mq = dup(mq);
54e5a5dd6cSEnji Cooper   EXPECT_OK(cap_poll_mq);
55e5a5dd6cSEnji Cooper   EXPECT_OK(cap_rights_limit(cap_poll_mq, &r_poll));
56e5a5dd6cSEnji Cooper   EXPECT_OK(mq_close_(mq));
57e5a5dd6cSEnji Cooper 
58e5a5dd6cSEnji Cooper   signal(SIGUSR2, seen_it_done_it);
59e5a5dd6cSEnji Cooper 
60e5a5dd6cSEnji Cooper   EXPECT_OK(cap_enter());  // Enter capability mode
61e5a5dd6cSEnji Cooper 
62e5a5dd6cSEnji Cooper   // Can no longer access the message queue via the POSIX IPC namespace.
63e5a5dd6cSEnji Cooper   EXPECT_CAPMODE(mq_open_("/cap_mw", O_RDWR|O_CREAT, 0644, NULL));
64e5a5dd6cSEnji Cooper 
65e5a5dd6cSEnji Cooper   struct sigevent se;
66e5a5dd6cSEnji Cooper   se.sigev_notify = SIGEV_SIGNAL;
67e5a5dd6cSEnji Cooper   se.sigev_signo = SIGUSR2;
68e5a5dd6cSEnji Cooper   EXPECT_OK(mq_notify_(cap_poll_mq, &se));
69e5a5dd6cSEnji Cooper   EXPECT_NOTCAPABLE(mq_notify_(cap_read_mq, &se));
70e5a5dd6cSEnji Cooper   EXPECT_NOTCAPABLE(mq_notify_(cap_write_mq, &se));
71e5a5dd6cSEnji Cooper 
72e5a5dd6cSEnji Cooper   const unsigned int kPriority = 10;
73e5a5dd6cSEnji Cooper   const char* message = "xyzzy";
74e5a5dd6cSEnji Cooper   struct timespec ts;
75e5a5dd6cSEnji Cooper   ts.tv_sec = 1;
76e5a5dd6cSEnji Cooper   ts.tv_nsec = 0;
77e5a5dd6cSEnji Cooper   EXPECT_OK(mq_timedsend_(cap_write_mq, message, strlen(message) + 1, kPriority, &ts));
78e5a5dd6cSEnji Cooper   EXPECT_NOTCAPABLE(mq_timedsend_(cap_read_mq, message, strlen(message) + 1, kPriority, &ts));
79e5a5dd6cSEnji Cooper 
80e5a5dd6cSEnji Cooper   sleep(1);  // Give the notification a chance to arrive.
81e5a5dd6cSEnji Cooper   EXPECT_TRUE(invoked);
82e5a5dd6cSEnji Cooper 
83e5a5dd6cSEnji Cooper   struct mq_attr mqa;
84e5a5dd6cSEnji Cooper   EXPECT_OK(mq_getattr_(cap_poll_mq, &mqa));
85e5a5dd6cSEnji Cooper   EXPECT_OK(mq_setattr_(cap_poll_mq, &mqa, NULL));
86e5a5dd6cSEnji Cooper   EXPECT_NOTCAPABLE(mq_getattr_(cap_write_mq, &mqa));
87e5a5dd6cSEnji Cooper 
88e5a5dd6cSEnji Cooper   char* buffer = (char *)malloc(mqa.mq_msgsize);
89e5a5dd6cSEnji Cooper   unsigned int priority;
90e5a5dd6cSEnji Cooper   EXPECT_NOTCAPABLE(mq_timedreceive_(cap_write_mq, buffer, mqa.mq_msgsize, &priority, &ts));
91e5a5dd6cSEnji Cooper   EXPECT_OK(mq_timedreceive_(cap_read_mq, buffer, mqa.mq_msgsize, &priority, &ts));
92e5a5dd6cSEnji Cooper   EXPECT_EQ(std::string(message), std::string(buffer));
93e5a5dd6cSEnji Cooper   EXPECT_EQ(kPriority, priority);
94e5a5dd6cSEnji Cooper   free(buffer);
95e5a5dd6cSEnji Cooper 
96e5a5dd6cSEnji Cooper   close(cap_read_mq);
97e5a5dd6cSEnji Cooper   close(cap_write_mq);
98e5a5dd6cSEnji Cooper   close(cap_poll_mq);
99e5a5dd6cSEnji Cooper }
100