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