cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mq_open_tests.c (15885B)


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