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