1 /*
2 * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved.
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 * DESCRIPTION
20 * Check for basic mount(2) system call flags.
21 *
22 * Verify that mount(2) syscall passes for each flag setting and validate
23 * the flags
24 * 1) MS_RDONLY - mount read-only.
25 * 2) MS_NODEV - disallow access to device special files.
26 * 3) MS_NOEXEC - disallow program execution.
27 * 4) MS_SYNCHRONOUS - writes are synced at once.
28 * 5) MS_REMOUNT - alter flags of a mounted FS.
29 * 6) MS_NOSUID - ignore suid and sgid bits.
30 * 7) MS_NOATIME - do not update access times.
31 */
32
33 #ifndef _GNU_SOURCE
34 #define _GNU_SOURCE
35 #endif
36
37 #include <sys/types.h>
38 #include <sys/mount.h>
39 #include <sys/stat.h>
40 #include <sys/wait.h>
41 #include <assert.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <pwd.h>
45 #include <unistd.h>
46
47 #include "test.h"
48 #include "safe_macros.h"
49
50 static void setup(void);
51 static void cleanup(void);
52 static int test_rwflag(int, int);
53
54 char *TCID = "mount03";
55 int TST_TOTAL = 7;
56
57 #define TEMP_FILE "temp_file"
58 #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
59 #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \
60 S_IXGRP|S_IROTH|S_IXOTH)
61 #define SUID_MODE (S_ISUID|S_IRUSR|S_IXUSR|S_IXGRP|S_IXOTH)
62
63 static const char mntpoint[] = "mntpoint";
64 static const char *device;
65 static const char *fs_type;
66 static int fildes;
67
68 static char write_buffer[BUFSIZ];
69 static char read_buffer[BUFSIZ];
70 static char path_name[PATH_MAX];
71 static char file[PATH_MAX];
72
73 long rwflags[] = {
74 MS_RDONLY,
75 MS_NODEV,
76 MS_NOEXEC,
77 MS_SYNCHRONOUS,
78 MS_RDONLY,
79 MS_NOSUID,
80 MS_NOATIME,
81 };
82
main(int argc,char * argv[])83 int main(int argc, char *argv[])
84 {
85 int lc, i;
86
87 tst_parse_opts(argc, argv, NULL, NULL);
88
89 setup();
90
91 for (lc = 0; TEST_LOOPING(lc); lc++) {
92
93 tst_count = 0;
94
95 for (i = 0; i < TST_TOTAL; ++i) {
96
97 TEST(mount(device, mntpoint, fs_type, rwflags[i],
98 NULL));
99
100 if (TEST_RETURN != 0) {
101 tst_resm(TFAIL | TTERRNO, "mount(2) failed");
102 continue;
103 }
104
105 /* Validate the rwflag */
106 if (test_rwflag(i, lc) == 1)
107 tst_resm(TFAIL, "mount(2) failed while"
108 " validating %ld", rwflags[i]);
109 else
110 tst_resm(TPASS, "mount(2) passed with "
111 "rwflag = %ld", rwflags[i]);
112
113 TEST(tst_umount(mntpoint));
114 if (TEST_RETURN != 0)
115 tst_brkm(TBROK | TTERRNO, cleanup,
116 "umount(2) failed for %s", mntpoint);
117 }
118 }
119
120 cleanup();
121 tst_exit();
122 }
123
124 /*
125 * test_rwflag(int i, int cnt)
126 * Validate the mount system call for rwflags.
127 */
test_rwflag(int i,int cnt)128 int test_rwflag(int i, int cnt)
129 {
130 int ret, fd, pid, status;
131 char nobody_uid[] = "nobody";
132 time_t atime;
133 struct passwd *ltpuser;
134 struct stat file_stat;
135 char readbuf[20];
136
137 switch (i) {
138 case 0:
139 /* Validate MS_RDONLY flag of mount call */
140
141 snprintf(file, PATH_MAX, "%stmp", path_name);
142 fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
143 if (fd == -1) {
144 if (errno == EROFS) {
145 return 0;
146 } else {
147 tst_resm(TWARN | TERRNO,
148 "open didn't fail with EROFS");
149 return 1;
150 }
151 }
152 close(fd);
153 return 1;
154 case 1:
155 /* Validate MS_NODEV flag of mount call */
156
157 snprintf(file, PATH_MAX, "%smynod_%d_%d", path_name, getpid(),
158 cnt);
159 if (mknod(file, S_IFBLK | 0777, 0) == 0) {
160 fd = open(file, O_RDWR, S_IRWXU);
161 if (fd == -1) {
162 if (errno == EACCES) {
163 return 0;
164 } else {
165 tst_resm(TWARN | TERRNO,
166 "open didn't fail with EACCES");
167 return 1;
168 }
169 }
170 close(fd);
171 } else {
172 tst_resm(TWARN | TERRNO, "mknod(2) failed to create %s",
173 file);
174 return 1;
175 }
176 return 1;
177 case 2:
178 /* Validate MS_NOEXEC flag of mount call */
179
180 snprintf(file, PATH_MAX, "%stmp1", path_name);
181 fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
182 if (fd == -1) {
183 tst_resm(TWARN | TERRNO, "opening %s failed", file);
184 } else {
185 close(fd);
186 ret = execlp(file, basename(file), NULL);
187 if ((ret == -1) && (errno == EACCES))
188 return 0;
189 }
190 return 1;
191 case 3:
192 /*
193 * Validate MS_SYNCHRONOUS flag of mount call.
194 * Copy some data into data buffer.
195 */
196
197 strcpy(write_buffer, "abcdefghijklmnopqrstuvwxyz");
198
199 /* Creat a temporary file under above directory */
200 snprintf(file, PATH_MAX, "%s%s", path_name, TEMP_FILE);
201 fildes = open(file, O_RDWR | O_CREAT, FILE_MODE);
202 if (fildes == -1) {
203 tst_resm(TWARN | TERRNO,
204 "open(%s, O_RDWR|O_CREAT, %#o) failed",
205 file, FILE_MODE);
206 return 1;
207 }
208
209 /* Write the buffer data into file */
210 if (write(fildes, write_buffer, strlen(write_buffer)) !=
211 (long)strlen(write_buffer)) {
212 tst_resm(TWARN | TERRNO, "writing to %s failed", file);
213 close(fildes);
214 return 1;
215 }
216
217 /* Set the file ptr to b'nning of file */
218 if (lseek(fildes, 0, SEEK_SET) < 0) {
219 tst_resm(TWARN, "lseek() failed on %s, error="
220 " %d", file, errno);
221 close(fildes);
222 return 1;
223 }
224
225 /* Read the contents of file */
226 if (read(fildes, read_buffer, sizeof(read_buffer)) > 0) {
227 if (strcmp(read_buffer, write_buffer)) {
228 tst_resm(TWARN, "Data read from %s and written "
229 "mismatch", file);
230 close(fildes);
231 return 1;
232 } else {
233 close(fildes);
234 return 0;
235 }
236 } else {
237 tst_resm(TWARN | TERRNO, "read() Fails on %s", file);
238 close(fildes);
239 return 1;
240 }
241
242 case 4:
243 /* Validate MS_REMOUNT flag of mount call */
244
245 TEST(mount(device, mntpoint, fs_type, MS_REMOUNT, NULL));
246 if (TEST_RETURN != 0) {
247 tst_resm(TWARN | TTERRNO, "mount(2) failed to remount");
248 return 1;
249 } else {
250 snprintf(file, PATH_MAX, "%stmp2", path_name);
251 fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
252 if (fd == -1) {
253 tst_resm(TWARN, "open(%s) on readonly "
254 "filesystem passed", file);
255 return 1;
256 } else {
257 close(fd);
258 return 0;
259 }
260 }
261 case 5:
262 /* Validate MS_NOSUID flag of mount call */
263
264 snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name);
265
266 pid = fork();
267 switch (pid) {
268 case -1:
269 tst_resm(TBROK | TERRNO, "fork failed");
270 return 1;
271 case 0:
272 ltpuser = getpwnam(nobody_uid);
273 if (setreuid(ltpuser->pw_uid, ltpuser->pw_uid) == -1)
274 tst_resm(TWARN | TERRNO,
275 "seteuid() failed to change euid to %d",
276 ltpuser->pw_uid);
277
278 execlp(file, basename(file), NULL);
279 exit(1);
280 default:
281 waitpid(pid, &status, 0);
282 if (WIFEXITED(status)) {
283 /* reset the setup_uid */
284 if (status)
285 return 0;
286 }
287 return 1;
288 }
289 case 6:
290 /* Validate MS_NOATIME flag of mount call */
291
292 snprintf(file, PATH_MAX, "%satime", path_name);
293 fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
294 if (fd == -1) {
295 tst_resm(TWARN | TERRNO, "opening %s failed", file);
296 return 1;
297 }
298
299 if (write(fd, "TEST_MS_NOATIME", 15) != 15) {
300 tst_resm(TWARN | TERRNO, "write %s failed", file);
301 close(fd);
302 return 1;
303 }
304
305 if (fstat(fd, &file_stat) == -1) {
306 tst_resm(TWARN | TERRNO, "stat %s failed #1", file);
307 close(fd);
308 return 1;
309 }
310
311 atime = file_stat.st_atime;
312
313 sleep(1);
314
315 if (read(fd, readbuf, sizeof(readbuf)) == -1) {
316 tst_resm(TWARN | TERRNO, "read %s failed", file);
317 close(fd);
318 return 1;
319 }
320
321 if (fstat(fd, &file_stat) == -1) {
322 tst_resm(TWARN | TERRNO, "stat %s failed #2", file);
323 close(fd);
324 return 1;
325 }
326 close(fd);
327
328 if (file_stat.st_atime != atime) {
329 tst_resm(TWARN, "access time is updated");
330 return 1;
331 }
332 return 0;
333 }
334 return 0;
335 }
336
setup(void)337 static void setup(void)
338 {
339 char path[PATH_MAX];
340 struct stat file_stat;
341
342 tst_sig(FORK, DEF_HANDLER, cleanup);
343
344 tst_require_root();
345
346 tst_tmpdir();
347
348 fs_type = tst_dev_fs_type();
349 device = tst_acquire_device(cleanup);
350
351 if (!device)
352 tst_brkm(TCONF, cleanup, "Failed to obtain block device");
353
354 tst_mkfs(cleanup, device, fs_type, NULL, NULL);
355
356 SAFE_MKDIR(cleanup, mntpoint, DIR_MODE);
357
358 if (getcwd(path_name, sizeof(path_name)) == NULL)
359 tst_brkm(TBROK, cleanup, "getcwd failed");
360
361 if (chmod(path_name, DIR_MODE) != 0)
362 tst_brkm(TBROK, cleanup, "chmod(%s, %#o) failed",
363 path_name, DIR_MODE);
364
365 strncpy(path, path_name, PATH_MAX);
366 snprintf(path_name, PATH_MAX, "%s/%s/", path, mntpoint);
367
368 SAFE_MOUNT(cleanup, device, mntpoint, fs_type, 0, NULL);
369 TST_RESOURCE_COPY(cleanup, "mount03_setuid_test", path_name);
370
371 snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name);
372 SAFE_STAT(cleanup, file, &file_stat);
373
374 if (file_stat.st_mode != SUID_MODE &&
375 chmod(file, SUID_MODE) < 0)
376 tst_brkm(TBROK, cleanup,
377 "setuid for setuid_test failed");
378 SAFE_UMOUNT(cleanup, mntpoint);
379
380 TEST_PAUSE;
381 }
382
cleanup(void)383 static void cleanup(void)
384 {
385 if (device)
386 tst_release_device(device);
387
388 tst_rmdir();
389 }
390