Home | History | Annotate | Download | only in mount
      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 
     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  */
    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, "%ssetuid_test", path_name);
    265 		SAFE_FILE_PRINTF(cleanup, file, "TEST FILE");
    266 
    267 		if (stat(file, &file_stat) < 0)
    268 			tst_brkm(TBROK, cleanup, "stat for setuid_test failed");
    269 
    270 		if (file_stat.st_mode != SUID_MODE &&
    271 		    chmod(file, SUID_MODE) < 0)
    272 			tst_brkm(TBROK, cleanup,
    273 				 "setuid for setuid_test failed");
    274 
    275 		pid = fork();
    276 		switch (pid) {
    277 		case -1:
    278 			tst_resm(TBROK | TERRNO, "fork failed");
    279 			return 1;
    280 		case 0:
    281 			ltpuser = getpwnam(nobody_uid);
    282 			if (setreuid(ltpuser->pw_uid, ltpuser->pw_uid) == -1)
    283 				tst_resm(TWARN | TERRNO,
    284 					 "seteuid() failed to change euid to %d",
    285 					 ltpuser->pw_uid);
    286 
    287 			execlp(file, basename(file), NULL);
    288 			exit(1);
    289 		default:
    290 			waitpid(pid, &status, 0);
    291 			if (WIFEXITED(status)) {
    292 				/* reset the setup_uid */
    293 				if (status)
    294 					return 0;
    295 				else
    296 					return 1;
    297 			}
    298 		}
    299 	case 6:
    300 		/* Validate MS_NOATIME flag of mount call */
    301 
    302 		snprintf(file, PATH_MAX, "%satime", path_name);
    303 		fd = open(file, O_CREAT | O_RDWR, S_IRWXU);
    304 		if (fd == -1) {
    305 			tst_resm(TWARN | TERRNO, "opening %s failed", file);
    306 			return 1;
    307 		}
    308 
    309 		if (write(fd, "TEST_MS_NOATIME", 15) != 15) {
    310 			tst_resm(TWARN | TERRNO, "write %s failed", file);
    311 			close(fd);
    312 			return 1;
    313 		}
    314 
    315 		if (fstat(fd, &file_stat) == -1) {
    316 			tst_resm(TWARN | TERRNO, "stat %s failed #1", file);
    317 			close(fd);
    318 			return 1;
    319 		}
    320 
    321 		atime = file_stat.st_atime;
    322 
    323 		sleep(1);
    324 
    325 		if (read(fd, readbuf, sizeof(readbuf)) == -1) {
    326 			tst_resm(TWARN | TERRNO, "read %s failed", file);
    327 			close(fd);
    328 			return 1;
    329 		}
    330 
    331 		if (fstat(fd, &file_stat) == -1) {
    332 			tst_resm(TWARN | TERRNO, "stat %s failed #2", file);
    333 			close(fd);
    334 			return 1;
    335 		}
    336 		close(fd);
    337 
    338 		if (file_stat.st_atime != atime) {
    339 			tst_resm(TWARN, "access time is updated");
    340 			return 1;
    341 		}
    342 		return 0;
    343 	}
    344 	return 0;
    345 }
    346 
    347 static void setup(void)
    348 {
    349 	char path[PATH_MAX];
    350 
    351 	tst_sig(FORK, DEF_HANDLER, cleanup);
    352 
    353 	tst_require_root();
    354 
    355 	tst_tmpdir();
    356 
    357 	fs_type = tst_dev_fs_type();
    358 	device = tst_acquire_device(cleanup);
    359 
    360 	if (!device)
    361 		tst_brkm(TCONF, cleanup, "Failed to obtain block device");
    362 
    363 	tst_mkfs(cleanup, device, fs_type, NULL, NULL);
    364 
    365 	SAFE_MKDIR(cleanup, mntpoint, DIR_MODE);
    366 
    367 	if (getcwd(path_name, sizeof(path_name)) == NULL)
    368 		tst_brkm(TBROK, cleanup, "getcwd failed");
    369 
    370 	if (chmod(path_name, DIR_MODE) != 0)
    371 		tst_brkm(TBROK, cleanup, "chmod(%s, %#o) failed",
    372 			 path_name, DIR_MODE);
    373 
    374 	strncpy(path, path_name, PATH_MAX);
    375 	snprintf(path_name, PATH_MAX, "%s/%s/", path, mntpoint);
    376 
    377 	TEST_PAUSE;
    378 }
    379 
    380 static void cleanup(void)
    381 {
    382 	if (device)
    383 		tst_release_device(device);
    384 
    385 	tst_rmdir();
    386 }
    387