Home | History | Annotate | Download | only in mmap
      1 /*
      2  * Copyright (c) 2002, Intel Corporation. All rights reserved.
      3  * Copyright (c) 2012, Cyril Hrubis <chrubis (at) suse.cz>
      4  *
      5  * This file is licensed under the GPL license.  For the full content
      6  * of this license, see the COPYING file at the top level of this
      7  * source tree.
      8  *
      9  * The mmap() function shall fail if:
     10  * ML [EAGAIN] The mapping could not be locked in memory,
     11  * if required by mlockall(), due to a lack of resources.
     12  *
     13  * Test Steps:
     14  * 1. Call mlockall(), setting MCL_FUTURE;
     15  * 2. Call setrlimit(), set rlim_cur of resource RLIMIT_MEMLOCK to a
     16  *    certain value.
     17  * 3. Change user to non-root user seteuid()
     18  * 4. Map a shared memory object, with size larger than the
     19  *    rlim_cur value set in step 2
     20  * 5. Should get EAGAIN.
     21  * 6. Change user to root seteuid()
     22  */
     23 
     24 #define _XOPEN_SOURCE 600
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <unistd.h>
     28 #include <sys/mman.h>
     29 #include <sys/types.h>
     30 #include <sys/stat.h>
     31 #include <sys/resource.h>
     32 #include <fcntl.h>
     33 #include <pwd.h>
     34 #include <string.h>
     35 #include <errno.h>
     36 #include "posixtest.h"
     37 
     38 /* Set the euid of this process to a non-root uid */
     39 int set_nonroot(void)
     40 {
     41 	struct passwd *pw;
     42 	setpwent();
     43 	/* search for the first user which is non root */
     44 	while ((pw = getpwent()) != NULL)
     45 		if (strcmp(pw->pw_name, "root"))
     46 			break;
     47 	endpwent();
     48 	if (pw == NULL) {
     49 		printf("There is no other user than current and root.\n");
     50 		return 1;
     51 	}
     52 
     53 	if (seteuid(pw->pw_uid) != 0) {
     54 		if (errno == EPERM) {
     55 			printf
     56 			    ("You don't have permission to change your UID.\n");
     57 			return 1;
     58 		}
     59 		perror("An error occurs when calling seteuid()");
     60 		return 1;
     61 	}
     62 
     63 	printf("Testing with user '%s' (uid: %d)\n",
     64 	       pw->pw_name, (int)geteuid());
     65 	return 0;
     66 }
     67 
     68 int main(void)
     69 {
     70 	char tmpfname[256];
     71 
     72 	/* size of shared memory object */
     73 	size_t shm_size;
     74 
     75 	void *pa;
     76 	size_t len;
     77 	int fd;
     78 
     79 	size_t memlock_size;
     80 	struct rlimit rlim = {.rlim_max = RLIM_INFINITY };
     81 
     82 	/* Lock all memory page to be mapped */
     83 	if (mlockall(MCL_FUTURE) == -1) {
     84 		printf("Error at mlockall(): %s\n", strerror(errno));
     85 		return PTS_UNRESOLVED;
     86 	}
     87 
     88 	/* Set rlim.rlim_cur < len */
     89 	len = 1024 * 1024;
     90 	memlock_size = len / 2;
     91 	rlim.rlim_cur = memlock_size;
     92 
     93 	/* We don't care of the size of the actual shared memory object */
     94 	shm_size = 1024;
     95 
     96 	if (setrlimit(RLIMIT_MEMLOCK, &rlim) == -1) {
     97 		printf("Error at setrlimit(): %s\n", strerror(errno));
     98 		return PTS_UNRESOLVED;
     99 	}
    100 
    101 	snprintf(tmpfname, sizeof(tmpfname), "pts_mmap_18_1_%d", getpid());
    102 
    103 	/* Create shared object */
    104 	shm_unlink(tmpfname);
    105 	fd = shm_open(tmpfname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    106 	if (fd == -1) {
    107 		printf("Error at shm_open(): %s\n", strerror(errno));
    108 		return PTS_UNRESOLVED;
    109 	}
    110 	shm_unlink(tmpfname);
    111 	if (ftruncate(fd, shm_size) == -1) {
    112 		printf("Error at ftruncate(): %s\n", strerror(errno));
    113 		return PTS_UNRESOLVED;
    114 	}
    115 
    116 	/* This test should be run under standard user permissions */
    117 	if (getuid() == 0) {
    118 		if (set_nonroot() != 0) {
    119 			printf("Cannot run this test as non-root user\n");
    120 			return PTS_UNTESTED;
    121 		}
    122 	}
    123 
    124 	/*
    125 	 * EAGAIN:
    126 	 * Lock all the memory by mlockall().
    127 	 * Set resource limit setrlimit()
    128 	 * Change the user to non-root then only setrmilit is applicable.
    129 	 */
    130 	pa = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    131 	if (pa == MAP_FAILED && errno == EAGAIN) {
    132 		printf("Got EAGAIN: %s\n", strerror(errno));
    133 		printf("Test PASSED\n");
    134 		/* Change user to root */
    135 		seteuid(0);
    136 		close(fd);
    137 		munmap(pa, len);
    138 		return PTS_PASS;
    139 	}
    140 
    141 	if (pa == MAP_FAILED)
    142 		perror("Error at mmap()");
    143 	close(fd);
    144 	munmap(pa, len);
    145 	printf("Test FAILED: Did not get EAGAIN as expected\n");
    146 	return PTS_FAIL;
    147 }
    148