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 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/mman.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/resource.h>
31 #include <fcntl.h>
32 #include <pwd.h>
33 #include <string.h>
34 #include <errno.h>
35 #include "posixtest.h"
36
37 /* Set the euid of this process to a non-root uid */
set_nonroot(void)38 int set_nonroot(void)
39 {
40 struct passwd *pw;
41 setpwent();
42 /* search for the first user which is non root */
43 while ((pw = getpwent()) != NULL)
44 if (strcmp(pw->pw_name, "root"))
45 break;
46 endpwent();
47 if (pw == NULL) {
48 printf("There is no other user than current and root.\n");
49 return 1;
50 }
51
52 if (seteuid(pw->pw_uid) != 0) {
53 if (errno == EPERM) {
54 printf
55 ("You don't have permission to change your UID.\n");
56 return 1;
57 }
58 perror("An error occurs when calling seteuid()");
59 return 1;
60 }
61
62 printf("Testing with user '%s' (uid: %d)\n",
63 pw->pw_name, (int)geteuid());
64 return 0;
65 }
66
main(void)67 int main(void)
68 {
69 char tmpfname[256];
70
71 /* size of shared memory object */
72 size_t shm_size;
73
74 void *pa;
75 size_t len;
76 int fd;
77
78 size_t memlock_size;
79 struct rlimit rlim = {.rlim_max = RLIM_INFINITY };
80
81 /* Lock all memory page to be mapped */
82 if (mlockall(MCL_FUTURE) == -1) {
83 printf("Error at mlockall(): %s\n", strerror(errno));
84 return PTS_UNRESOLVED;
85 }
86
87 /* Set rlim.rlim_cur < len */
88 len = 1024 * 1024;
89 memlock_size = len / 2;
90 rlim.rlim_cur = memlock_size;
91
92 /* We don't care of the size of the actual shared memory object */
93 shm_size = 1024;
94
95 if (setrlimit(RLIMIT_MEMLOCK, &rlim) == -1) {
96 printf("Error at setrlimit(): %s\n", strerror(errno));
97 return PTS_UNRESOLVED;
98 }
99
100 snprintf(tmpfname, sizeof(tmpfname), "pts_mmap_18_1_%d", getpid());
101
102 /* Create shared object */
103 shm_unlink(tmpfname);
104 fd = shm_open(tmpfname, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
105 if (fd == -1) {
106 printf("Error at shm_open(): %s\n", strerror(errno));
107 return PTS_UNRESOLVED;
108 }
109 shm_unlink(tmpfname);
110 if (ftruncate(fd, shm_size) == -1) {
111 printf("Error at ftruncate(): %s\n", strerror(errno));
112 return PTS_UNRESOLVED;
113 }
114
115 /* This test should be run under standard user permissions */
116 if (getuid() == 0) {
117 if (set_nonroot() != 0) {
118 printf("Cannot run this test as non-root user\n");
119 return PTS_UNTESTED;
120 }
121 }
122
123 /*
124 * EAGAIN:
125 * Lock all the memory by mlockall().
126 * Set resource limit setrlimit()
127 * Change the user to non-root then only setrmilit is applicable.
128 */
129 pa = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
130 if (pa == MAP_FAILED && errno == EAGAIN) {
131 printf("Got EAGAIN: %s\n", strerror(errno));
132 printf("Test PASSED\n");
133 /* Change user to root */
134 seteuid(0);
135 close(fd);
136 munmap(pa, len);
137 return PTS_PASS;
138 }
139
140 if (pa == MAP_FAILED)
141 perror("Error at mmap()");
142 close(fd);
143 munmap(pa, len);
144 printf("Test FAILED: Did not get EAGAIN as expected\n");
145 return PTS_FAIL;
146 }
147