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 "safe_macros.h"
83 #include <sys/resource.h>
84 #include <sys/utsname.h>
85
86 void setup();
87 int setup_test(int);
88 int compare(char s1[], char s2[]);
89 void cleanup_test(int);
90 void cleanup();
91
92 char *TCID = "mlockall03";
93 int TST_TOTAL = 3;
94
95 char *ref_release = "2.6.8\0";
96
97 struct test_case_t {
98 int flag; /* flag value */
99 int error; /* error description */
100 char *edesc; /* Expected error no */
101 } TC[] = {
102 {
103 MCL_CURRENT, ENOMEM,
104 "tried to lock more memory than the limit permitted"}, {
105 MCL_CURRENT, EPERM, "Not a superuser and RLIMIT_MEMLOCK was 0"}, {
106 ~(MCL_CURRENT | MCL_FUTURE), EINVAL, "Unknown flag"}
107 };
108
main(int ac,char ** av)109 int main(int ac, char **av)
110 {
111 int lc, i;
112 struct utsname *buf;
113
114 tst_parse_opts(ac, av, NULL, NULL);
115
116 /* allocate some space for buf */
117 if ((buf = malloc((size_t)sizeof(struct utsname))) == NULL) {
118 tst_brkm(TFAIL, NULL, "malloc failed for buf");
119 }
120
121 if (uname(buf) < 0) {
122 tst_resm(TFAIL, "uname failed getting release number");
123 }
124
125 if ((compare(ref_release, buf->release)) <= 0) {
126 tst_brkm(TCONF,
127 NULL,
128 "In Linux 2.6.8 and earlier this test will not run.");
129 }
130
131 setup();
132
133 /* check looping state */
134 for (lc = 0; TEST_LOOPING(lc); lc++) {
135
136 tst_count = 0;
137
138 for (i = 0; i < TST_TOTAL; i++) {
139
140 if (setup_test(i)) {
141 tst_resm(TFAIL, "mlockall() Failed while setup "
142 "for checking error %s", TC[i].edesc);
143 continue;
144 }
145
146 TEST(mlockall(TC[i].flag));
147
148 /* check return code */
149 if (TEST_RETURN == -1) {
150 if (TEST_ERRNO != TC[i].error)
151 tst_brkm(TFAIL, cleanup,
152 "mlockall() Failed with wrong "
153 "errno, expected errno=%s, "
154 "got errno=%d : %s",
155 TC[i].edesc, TEST_ERRNO,
156 strerror(TEST_ERRNO));
157 else
158 tst_resm(TPASS,
159 "expected failure - errno "
160 "= %d : %s",
161 TEST_ERRNO,
162 strerror(TEST_ERRNO));
163 } else {
164 tst_brkm(TFAIL, cleanup,
165 "mlockall() Failed, expected "
166 "return value=-1, got %ld",
167 TEST_RETURN);
168 }
169 cleanup_test(i);
170 }
171 }
172
173 /* cleanup and exit */
174 cleanup();
175
176 tst_exit();
177 }
178
179 /*
180 * setup() - performs all ONE TIME setup for this test.
181 */
setup(void)182 void setup(void)
183 {
184
185 tst_require_root();
186
187 tst_sig(FORK, DEF_HANDLER, cleanup);
188
189 TEST_PAUSE;
190
191 return;
192 }
193
compare(char s1[],char s2[])194 int compare(char s1[], char s2[])
195 {
196 int i = 0;
197 while (s1[i] == s2[i] && s1[i])
198 i++;
199
200 if (i < 4)
201 return s2[i] - s1[i];
202 if ((i == 4) && (isalnum(s2[i + 1]))) {
203 return 1;
204 } else {
205 /* it is not an alphanumeric character */
206 return s2[i] - s1[i];
207 }
208 return 0;
209 }
210
setup_test(int i)211 int setup_test(int i)
212 {
213 struct rlimit rl;
214 char nobody_uid[] = "nobody";
215 struct passwd *ltpuser;
216
217 switch (i) {
218 case 0:
219 ltpuser = getpwnam(nobody_uid);
220 if (seteuid(ltpuser->pw_uid) == -1) {
221 tst_brkm(TBROK, cleanup, "seteuid() failed to "
222 "change euid to %d errno = %d : %s",
223 ltpuser->pw_uid, TEST_ERRNO,
224 strerror(TEST_ERRNO));
225 return 1;
226 }
227
228 rl.rlim_max = 10;
229 rl.rlim_cur = 7;
230
231 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
232 tst_resm(TWARN | TERRNO, "setrlimit failed to set the "
233 "resource for RLIMIT_MEMLOCK to check "
234 "for mlockall() error %s\n", TC[i].edesc);
235 return 1;
236 }
237 return 0;
238 case 1:
239 rl.rlim_max = 0;
240 rl.rlim_cur = 0;
241
242 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
243 tst_resm(TWARN, "setrlimit failed to set the "
244 "resource for RLIMIT_MEMLOCK to check "
245 "for mlockall() error %s\n", TC[i].edesc);
246 return 1;
247 }
248
249 ltpuser = getpwnam(nobody_uid);
250 if (seteuid(ltpuser->pw_uid) == -1) {
251 tst_brkm(TBROK, cleanup, "seteuid() failed to "
252 "change euid to %d errno = %d : %s",
253 ltpuser->pw_uid, TEST_ERRNO,
254 strerror(TEST_ERRNO));
255 return 1;
256 }
257
258 return 0;
259 }
260 return 0;
261 }
262
cleanup_test(int i)263 void cleanup_test(int i)
264 {
265 struct rlimit rl;
266
267 switch (i) {
268 case 0:
269 case 1:
270 SAFE_SETEUID(cleanup, 0);
271
272 rl.rlim_max = -1;
273 rl.rlim_cur = -1;
274
275 if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) {
276 tst_brkm(TFAIL, cleanup,
277 "setrlimit failed to reset the "
278 "resource for RLIMIT_MEMLOCK while "
279 "checking for mlockall() error %s\n",
280 TC[i].edesc);
281 }
282 return;
283
284 }
285 }
286
287 /*
288 * cleanup() - performs all ONE TIME cleanup for this test at
289 * completion or premature exit.
290 */
cleanup(void)291 void cleanup(void)
292 {
293 return;
294 }
295