1 /*
2  * Copyright (c) 2002, Intel Corporation. All rights reserved.
3  * Copyright (c) 2012, Cyril Hrubis <chrubis@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 */
set_nonroot(void)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 
main(void)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