18ac5aef8SEnji Cooper // Tests for POSIX message queue functionality.
28ac5aef8SEnji Cooper
38ac5aef8SEnji Cooper #include <time.h>
48ac5aef8SEnji Cooper #include <fcntl.h>
58ac5aef8SEnji Cooper #include <sys/stat.h>
68ac5aef8SEnji Cooper #include <mqueue.h>
78ac5aef8SEnji Cooper
88ac5aef8SEnji Cooper #include <string>
98ac5aef8SEnji Cooper
108ac5aef8SEnji Cooper #include "capsicum.h"
118ac5aef8SEnji Cooper #include "syscalls.h"
128ac5aef8SEnji Cooper #include "capsicum-test.h"
138ac5aef8SEnji Cooper
148ac5aef8SEnji Cooper // Run a test case in a forked process, possibly cleaning up a
158ac5aef8SEnji Cooper // message after completion
168ac5aef8SEnji Cooper #define FORK_TEST_ON_MQ(test_case_name, test_name, test_mq) \
178ac5aef8SEnji Cooper static void test_case_name##_##test_name##_ForkTest(); \
188ac5aef8SEnji Cooper TEST(test_case_name, test_name ## Forked) { \
198ac5aef8SEnji Cooper _RUN_FORKED_FN(test_case_name##_##test_name##_ForkTest, \
208ac5aef8SEnji Cooper #test_case_name, #test_name); \
218ac5aef8SEnji Cooper const char *mqname = test_mq; \
228ac5aef8SEnji Cooper if (mqname) mq_unlink_(mqname); \
238ac5aef8SEnji Cooper } \
248ac5aef8SEnji Cooper static void test_case_name##_##test_name##_ForkTest()
258ac5aef8SEnji Cooper
268ac5aef8SEnji Cooper static bool invoked;
seen_it_done_it(int)278ac5aef8SEnji Cooper void seen_it_done_it(int) {
288ac5aef8SEnji Cooper invoked = true;
298ac5aef8SEnji Cooper }
308ac5aef8SEnji Cooper
31*2d936e6cSAlex Richardson FORK_TEST_ON_MQ(PosixMqueue, CapModeIfMqOpenAvailable, "/cap_mq") {
328ac5aef8SEnji Cooper int mq = mq_open_("/cap_mq", O_RDWR|O_CREAT, 0644, NULL);
338ac5aef8SEnji Cooper // On FreeBSD, turn on message queue support with:
348ac5aef8SEnji Cooper // - 'kldload mqueuefs'
358ac5aef8SEnji Cooper // - 'options P1003_1B_MQUEUE' in kernel build config.
368ac5aef8SEnji Cooper if (mq < 0 && errno == ENOSYS) {
37*2d936e6cSAlex Richardson GTEST_SKIP() << "mq_open -> -ENOSYS";
388ac5aef8SEnji Cooper }
398ac5aef8SEnji Cooper EXPECT_OK(mq);
408ac5aef8SEnji Cooper cap_rights_t r_read;
418ac5aef8SEnji Cooper cap_rights_init(&r_read, CAP_READ);
428ac5aef8SEnji Cooper cap_rights_t r_write;
438ac5aef8SEnji Cooper cap_rights_init(&r_write, CAP_WRITE);
448ac5aef8SEnji Cooper cap_rights_t r_poll;
458ac5aef8SEnji Cooper cap_rights_init(&r_poll, CAP_EVENT);
468ac5aef8SEnji Cooper
478ac5aef8SEnji Cooper int cap_read_mq = dup(mq);
488ac5aef8SEnji Cooper EXPECT_OK(cap_read_mq);
498ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(cap_read_mq, &r_read));
508ac5aef8SEnji Cooper int cap_write_mq = dup(mq);
518ac5aef8SEnji Cooper EXPECT_OK(cap_write_mq);
528ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(cap_write_mq, &r_write));
538ac5aef8SEnji Cooper int cap_poll_mq = dup(mq);
548ac5aef8SEnji Cooper EXPECT_OK(cap_poll_mq);
558ac5aef8SEnji Cooper EXPECT_OK(cap_rights_limit(cap_poll_mq, &r_poll));
568ac5aef8SEnji Cooper EXPECT_OK(mq_close_(mq));
578ac5aef8SEnji Cooper
588ac5aef8SEnji Cooper signal(SIGUSR2, seen_it_done_it);
598ac5aef8SEnji Cooper
608ac5aef8SEnji Cooper EXPECT_OK(cap_enter()); // Enter capability mode
618ac5aef8SEnji Cooper
628ac5aef8SEnji Cooper // Can no longer access the message queue via the POSIX IPC namespace.
638ac5aef8SEnji Cooper EXPECT_CAPMODE(mq_open_("/cap_mw", O_RDWR|O_CREAT, 0644, NULL));
648ac5aef8SEnji Cooper
658ac5aef8SEnji Cooper struct sigevent se;
668ac5aef8SEnji Cooper se.sigev_notify = SIGEV_SIGNAL;
678ac5aef8SEnji Cooper se.sigev_signo = SIGUSR2;
688ac5aef8SEnji Cooper EXPECT_OK(mq_notify_(cap_poll_mq, &se));
698ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(mq_notify_(cap_read_mq, &se));
708ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(mq_notify_(cap_write_mq, &se));
718ac5aef8SEnji Cooper
728ac5aef8SEnji Cooper const unsigned int kPriority = 10;
738ac5aef8SEnji Cooper const char* message = "xyzzy";
748ac5aef8SEnji Cooper struct timespec ts;
758ac5aef8SEnji Cooper ts.tv_sec = 1;
768ac5aef8SEnji Cooper ts.tv_nsec = 0;
778ac5aef8SEnji Cooper EXPECT_OK(mq_timedsend_(cap_write_mq, message, strlen(message) + 1, kPriority, &ts));
788ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(mq_timedsend_(cap_read_mq, message, strlen(message) + 1, kPriority, &ts));
798ac5aef8SEnji Cooper
808ac5aef8SEnji Cooper sleep(1); // Give the notification a chance to arrive.
818ac5aef8SEnji Cooper EXPECT_TRUE(invoked);
828ac5aef8SEnji Cooper
838ac5aef8SEnji Cooper struct mq_attr mqa;
848ac5aef8SEnji Cooper EXPECT_OK(mq_getattr_(cap_poll_mq, &mqa));
858ac5aef8SEnji Cooper EXPECT_OK(mq_setattr_(cap_poll_mq, &mqa, NULL));
868ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(mq_getattr_(cap_write_mq, &mqa));
878ac5aef8SEnji Cooper
888ac5aef8SEnji Cooper char* buffer = (char *)malloc(mqa.mq_msgsize);
898ac5aef8SEnji Cooper unsigned int priority;
908ac5aef8SEnji Cooper EXPECT_NOTCAPABLE(mq_timedreceive_(cap_write_mq, buffer, mqa.mq_msgsize, &priority, &ts));
918ac5aef8SEnji Cooper EXPECT_OK(mq_timedreceive_(cap_read_mq, buffer, mqa.mq_msgsize, &priority, &ts));
928ac5aef8SEnji Cooper EXPECT_EQ(std::string(message), std::string(buffer));
938ac5aef8SEnji Cooper EXPECT_EQ(kPriority, priority);
948ac5aef8SEnji Cooper free(buffer);
958ac5aef8SEnji Cooper
968ac5aef8SEnji Cooper close(cap_read_mq);
978ac5aef8SEnji Cooper close(cap_write_mq);
988ac5aef8SEnji Cooper close(cap_poll_mq);
998ac5aef8SEnji Cooper }
100