linux/tools/testing/selftests/mqueue/mq_open_tests.c
<<
>>
Prefs
   1/*
   2 * This application is Copyright 2012 Red Hat, Inc.
   3 *      Doug Ledford <dledford@redhat.com>
   4 *
   5 * mq_open_tests is free software: you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation, version 3.
   8 *
   9 * mq_open_tests is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * For the full text of the license, see <http://www.gnu.org/licenses/>.
  15 *
  16 * mq_open_tests.c
  17 *   Tests the various situations that should either succeed or fail to
  18 *   open a posix message queue and then reports whether or not they
  19 *   did as they were supposed to.
  20 *
  21 */
  22#include <stdio.h>
  23#include <stdlib.h>
  24#include <unistd.h>
  25#include <fcntl.h>
  26#include <string.h>
  27#include <limits.h>
  28#include <errno.h>
  29#include <sys/types.h>
  30#include <sys/time.h>
  31#include <sys/resource.h>
  32#include <sys/stat.h>
  33#include <mqueue.h>
  34
  35static char *usage =
  36"Usage:\n"
  37"  %s path\n"
  38"\n"
  39"       path    Path name of the message queue to create\n"
  40"\n"
  41"       Note: this program must be run as root in order to enable all tests\n"
  42"\n";
  43
  44char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
  45char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
  46char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
  47char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
  48
  49int default_settings;
  50struct rlimit saved_limits, cur_limits;
  51int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
  52int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
  53FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
  54char *queue_path;
  55mqd_t queue = -1;
  56
  57static inline void __set(FILE *stream, int value, char *err_msg);
  58void shutdown(int exit_val, char *err_cause, int line_no);
  59static inline int get(FILE *stream);
  60static inline void set(FILE *stream, int value);
  61static inline void getr(int type, struct rlimit *rlim);
  62static inline void setr(int type, struct rlimit *rlim);
  63void validate_current_settings();
  64static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
  65static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
  66
  67static inline void __set(FILE *stream, int value, char *err_msg)
  68{
  69        rewind(stream);
  70        if (fprintf(stream, "%d", value) < 0)
  71                perror(err_msg);
  72}
  73
  74
  75void shutdown(int exit_val, char *err_cause, int line_no)
  76{
  77        static int in_shutdown = 0;
  78
  79        /* In case we get called recursively by a set() call below */
  80        if (in_shutdown++)
  81                return;
  82
  83        seteuid(0);
  84
  85        if (queue != -1)
  86                if (mq_close(queue))
  87                        perror("mq_close() during shutdown");
  88        if (queue_path)
  89                /*
  90                 * Be silent if this fails, if we cleaned up already it's
  91                 * expected to fail
  92                 */
  93                mq_unlink(queue_path);
  94        if (default_settings) {
  95                if (saved_def_msgs)
  96                        __set(def_msgs, saved_def_msgs,
  97                              "failed to restore saved_def_msgs");
  98                if (saved_def_msgsize)
  99                        __set(def_msgsize, saved_def_msgsize,
 100                              "failed to restore saved_def_msgsize");
 101        }
 102        if (saved_max_msgs)
 103                __set(max_msgs, saved_max_msgs,
 104                      "failed to restore saved_max_msgs");
 105        if (saved_max_msgsize)
 106                __set(max_msgsize, saved_max_msgsize,
 107                      "failed to restore saved_max_msgsize");
 108        if (exit_val)
 109                error(exit_val, errno, "%s at %d", err_cause, line_no);
 110        exit(0);
 111}
 112
 113static inline int get(FILE *stream)
 114{
 115        int value;
 116        rewind(stream);
 117        if (fscanf(stream, "%d", &value) != 1)
 118                shutdown(4, "Error reading /proc entry", __LINE__ - 1);
 119        return value;
 120}
 121
 122static inline void set(FILE *stream, int value)
 123{
 124        int new_value;
 125
 126        rewind(stream);
 127        if (fprintf(stream, "%d", value) < 0)
 128                return shutdown(5, "Failed writing to /proc file",
 129                                __LINE__ - 1);
 130        new_value = get(stream);
 131        if (new_value != value)
 132                return shutdown(5, "We didn't get what we wrote to /proc back",
 133                                __LINE__ - 1);
 134}
 135
 136static inline void getr(int type, struct rlimit *rlim)
 137{
 138        if (getrlimit(type, rlim))
 139                shutdown(6, "getrlimit()", __LINE__ - 1);
 140}
 141
 142static inline void setr(int type, struct rlimit *rlim)
 143{
 144        if (setrlimit(type, rlim))
 145                shutdown(7, "setrlimit()", __LINE__ - 1);
 146}
 147
 148void validate_current_settings()
 149{
 150        int rlim_needed;
 151
 152        if (cur_limits.rlim_cur < 4096) {
 153                printf("Current rlimit value for POSIX message queue bytes is "
 154                       "unreasonably low,\nincreasing.\n\n");
 155                cur_limits.rlim_cur = 8192;
 156                cur_limits.rlim_max = 16384;
 157                setr(RLIMIT_MSGQUEUE, &cur_limits);
 158        }
 159
 160        if (default_settings) {
 161                rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
 162                                                    2 * sizeof(void *));
 163                if (rlim_needed > cur_limits.rlim_cur) {
 164                        printf("Temporarily lowering default queue parameters "
 165                               "to something that will work\n"
 166                               "with the current rlimit values.\n\n");
 167                        set(def_msgs, 10);
 168                        cur_def_msgs = 10;
 169                        set(def_msgsize, 128);
 170                        cur_def_msgsize = 128;
 171                }
 172        } else {
 173                rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
 174                                                    2 * sizeof(void *));
 175                if (rlim_needed > cur_limits.rlim_cur) {
 176                        printf("Temporarily lowering maximum queue parameters "
 177                               "to something that will work\n"
 178                               "with the current rlimit values in case this is "
 179                               "a kernel that ties the default\n"
 180                               "queue parameters to the maximum queue "
 181                               "parameters.\n\n");
 182                        set(max_msgs, 10);
 183                        cur_max_msgs = 10;
 184                        set(max_msgsize, 128);
 185                        cur_max_msgsize = 128;
 186                }
 187        }
 188}
 189
 190/*
 191 * test_queue - Test opening a queue, shutdown if we fail.  This should
 192 * only be called in situations that should never fail.  We clean up
 193 * after ourselves and return the queue attributes in *result.
 194 */
 195static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
 196{
 197        int flags = O_RDWR | O_EXCL | O_CREAT;
 198        int perms = DEFFILEMODE;
 199
 200        if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
 201                shutdown(1, "mq_open()", __LINE__);
 202        if (mq_getattr(queue, result))
 203                shutdown(1, "mq_getattr()", __LINE__);
 204        if (mq_close(queue))
 205                shutdown(1, "mq_close()", __LINE__);
 206        queue = -1;
 207        if (mq_unlink(queue_path))
 208                shutdown(1, "mq_unlink()", __LINE__);
 209}
 210
 211/*
 212 * Same as test_queue above, but failure is not fatal.
 213 * Returns:
 214 * 0 - Failed to create a queue
 215 * 1 - Created a queue, attributes in *result
 216 */
 217static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
 218{
 219        int flags = O_RDWR | O_EXCL | O_CREAT;
 220        int perms = DEFFILEMODE;
 221
 222        if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
 223                return 0;
 224        if (mq_getattr(queue, result))
 225                shutdown(1, "mq_getattr()", __LINE__);
 226        if (mq_close(queue))
 227                shutdown(1, "mq_close()", __LINE__);
 228        queue = -1;
 229        if (mq_unlink(queue_path))
 230                shutdown(1, "mq_unlink()", __LINE__);
 231        return 1;
 232}
 233
 234int main(int argc, char *argv[])
 235{
 236        struct mq_attr attr, result;
 237
 238        if (argc != 2) {
 239                fprintf(stderr, "Must pass a valid queue name\n\n");
 240                fprintf(stderr, usage, argv[0]);
 241                exit(1);
 242        }
 243
 244        /*
 245         * Although we can create a msg queue with a non-absolute path name,
 246         * unlink will fail.  So, if the name doesn't start with a /, add one
 247         * when we save it.
 248         */
 249        if (*argv[1] == '/')
 250                queue_path = strdup(argv[1]);
 251        else {
 252                queue_path = malloc(strlen(argv[1]) + 2);
 253                if (!queue_path) {
 254                        perror("malloc()");
 255                        exit(1);
 256                }
 257                queue_path[0] = '/';
 258                queue_path[1] = 0;
 259                strcat(queue_path, argv[1]);
 260        }
 261
 262        if (getuid() != 0) {
 263                fprintf(stderr, "Not running as root, but almost all tests "
 264                        "require root in order to modify\nsystem settings.  "
 265                        "Exiting.\n");
 266                exit(1);
 267        }
 268
 269        /* Find out what files there are for us to make tweaks in */
 270        def_msgs = fopen(DEF_MSGS, "r+");
 271        def_msgsize = fopen(DEF_MSGSIZE, "r+");
 272        max_msgs = fopen(MAX_MSGS, "r+");
 273        max_msgsize = fopen(MAX_MSGSIZE, "r+");
 274
 275        if (!max_msgs)
 276                shutdown(2, "Failed to open msg_max", __LINE__);
 277        if (!max_msgsize)
 278                shutdown(2, "Failed to open msgsize_max", __LINE__);
 279        if (def_msgs || def_msgsize)
 280                default_settings = 1;
 281
 282        /* Load up the current system values for everything we can */
 283        getr(RLIMIT_MSGQUEUE, &saved_limits);
 284        cur_limits = saved_limits;
 285        if (default_settings) {
 286                saved_def_msgs = cur_def_msgs = get(def_msgs);
 287                saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
 288        }
 289        saved_max_msgs = cur_max_msgs = get(max_msgs);
 290        saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
 291
 292        /* Tell the user our initial state */
 293        printf("\nInitial system state:\n");
 294        printf("\tUsing queue path:\t\t%s\n", queue_path);
 295        printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur);
 296        printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max);
 297        printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
 298        printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
 299        if (default_settings) {
 300                printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
 301                printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
 302        } else {
 303                printf("\tDefault Message Size:\t\tNot Supported\n");
 304                printf("\tDefault Queue Size:\t\tNot Supported\n");
 305        }
 306        printf("\n");
 307
 308        validate_current_settings();
 309
 310        printf("Adjusted system state for testing:\n");
 311        printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur);
 312        printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max);
 313        printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
 314        printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
 315        if (default_settings) {
 316                printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
 317                printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
 318        }
 319
 320        printf("\n\nTest series 1, behavior when no attr struct "
 321               "passed to mq_open:\n");
 322        if (!default_settings) {
 323                test_queue(NULL, &result);
 324                printf("Given sane system settings, mq_open without an attr "
 325                       "struct succeeds:\tPASS\n");
 326                if (result.mq_maxmsg != cur_max_msgs ||
 327                    result.mq_msgsize != cur_max_msgsize) {
 328                        printf("Kernel does not support setting the default "
 329                               "mq attributes,\nbut also doesn't tie the "
 330                               "defaults to the maximums:\t\t\tPASS\n");
 331                } else {
 332                        set(max_msgs, ++cur_max_msgs);
 333                        set(max_msgsize, ++cur_max_msgsize);
 334                        test_queue(NULL, &result);
 335                        if (result.mq_maxmsg == cur_max_msgs &&
 336                            result.mq_msgsize == cur_max_msgsize)
 337                                printf("Kernel does not support setting the "
 338                                       "default mq attributes and\n"
 339                                       "also ties system wide defaults to "
 340                                       "the system wide maximums:\t\t"
 341                                       "FAIL\n");
 342                        else
 343                                printf("Kernel does not support setting the "
 344                                       "default mq attributes,\n"
 345                                       "but also doesn't tie the defaults to "
 346                                       "the maximums:\t\t\tPASS\n");
 347                }
 348        } else {
 349                printf("Kernel supports setting defaults separately from "
 350                       "maximums:\t\tPASS\n");
 351                /*
 352                 * While we are here, go ahead and test that the kernel
 353                 * properly follows the default settings
 354                 */
 355                test_queue(NULL, &result);
 356                printf("Given sane values, mq_open without an attr struct "
 357                       "succeeds:\t\tPASS\n");
 358                if (result.mq_maxmsg != cur_def_msgs ||
 359                    result.mq_msgsize != cur_def_msgsize)
 360                        printf("Kernel supports setting defaults, but does "
 361                               "not actually honor them:\tFAIL\n\n");
 362                else {
 363                        set(def_msgs, ++cur_def_msgs);
 364                        set(def_msgsize, ++cur_def_msgsize);
 365                        /* In case max was the same as the default */
 366                        set(max_msgs, ++cur_max_msgs);
 367                        set(max_msgsize, ++cur_max_msgsize);
 368                        test_queue(NULL, &result);
 369                        if (result.mq_maxmsg != cur_def_msgs ||
 370                            result.mq_msgsize != cur_def_msgsize)
 371                                printf("Kernel supports setting defaults, but "
 372                                       "does not actually honor them:\t"
 373                                       "FAIL\n");
 374                        else
 375                                printf("Kernel properly honors default setting "
 376                                       "knobs:\t\t\t\tPASS\n");
 377                }
 378                set(def_msgs, cur_max_msgs + 1);
 379                cur_def_msgs = cur_max_msgs + 1;
 380                set(def_msgsize, cur_max_msgsize + 1);
 381                cur_def_msgsize = cur_max_msgsize + 1;
 382                if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
 383                    cur_limits.rlim_cur) {
 384                        cur_limits.rlim_cur = (cur_def_msgs + 2) *
 385                                (cur_def_msgsize + 2 * sizeof(void *));
 386                        cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
 387                        setr(RLIMIT_MSGQUEUE, &cur_limits);
 388                }
 389                if (test_queue_fail(NULL, &result)) {
 390                        if (result.mq_maxmsg == cur_max_msgs &&
 391                            result.mq_msgsize == cur_max_msgsize)
 392                                printf("Kernel properly limits default values "
 393                                       "to lesser of default/max:\t\tPASS\n");
 394                        else
 395                                printf("Kernel does not properly set default "
 396                                       "queue parameters when\ndefaults > "
 397                                       "max:\t\t\t\t\t\t\t\tFAIL\n");
 398                } else
 399                        printf("Kernel fails to open mq because defaults are "
 400                               "greater than maximums:\tFAIL\n");
 401                set(def_msgs, --cur_def_msgs);
 402                set(def_msgsize, --cur_def_msgsize);
 403                cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
 404                        cur_def_msgsize;
 405                setr(RLIMIT_MSGQUEUE, &cur_limits);
 406                if (test_queue_fail(NULL, &result))
 407                        printf("Kernel creates queue even though defaults "
 408                               "would exceed\nrlimit setting:"
 409                               "\t\t\t\t\t\t\t\tFAIL\n");
 410                else
 411                        printf("Kernel properly fails to create queue when "
 412                               "defaults would\nexceed rlimit:"
 413                               "\t\t\t\t\t\t\t\tPASS\n");
 414        }
 415
 416        /*
 417         * Test #2 - open with an attr struct that exceeds rlimit
 418         */
 419        printf("\n\nTest series 2, behavior when attr struct is "
 420               "passed to mq_open:\n");
 421        cur_max_msgs = 32;
 422        cur_max_msgsize = cur_limits.rlim_max >> 4;
 423        set(max_msgs, cur_max_msgs);
 424        set(max_msgsize, cur_max_msgsize);
 425        attr.mq_maxmsg = cur_max_msgs;
 426        attr.mq_msgsize = cur_max_msgsize;
 427        if (test_queue_fail(&attr, &result))
 428                printf("Queue open in excess of rlimit max when euid = 0 "
 429                       "succeeded:\t\tFAIL\n");
 430        else
 431                printf("Queue open in excess of rlimit max when euid = 0 "
 432                       "failed:\t\tPASS\n");
 433        attr.mq_maxmsg = cur_max_msgs + 1;
 434        attr.mq_msgsize = 10;
 435        if (test_queue_fail(&attr, &result))
 436                printf("Queue open with mq_maxmsg > limit when euid = 0 "
 437                       "succeeded:\t\tPASS\n");
 438        else
 439                printf("Queue open with mq_maxmsg > limit when euid = 0 "
 440                       "failed:\t\tFAIL\n");
 441        attr.mq_maxmsg = 1;
 442        attr.mq_msgsize = cur_max_msgsize + 1;
 443        if (test_queue_fail(&attr, &result))
 444                printf("Queue open with mq_msgsize > limit when euid = 0 "
 445                       "succeeded:\t\tPASS\n");
 446        else
 447                printf("Queue open with mq_msgsize > limit when euid = 0 "
 448                       "failed:\t\tFAIL\n");
 449        attr.mq_maxmsg = 65536;
 450        attr.mq_msgsize = 65536;
 451        if (test_queue_fail(&attr, &result))
 452                printf("Queue open with total size > 2GB when euid = 0 "
 453                       "succeeded:\t\tFAIL\n");
 454        else
 455                printf("Queue open with total size > 2GB when euid = 0 "
 456                       "failed:\t\t\tPASS\n");
 457        seteuid(99);
 458        attr.mq_maxmsg = cur_max_msgs;
 459        attr.mq_msgsize = cur_max_msgsize;
 460        if (test_queue_fail(&attr, &result))
 461                printf("Queue open in excess of rlimit max when euid = 99 "
 462                       "succeeded:\t\tFAIL\n");
 463        else
 464                printf("Queue open in excess of rlimit max when euid = 99 "
 465                       "failed:\t\tPASS\n");
 466        attr.mq_maxmsg = cur_max_msgs + 1;
 467        attr.mq_msgsize = 10;
 468        if (test_queue_fail(&attr, &result))
 469                printf("Queue open with mq_maxmsg > limit when euid = 99 "
 470                       "succeeded:\t\tFAIL\n");
 471        else
 472                printf("Queue open with mq_maxmsg > limit when euid = 99 "
 473                       "failed:\t\tPASS\n");
 474        attr.mq_maxmsg = 1;
 475        attr.mq_msgsize = cur_max_msgsize + 1;
 476        if (test_queue_fail(&attr, &result))
 477                printf("Queue open with mq_msgsize > limit when euid = 99 "
 478                       "succeeded:\t\tFAIL\n");
 479        else
 480                printf("Queue open with mq_msgsize > limit when euid = 99 "
 481                       "failed:\t\tPASS\n");
 482        attr.mq_maxmsg = 65536;
 483        attr.mq_msgsize = 65536;
 484        if (test_queue_fail(&attr, &result))
 485                printf("Queue open with total size > 2GB when euid = 99 "
 486                       "succeeded:\t\tFAIL\n");
 487        else
 488                printf("Queue open with total size > 2GB when euid = 99 "
 489                       "failed:\t\t\tPASS\n");
 490
 491        shutdown(0,"",0);
 492}
 493