0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include <stdio.h>
0023 #include <stdlib.h>
0024 #include <unistd.h>
0025 #include <fcntl.h>
0026 #include <string.h>
0027 #include <limits.h>
0028 #include <errno.h>
0029 #include <sys/types.h>
0030 #include <sys/time.h>
0031 #include <sys/resource.h>
0032 #include <sys/stat.h>
0033 #include <mqueue.h>
0034 #include <error.h>
0035
0036 #include "../kselftest.h"
0037
0038 static char *usage =
0039 "Usage:\n"
0040 " %s path\n"
0041 "\n"
0042 " path Path name of the message queue to create\n"
0043 "\n"
0044 " Note: this program must be run as root in order to enable all tests\n"
0045 "\n";
0046
0047 char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
0048 char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
0049 char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
0050 char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
0051
0052 int default_settings;
0053 struct rlimit saved_limits, cur_limits;
0054 int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
0055 int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
0056 FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
0057 char *queue_path;
0058 char *default_queue_path = "/test1";
0059 mqd_t queue = -1;
0060
0061 static inline void __set(FILE *stream, int value, char *err_msg);
0062 void shutdown(int exit_val, char *err_cause, int line_no);
0063 static inline int get(FILE *stream);
0064 static inline void set(FILE *stream, int value);
0065 static inline void getr(int type, struct rlimit *rlim);
0066 static inline void setr(int type, struct rlimit *rlim);
0067 void validate_current_settings();
0068 static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
0069 static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
0070
0071 static inline void __set(FILE *stream, int value, char *err_msg)
0072 {
0073 rewind(stream);
0074 if (fprintf(stream, "%d", value) < 0)
0075 perror(err_msg);
0076 }
0077
0078
0079 void shutdown(int exit_val, char *err_cause, int line_no)
0080 {
0081 static int in_shutdown = 0;
0082
0083
0084 if (in_shutdown++)
0085 return;
0086
0087 if (seteuid(0) == -1)
0088 perror("seteuid() failed");
0089
0090 if (queue != -1)
0091 if (mq_close(queue))
0092 perror("mq_close() during shutdown");
0093 if (queue_path)
0094
0095
0096
0097
0098 mq_unlink(queue_path);
0099 if (default_settings) {
0100 if (saved_def_msgs)
0101 __set(def_msgs, saved_def_msgs,
0102 "failed to restore saved_def_msgs");
0103 if (saved_def_msgsize)
0104 __set(def_msgsize, saved_def_msgsize,
0105 "failed to restore saved_def_msgsize");
0106 }
0107 if (saved_max_msgs)
0108 __set(max_msgs, saved_max_msgs,
0109 "failed to restore saved_max_msgs");
0110 if (saved_max_msgsize)
0111 __set(max_msgsize, saved_max_msgsize,
0112 "failed to restore saved_max_msgsize");
0113 if (exit_val)
0114 error(exit_val, errno, "%s at %d", err_cause, line_no);
0115 exit(0);
0116 }
0117
0118 static inline int get(FILE *stream)
0119 {
0120 int value;
0121 rewind(stream);
0122 if (fscanf(stream, "%d", &value) != 1)
0123 shutdown(4, "Error reading /proc entry", __LINE__ - 1);
0124 return value;
0125 }
0126
0127 static inline void set(FILE *stream, int value)
0128 {
0129 int new_value;
0130
0131 rewind(stream);
0132 if (fprintf(stream, "%d", value) < 0)
0133 return shutdown(5, "Failed writing to /proc file",
0134 __LINE__ - 1);
0135 new_value = get(stream);
0136 if (new_value != value)
0137 return shutdown(5, "We didn't get what we wrote to /proc back",
0138 __LINE__ - 1);
0139 }
0140
0141 static inline void getr(int type, struct rlimit *rlim)
0142 {
0143 if (getrlimit(type, rlim))
0144 shutdown(6, "getrlimit()", __LINE__ - 1);
0145 }
0146
0147 static inline void setr(int type, struct rlimit *rlim)
0148 {
0149 if (setrlimit(type, rlim))
0150 shutdown(7, "setrlimit()", __LINE__ - 1);
0151 }
0152
0153 void validate_current_settings()
0154 {
0155 int rlim_needed;
0156
0157 if (cur_limits.rlim_cur < 4096) {
0158 printf("Current rlimit value for POSIX message queue bytes is "
0159 "unreasonably low,\nincreasing.\n\n");
0160 cur_limits.rlim_cur = 8192;
0161 cur_limits.rlim_max = 16384;
0162 setr(RLIMIT_MSGQUEUE, &cur_limits);
0163 }
0164
0165 if (default_settings) {
0166 rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
0167 2 * sizeof(void *));
0168 if (rlim_needed > cur_limits.rlim_cur) {
0169 printf("Temporarily lowering default queue parameters "
0170 "to something that will work\n"
0171 "with the current rlimit values.\n\n");
0172 set(def_msgs, 10);
0173 cur_def_msgs = 10;
0174 set(def_msgsize, 128);
0175 cur_def_msgsize = 128;
0176 }
0177 } else {
0178 rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
0179 2 * sizeof(void *));
0180 if (rlim_needed > cur_limits.rlim_cur) {
0181 printf("Temporarily lowering maximum queue parameters "
0182 "to something that will work\n"
0183 "with the current rlimit values in case this is "
0184 "a kernel that ties the default\n"
0185 "queue parameters to the maximum queue "
0186 "parameters.\n\n");
0187 set(max_msgs, 10);
0188 cur_max_msgs = 10;
0189 set(max_msgsize, 128);
0190 cur_max_msgsize = 128;
0191 }
0192 }
0193 }
0194
0195
0196
0197
0198
0199
0200 static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
0201 {
0202 int flags = O_RDWR | O_EXCL | O_CREAT;
0203 int perms = DEFFILEMODE;
0204
0205 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
0206 shutdown(1, "mq_open()", __LINE__);
0207 if (mq_getattr(queue, result))
0208 shutdown(1, "mq_getattr()", __LINE__);
0209 if (mq_close(queue))
0210 shutdown(1, "mq_close()", __LINE__);
0211 queue = -1;
0212 if (mq_unlink(queue_path))
0213 shutdown(1, "mq_unlink()", __LINE__);
0214 }
0215
0216
0217
0218
0219
0220
0221
0222 static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
0223 {
0224 int flags = O_RDWR | O_EXCL | O_CREAT;
0225 int perms = DEFFILEMODE;
0226
0227 if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
0228 return 0;
0229 if (mq_getattr(queue, result))
0230 shutdown(1, "mq_getattr()", __LINE__);
0231 if (mq_close(queue))
0232 shutdown(1, "mq_close()", __LINE__);
0233 queue = -1;
0234 if (mq_unlink(queue_path))
0235 shutdown(1, "mq_unlink()", __LINE__);
0236 return 1;
0237 }
0238
0239 int main(int argc, char *argv[])
0240 {
0241 struct mq_attr attr, result;
0242
0243 if (argc != 2) {
0244 printf("Using Default queue path - %s\n", default_queue_path);
0245 queue_path = default_queue_path;
0246 } else {
0247
0248
0249
0250
0251
0252
0253 if (*argv[1] == '/')
0254 queue_path = strdup(argv[1]);
0255 else {
0256 queue_path = malloc(strlen(argv[1]) + 2);
0257 if (!queue_path) {
0258 perror("malloc()");
0259 exit(1);
0260 }
0261 queue_path[0] = '/';
0262 queue_path[1] = 0;
0263 strcat(queue_path, argv[1]);
0264 }
0265 }
0266
0267 if (getuid() != 0)
0268 ksft_exit_skip("Not running as root, but almost all tests "
0269 "require root in order to modify\nsystem settings. "
0270 "Exiting.\n");
0271
0272
0273 def_msgs = fopen(DEF_MSGS, "r+");
0274 def_msgsize = fopen(DEF_MSGSIZE, "r+");
0275 max_msgs = fopen(MAX_MSGS, "r+");
0276 max_msgsize = fopen(MAX_MSGSIZE, "r+");
0277
0278 if (!max_msgs)
0279 shutdown(2, "Failed to open msg_max", __LINE__);
0280 if (!max_msgsize)
0281 shutdown(2, "Failed to open msgsize_max", __LINE__);
0282 if (def_msgs || def_msgsize)
0283 default_settings = 1;
0284
0285
0286 getr(RLIMIT_MSGQUEUE, &saved_limits);
0287 cur_limits = saved_limits;
0288 if (default_settings) {
0289 saved_def_msgs = cur_def_msgs = get(def_msgs);
0290 saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
0291 }
0292 saved_max_msgs = cur_max_msgs = get(max_msgs);
0293 saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
0294
0295
0296 printf("\nInitial system state:\n");
0297 printf("\tUsing queue path:\t\t%s\n", queue_path);
0298 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
0299 (long) saved_limits.rlim_cur);
0300 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
0301 (long) saved_limits.rlim_max);
0302 printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
0303 printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
0304 if (default_settings) {
0305 printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
0306 printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
0307 } else {
0308 printf("\tDefault Message Size:\t\tNot Supported\n");
0309 printf("\tDefault Queue Size:\t\tNot Supported\n");
0310 }
0311 printf("\n");
0312
0313 validate_current_settings();
0314
0315 printf("Adjusted system state for testing:\n");
0316 printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
0317 printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
0318 printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
0319 printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
0320 if (default_settings) {
0321 printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
0322 printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
0323 }
0324
0325 printf("\n\nTest series 1, behavior when no attr struct "
0326 "passed to mq_open:\n");
0327 if (!default_settings) {
0328 test_queue(NULL, &result);
0329 printf("Given sane system settings, mq_open without an attr "
0330 "struct succeeds:\tPASS\n");
0331 if (result.mq_maxmsg != cur_max_msgs ||
0332 result.mq_msgsize != cur_max_msgsize) {
0333 printf("Kernel does not support setting the default "
0334 "mq attributes,\nbut also doesn't tie the "
0335 "defaults to the maximums:\t\t\tPASS\n");
0336 } else {
0337 set(max_msgs, ++cur_max_msgs);
0338 set(max_msgsize, ++cur_max_msgsize);
0339 test_queue(NULL, &result);
0340 if (result.mq_maxmsg == cur_max_msgs &&
0341 result.mq_msgsize == cur_max_msgsize)
0342 printf("Kernel does not support setting the "
0343 "default mq attributes and\n"
0344 "also ties system wide defaults to "
0345 "the system wide maximums:\t\t"
0346 "FAIL\n");
0347 else
0348 printf("Kernel does not support setting the "
0349 "default mq attributes,\n"
0350 "but also doesn't tie the defaults to "
0351 "the maximums:\t\t\tPASS\n");
0352 }
0353 } else {
0354 printf("Kernel supports setting defaults separately from "
0355 "maximums:\t\tPASS\n");
0356
0357
0358
0359
0360 test_queue(NULL, &result);
0361 printf("Given sane values, mq_open without an attr struct "
0362 "succeeds:\t\tPASS\n");
0363 if (result.mq_maxmsg != cur_def_msgs ||
0364 result.mq_msgsize != cur_def_msgsize)
0365 printf("Kernel supports setting defaults, but does "
0366 "not actually honor them:\tFAIL\n\n");
0367 else {
0368 set(def_msgs, ++cur_def_msgs);
0369 set(def_msgsize, ++cur_def_msgsize);
0370
0371 set(max_msgs, ++cur_max_msgs);
0372 set(max_msgsize, ++cur_max_msgsize);
0373 test_queue(NULL, &result);
0374 if (result.mq_maxmsg != cur_def_msgs ||
0375 result.mq_msgsize != cur_def_msgsize)
0376 printf("Kernel supports setting defaults, but "
0377 "does not actually honor them:\t"
0378 "FAIL\n");
0379 else
0380 printf("Kernel properly honors default setting "
0381 "knobs:\t\t\t\tPASS\n");
0382 }
0383 set(def_msgs, cur_max_msgs + 1);
0384 cur_def_msgs = cur_max_msgs + 1;
0385 set(def_msgsize, cur_max_msgsize + 1);
0386 cur_def_msgsize = cur_max_msgsize + 1;
0387 if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
0388 cur_limits.rlim_cur) {
0389 cur_limits.rlim_cur = (cur_def_msgs + 2) *
0390 (cur_def_msgsize + 2 * sizeof(void *));
0391 cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
0392 setr(RLIMIT_MSGQUEUE, &cur_limits);
0393 }
0394 if (test_queue_fail(NULL, &result)) {
0395 if (result.mq_maxmsg == cur_max_msgs &&
0396 result.mq_msgsize == cur_max_msgsize)
0397 printf("Kernel properly limits default values "
0398 "to lesser of default/max:\t\tPASS\n");
0399 else
0400 printf("Kernel does not properly set default "
0401 "queue parameters when\ndefaults > "
0402 "max:\t\t\t\t\t\t\t\tFAIL\n");
0403 } else
0404 printf("Kernel fails to open mq because defaults are "
0405 "greater than maximums:\tFAIL\n");
0406 set(def_msgs, --cur_def_msgs);
0407 set(def_msgsize, --cur_def_msgsize);
0408 cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
0409 cur_def_msgsize;
0410 setr(RLIMIT_MSGQUEUE, &cur_limits);
0411 if (test_queue_fail(NULL, &result))
0412 printf("Kernel creates queue even though defaults "
0413 "would exceed\nrlimit setting:"
0414 "\t\t\t\t\t\t\t\tFAIL\n");
0415 else
0416 printf("Kernel properly fails to create queue when "
0417 "defaults would\nexceed rlimit:"
0418 "\t\t\t\t\t\t\t\tPASS\n");
0419 }
0420
0421
0422
0423
0424 printf("\n\nTest series 2, behavior when attr struct is "
0425 "passed to mq_open:\n");
0426 cur_max_msgs = 32;
0427 cur_max_msgsize = cur_limits.rlim_max >> 4;
0428 set(max_msgs, cur_max_msgs);
0429 set(max_msgsize, cur_max_msgsize);
0430 attr.mq_maxmsg = cur_max_msgs;
0431 attr.mq_msgsize = cur_max_msgsize;
0432 if (test_queue_fail(&attr, &result))
0433 printf("Queue open in excess of rlimit max when euid = 0 "
0434 "succeeded:\t\tFAIL\n");
0435 else
0436 printf("Queue open in excess of rlimit max when euid = 0 "
0437 "failed:\t\tPASS\n");
0438 attr.mq_maxmsg = cur_max_msgs + 1;
0439 attr.mq_msgsize = 10;
0440 if (test_queue_fail(&attr, &result))
0441 printf("Queue open with mq_maxmsg > limit when euid = 0 "
0442 "succeeded:\t\tPASS\n");
0443 else
0444 printf("Queue open with mq_maxmsg > limit when euid = 0 "
0445 "failed:\t\tFAIL\n");
0446 attr.mq_maxmsg = 1;
0447 attr.mq_msgsize = cur_max_msgsize + 1;
0448 if (test_queue_fail(&attr, &result))
0449 printf("Queue open with mq_msgsize > limit when euid = 0 "
0450 "succeeded:\t\tPASS\n");
0451 else
0452 printf("Queue open with mq_msgsize > limit when euid = 0 "
0453 "failed:\t\tFAIL\n");
0454 attr.mq_maxmsg = 65536;
0455 attr.mq_msgsize = 65536;
0456 if (test_queue_fail(&attr, &result))
0457 printf("Queue open with total size > 2GB when euid = 0 "
0458 "succeeded:\t\tFAIL\n");
0459 else
0460 printf("Queue open with total size > 2GB when euid = 0 "
0461 "failed:\t\t\tPASS\n");
0462
0463 if (seteuid(99) == -1) {
0464 perror("seteuid() failed");
0465 exit(1);
0466 }
0467
0468 attr.mq_maxmsg = cur_max_msgs;
0469 attr.mq_msgsize = cur_max_msgsize;
0470 if (test_queue_fail(&attr, &result))
0471 printf("Queue open in excess of rlimit max when euid = 99 "
0472 "succeeded:\t\tFAIL\n");
0473 else
0474 printf("Queue open in excess of rlimit max when euid = 99 "
0475 "failed:\t\tPASS\n");
0476 attr.mq_maxmsg = cur_max_msgs + 1;
0477 attr.mq_msgsize = 10;
0478 if (test_queue_fail(&attr, &result))
0479 printf("Queue open with mq_maxmsg > limit when euid = 99 "
0480 "succeeded:\t\tFAIL\n");
0481 else
0482 printf("Queue open with mq_maxmsg > limit when euid = 99 "
0483 "failed:\t\tPASS\n");
0484 attr.mq_maxmsg = 1;
0485 attr.mq_msgsize = cur_max_msgsize + 1;
0486 if (test_queue_fail(&attr, &result))
0487 printf("Queue open with mq_msgsize > limit when euid = 99 "
0488 "succeeded:\t\tFAIL\n");
0489 else
0490 printf("Queue open with mq_msgsize > limit when euid = 99 "
0491 "failed:\t\tPASS\n");
0492 attr.mq_maxmsg = 65536;
0493 attr.mq_msgsize = 65536;
0494 if (test_queue_fail(&attr, &result))
0495 printf("Queue open with total size > 2GB when euid = 99 "
0496 "succeeded:\t\tFAIL\n");
0497 else
0498 printf("Queue open with total size > 2GB when euid = 99 "
0499 "failed:\t\t\tPASS\n");
0500
0501 shutdown(0,"",0);
0502 }