1 /*
2 * Copyright (C) Bull S.A. 2005. $
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15 *
16 */
17 /**************************************************************************
18 *
19 * TEST IDENTIFIER : mlockall03
20 *
21 * EXECUTED BY : root / superuser
22 *
23 * TEST TITLE : Test for checking basic error conditions for
24 * mlockall(2)
25 *
26 * TEST CASE TOTAL : 3
27 *
28 * AUTHOR : Jacky Malcles
29 *
30 * SIGNALS
31 * Uses SIGUSR1 to pause before test if option set.
32 * (See the parse_opts(3) man page).
33 *
34 * DESCRIPTION
35 *$
36 * Verify that mlockall(2) returns -1 and sets errno to
37 *
38 * 1) ENOMEM - If the caller had a non-zero RLIMIT_MEMLOCK
39 * and tried to lock more memory than the limit permitted.
40 * 2) EPERM - If the caller was not privileged
41 * and its RLIMIT_MEMLOCK soft resource limit was 0.
42 * 3) EINVAL - Unknown flags were specified.
43 *
44 * Setup:
45 * Setup signal handling.
46 * Pause for SIGUSR1 if option specified.
47 *
48 * Test:
49 * Loop if the proper options are given.
50 * Do necessary setup for each test.
51 * Execute system call
52 * Check return code, if system call failed and errno == expected errno
53 * Issue sys call passed with expected return value and errno.
54 * Otherwise,
55 * Issue sys call failed to produce expected error.
56 * Do cleanup for each test.
57 *
58 * Cleanup:
59 * Print errno log and/or timing stats if options given
60 *
61 * USAGE: <for command-line>
62 * mlockall03 [-c n] [-e] [-i n] [-I x] [-p x] [-t]
63 * where,
64 * -c n : Run n copies concurrently
65 * -e : Turn on errno logging.
66 * -h : Show this help screen
67 * -i n : Execute test n times.
68 * -I x : Execute test for x seconds.
69 * -p : Pause for SIGUSR1 before starting
70 * -P x : Pause for x seconds between iterations.
71 * -t : Turn on syscall timing.
72 *
73 * RESTRICTIONS
74 * Test must run as root.
75 *****************************************************************************/
76 #include <errno.h>
77 #include <unistd.h>
78 #include <pwd.h>
79 #include <ctype.h>
80 #include <sys/mman.h>
81 #include "test.h"
82 #include <sys/resource.h>
83 #include <sys/utsname.h>
84
85 void setup();
86 int setup_test(int);
87 int compare(char s1[], char s2[]);
88 void cleanup_test(int);
89 void cleanup();
90
91 char *TCID = "mlockall03";
92 int TST_TOTAL = 3;
93
94 #if !defined(UCLINUX)
95
96 char *ref_release = "2.6.8\0";
97
98 struct test_case_t {
99 int flag; /* flag value */
100 int error; /* error description */
101 char *edesc; /* Expected error no */
102 } TC[] = {
103 {
104 MCL_CURRENT, ENOMEM,
105 "tried to lock more memory than the limit permitted"}, {
106 MCL_CURRENT, EPERM, "Not a superuser and RLIMIT_MEMLOCK was 0"}, {
107 ~(MCL_CURRENT | MCL_FUTURE), EINVAL, "Unknown flag"}
108 };
109
main(int ac,char ** av)110 int main(int ac, char **av)
111 {
112 int lc, i;
113 struct utsname *buf;
114
115 tst_parse_opts(ac, av, NULL, NULL);
116
117 /* allocate some space for buf */
118 if ((buf = malloc((size_t)sizeof(struct utsname))) == NULL) {
119 tst_brkm(TFAIL, NULL, "malloc failed for buf");
120 }
121
122 if (uname(buf) < 0) {
123 tst_resm(TFAIL, "uname failed getting release number");
124 }
125
126 if ((compare(ref_release, buf->release)) <= 0) {
127 tst_brkm(TCONF,
128 NULL,
129 "In Linux 2.6.8 and earlier this test will not run.");
130 }
131
132 setup();
133
134 /* check looping state */
135 for (lc = 0; TEST_LOOPING(lc); lc++) {
136
137 tst_count = 0;
138
139 for (i = 0; i < TST_TOTAL; i++) {
140
141 if (setup_test(i)) {
142 tst_resm(TFAIL, "mlockall() Failed while setup "
143 "for checking error %s", TC[i].edesc);
144 continue;
145 }
146
147 TEST(mlockall(TC[i].flag));
148
149 /* check return code */
150 if (TEST_RETURN == -1) {
151 if (TEST_ERRNO != TC[i].error)
152 tst_brkm(TFAIL, cleanup,
153 "mlockall() Failed with wrong "
154 "errno, expected errno=%s, "
155 "got errno=%d : %s",
156 TC[i].edesc, TEST_ERRNO,
157 strerror(TEST_ERRNO));
158 else
159 tst_resm(TPASS,
160 "expected failure - errno "
161 "= %d : %s",
162 TEST_ERRNO,
163 strerror(TEST_ERRNO));
164 } else {
165 tst_brkm(TFAIL, cleanup,
166 "mlockall() Failed, expected "
167 "return value=-1, got %ld",
168 TEST_RETURN);
169 }
170 cleanup_test(i);
171 }
172 }
173
174 /* cleanup and exit */
175 cleanup();
176
177 tst_exit();
178 }
179
180 /*
181 * setup() - performs all ONE TIME setup for this test.
182 */
setup(void)183 void setup(void)
184 {
185
186 tst_require_root();
187
188 tst_sig(FORK, DEF_HANDLER, cleanup);
189
190 TEST_PAUSE;
191
192 return;
193 }
194
compare(char s1[],char s2[])195 int compare(char s1[], char s2[])
196 {
197 int i = 0;
198 while (s1[i] == s2[i] && s1[i])
199 i++;
200
201 if (i < 4)
202 return s2[i] - s1[i];
203 if ((i == 4) && (isalnum(s2[i + 1]))) {
204 return 1;
205 } else {
206 /* it is not an alphanumeric character */
207 return s2[i] - s1[i];
208 }
209 return 0;
210 }
211
setup_test(int i)212 int setup_test(int i)
213 {
214 struct rlimit rl;
215 char nobody_uid[] = "nobody";
216 struct passwd *ltpuser;
217
218 switch (i) {
219 case 0:
220 ltpuser = getpwnam(nobody_uid);
221 if (seteuid(ltpuser->pw_uid) == -1) {
222 tst_brkm(TBROK, cleanup, "seteuid() failed to "
223 "change euid to %d errno = %d : %s",
224 ltpuser->pw_uid, TEST_ERRNO,
225 strerror(TEST_ERRNO));
226 return 1;
227 }
228
229 rl.rlim_max = 10;
230 rl.rlim_cur = 7;
231
232 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
233 tst_resm(TWARN, "setrlimit failed to set the "
234 "resource for RLIMIT_MEMLOCK to check "
235 "for mlockall() error %s\n", TC[i].edesc);
236 return 1;
237 }
238 return 0;
239 case 1:
240 rl.rlim_max = 0;
241 rl.rlim_cur = 0;
242
243 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
244 tst_resm(TWARN, "setrlimit failed to set the "
245 "resource for RLIMIT_MEMLOCK to check "
246 "for mlockall() error %s\n", TC[i].edesc);
247 return 1;
248 }
249
250 ltpuser = getpwnam(nobody_uid);
251 if (seteuid(ltpuser->pw_uid) == -1) {
252 tst_brkm(TBROK, cleanup, "seteuid() failed to "
253 "change euid to %d errno = %d : %s",
254 ltpuser->pw_uid, TEST_ERRNO,
255 strerror(TEST_ERRNO));
256 return 1;
257 }
258
259 return 0;
260 }
261 return 0;
262 }
263
cleanup_test(int i)264 void cleanup_test(int i)
265 {
266 struct rlimit rl;
267
268 switch (i) {
269 case 0:
270 if (seteuid(0) == -1) {
271 tst_brkm(TBROK, cleanup, "seteuid() failed to "
272 "change euid to %d errno = %d : %s",
273 0, TEST_ERRNO, strerror(TEST_ERRNO));
274 }
275
276 rl.rlim_max = -1;
277 rl.rlim_cur = -1;
278
279 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
280 tst_brkm(TFAIL, cleanup,
281 "setrlimit failed to reset the "
282 "resource for RLIMIT_MEMLOCK while "
283 "checking for mlockall() error %s\n",
284 TC[i].edesc);
285 }
286
287 return;
288
289 case 1:
290 if (seteuid(0) == -1) {
291 tst_brkm(TBROK, cleanup, "seteuid() failed to "
292 "change euid to %d errno = %d : %s",
293 0, TEST_ERRNO, strerror(TEST_ERRNO));
294 }
295 return;
296
297 }
298 }
299
300 #else
301
main(void)302 int main(void)
303 {
304 tst_resm(TINFO, "test is not available on uClinux");
305 tst_exit();
306 }
307
308 #endif /* if !defined(UCLINUX) */
309
310 /*
311 * cleanup() - performs all ONE TIME cleanup for this test at
312 * completion or premature exit.
313 */
cleanup(void)314 void cleanup(void)
315 {
316 return;
317 }
318