Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * This application is Copyright 2012 Red Hat, Inc.
0003  *  Doug Ledford <dledford@redhat.com>
0004  *
0005  * mq_open_tests is free software: you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation, version 3.
0008  *
0009  * mq_open_tests is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  * GNU General Public License for more details.
0013  *
0014  * For the full text of the license, see <http://www.gnu.org/licenses/>.
0015  *
0016  * mq_open_tests.c
0017  *   Tests the various situations that should either succeed or fail to
0018  *   open a posix message queue and then reports whether or not they
0019  *   did as they were supposed to.
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     /* In case we get called recursively by a set() call below */
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          * Be silent if this fails, if we cleaned up already it's
0096          * expected to fail
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  * test_queue - Test opening a queue, shutdown if we fail.  This should
0197  * only be called in situations that should never fail.  We clean up
0198  * after ourselves and return the queue attributes in *result.
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  * Same as test_queue above, but failure is not fatal.
0218  * Returns:
0219  * 0 - Failed to create a queue
0220  * 1 - Created a queue, attributes in *result
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      * Although we can create a msg queue with a non-absolute path name,
0250      * unlink will fail.  So, if the name doesn't start with a /, add one
0251      * when we save it.
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     /* Find out what files there are for us to make tweaks in */
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     /* Load up the current system values for everything we can */
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     /* Tell the user our initial state */
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          * While we are here, go ahead and test that the kernel
0358          * properly follows the default settings
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             /* In case max was the same as the default */
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      * Test #2 - open with an attr struct that exceeds rlimit
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 }