/* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the GNU General Public License along * with this program; if not, write the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ /* * DESCRIPTION * Check for basic mount(2) system call flags. * * Verify that mount(2) syscall passes for each flag setting and validate * the flags * 1) MS_RDONLY - mount read-only. * 2) MS_NODEV - disallow access to device special files. * 3) MS_NOEXEC - disallow program execution. * 4) MS_SYNCHRONOUS - writes are synced at once. * 5) MS_REMOUNT - alter flags of a mounted FS. * 6) MS_NOSUID - ignore suid and sgid bits. * 7) MS_NOATIME - do not update access times. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include "test.h" #include "safe_macros.h" static void setup(void); static void cleanup(void); static int test_rwflag(int, int); char *TCID = "mount03"; int TST_TOTAL = 7; #define TEMP_FILE "temp_file" #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ S_IXGRP|S_IROTH|S_IXOTH) #define SUID_MODE (S_ISUID|S_IRUSR|S_IXUSR|S_IXGRP|S_IXOTH) static const char mntpoint[] = "mntpoint"; static const char *device; static const char *fs_type; static int fildes; static char write_buffer[BUFSIZ]; static char read_buffer[BUFSIZ]; static char path_name[PATH_MAX]; static char file[PATH_MAX]; long rwflags[] = { MS_RDONLY, MS_NODEV, MS_NOEXEC, MS_SYNCHRONOUS, MS_RDONLY, MS_NOSUID, MS_NOATIME, }; int main(int argc, char *argv[]) { int lc, i; tst_parse_opts(argc, argv, NULL, NULL); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; for (i = 0; i < TST_TOTAL; ++i) { TEST(mount(device, mntpoint, fs_type, rwflags[i], NULL)); if (TEST_RETURN != 0) { tst_resm(TFAIL | TTERRNO, "mount(2) failed"); continue; } /* Validate the rwflag */ if (test_rwflag(i, lc) == 1) tst_resm(TFAIL, "mount(2) failed while" " validating %ld", rwflags[i]); else tst_resm(TPASS, "mount(2) passed with " "rwflag = %ld", rwflags[i]); TEST(tst_umount(mntpoint)); if (TEST_RETURN != 0) tst_brkm(TBROK | TTERRNO, cleanup, "umount(2) failed for %s", mntpoint); } } cleanup(); tst_exit(); } /* * test_rwflag(int i, int cnt) * Validate the mount system call for rwflags. */ int test_rwflag(int i, int cnt) { int ret, fd, pid, status; char nobody_uid[] = "nobody"; time_t atime; struct passwd *ltpuser; struct stat file_stat; char readbuf[20]; switch (i) { case 0: /* Validate MS_RDONLY flag of mount call */ snprintf(file, PATH_MAX, "%stmp", path_name); fd = open(file, O_CREAT | O_RDWR, S_IRWXU); if (fd == -1) { if (errno == EROFS) { return 0; } else { tst_resm(TWARN | TERRNO, "open didn't fail with EROFS"); return 1; } } close(fd); return 1; case 1: /* Validate MS_NODEV flag of mount call */ snprintf(file, PATH_MAX, "%smynod_%d_%d", path_name, getpid(), cnt); if (mknod(file, S_IFBLK | 0777, 0) == 0) { fd = open(file, O_RDWR, S_IRWXU); if (fd == -1) { if (errno == EACCES) { return 0; } else { tst_resm(TWARN | TERRNO, "open didn't fail with EACCES"); return 1; } } close(fd); } else { tst_resm(TWARN | TERRNO, "mknod(2) failed to create %s", file); return 1; } return 1; case 2: /* Validate MS_NOEXEC flag of mount call */ snprintf(file, PATH_MAX, "%stmp1", path_name); fd = open(file, O_CREAT | O_RDWR, S_IRWXU); if (fd == -1) { tst_resm(TWARN | TERRNO, "opening %s failed", file); } else { close(fd); ret = execlp(file, basename(file), NULL); if ((ret == -1) && (errno == EACCES)) return 0; } return 1; case 3: /* * Validate MS_SYNCHRONOUS flag of mount call. * Copy some data into data buffer. */ strcpy(write_buffer, "abcdefghijklmnopqrstuvwxyz"); /* Creat a temporary file under above directory */ snprintf(file, PATH_MAX, "%s%s", path_name, TEMP_FILE); fildes = open(file, O_RDWR | O_CREAT, FILE_MODE); if (fildes == -1) { tst_resm(TWARN | TERRNO, "open(%s, O_RDWR|O_CREAT, %#o) failed", file, FILE_MODE); return 1; } /* Write the buffer data into file */ if (write(fildes, write_buffer, strlen(write_buffer)) != strlen(write_buffer)) { tst_resm(TWARN | TERRNO, "writing to %s failed", file); close(fildes); return 1; } /* Set the file ptr to b'nning of file */ if (lseek(fildes, 0, SEEK_SET) < 0) { tst_resm(TWARN, "lseek() failed on %s, error=" " %d", file, errno); close(fildes); return 1; } /* Read the contents of file */ if (read(fildes, read_buffer, sizeof(read_buffer)) > 0) { if (strcmp(read_buffer, write_buffer)) { tst_resm(TWARN, "Data read from %s and written " "mismatch", file); close(fildes); return 1; } else { close(fildes); return 0; } } else { tst_resm(TWARN | TERRNO, "read() Fails on %s", file); close(fildes); return 1; } case 4: /* Validate MS_REMOUNT flag of mount call */ TEST(mount(device, mntpoint, fs_type, MS_REMOUNT, NULL)); if (TEST_RETURN != 0) { tst_resm(TWARN | TTERRNO, "mount(2) failed to remount"); return 1; } else { snprintf(file, PATH_MAX, "%stmp2", path_name); fd = open(file, O_CREAT | O_RDWR, S_IRWXU); if (fd == -1) { tst_resm(TWARN, "open(%s) on readonly " "filesystem passed", file); return 1; } else { close(fd); return 0; } } case 5: /* Validate MS_NOSUID flag of mount call */ snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name); pid = fork(); switch (pid) { case -1: tst_resm(TBROK | TERRNO, "fork failed"); return 1; case 0: ltpuser = getpwnam(nobody_uid); if (setreuid(ltpuser->pw_uid, ltpuser->pw_uid) == -1) tst_resm(TWARN | TERRNO, "seteuid() failed to change euid to %d", ltpuser->pw_uid); execlp(file, basename(file), NULL); exit(1); default: waitpid(pid, &status, 0); if (WIFEXITED(status)) { /* reset the setup_uid */ if (status) return 0; } return 1; } case 6: /* Validate MS_NOATIME flag of mount call */ snprintf(file, PATH_MAX, "%satime", path_name); fd = open(file, O_CREAT | O_RDWR, S_IRWXU); if (fd == -1) { tst_resm(TWARN | TERRNO, "opening %s failed", file); return 1; } if (write(fd, "TEST_MS_NOATIME", 15) != 15) { tst_resm(TWARN | TERRNO, "write %s failed", file); close(fd); return 1; } if (fstat(fd, &file_stat) == -1) { tst_resm(TWARN | TERRNO, "stat %s failed #1", file); close(fd); return 1; } atime = file_stat.st_atime; sleep(1); if (read(fd, readbuf, sizeof(readbuf)) == -1) { tst_resm(TWARN | TERRNO, "read %s failed", file); close(fd); return 1; } if (fstat(fd, &file_stat) == -1) { tst_resm(TWARN | TERRNO, "stat %s failed #2", file); close(fd); return 1; } close(fd); if (file_stat.st_atime != atime) { tst_resm(TWARN, "access time is updated"); return 1; } return 0; } return 0; } static void setup(void) { char path[PATH_MAX]; struct stat file_stat; tst_sig(FORK, DEF_HANDLER, cleanup); tst_require_root(); tst_tmpdir(); fs_type = tst_dev_fs_type(); device = tst_acquire_device(cleanup); if (!device) tst_brkm(TCONF, cleanup, "Failed to obtain block device"); tst_mkfs(cleanup, device, fs_type, NULL, NULL); SAFE_MKDIR(cleanup, mntpoint, DIR_MODE); if (getcwd(path_name, sizeof(path_name)) == NULL) tst_brkm(TBROK, cleanup, "getcwd failed"); if (chmod(path_name, DIR_MODE) != 0) tst_brkm(TBROK, cleanup, "chmod(%s, %#o) failed", path_name, DIR_MODE); strncpy(path, path_name, PATH_MAX); snprintf(path_name, PATH_MAX, "%s/%s/", path, mntpoint); SAFE_MOUNT(cleanup, device, mntpoint, fs_type, 0, NULL); TST_RESOURCE_COPY(cleanup, "mount03_setuid_test", path_name); snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name); SAFE_STAT(cleanup, file, &file_stat); if (file_stat.st_mode != SUID_MODE && chmod(file, SUID_MODE) < 0) tst_brkm(TBROK, cleanup, "setuid for setuid_test failed"); SAFE_UMOUNT(cleanup, mntpoint); TEST_PAUSE; } static void cleanup(void) { if (device) tst_release_device(device); tst_rmdir(); }