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 		    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