1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <errno.h> 6#include <fcntl.h> 7#include <limits.h> 8#include <stdalign.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <sys/stat.h> 13#include <sys/statfs.h> 14#include <sys/types.h> 15#include <time.h> 16#include <unistd.h> 17 18#include <fbl/string.h> 19#include <fbl/unique_fd.h> 20#include <lib/fzl/fdio.h> 21#include <fs-test-utils/fixture.h> 22#include <fs-test-utils/unittest.h> 23#include <fuchsia/io/c/fidl.h> 24#include <unittest/unittest.h> 25#include <zircon/device/block.h> 26#include <zircon/device/ramdisk.h> 27#include <zircon/device/vfs.h> 28#include <zircon/syscalls.h> 29 30#include <fs-management/mount.h> 31#include <fs-management/ramdisk.h> 32 33namespace { 34 35fs_test_utils::FixtureOptions PartitionOverFvmWithRamdisk() { 36 fs_test_utils::FixtureOptions options = 37 fs_test_utils::FixtureOptions::Default(DISK_FORMAT_MINFS); 38 options.use_fvm = true; 39 options.fs_format = false; 40 options.fs_mount = false; 41 return options; 42} 43 44bool CheckMountedFs(const char* path, const char* fs_name, size_t len) { 45 BEGIN_HELPER; 46 fbl::unique_fd fd(open(path, O_RDONLY | O_DIRECTORY)); 47 ASSERT_TRUE(fd); 48 49 fuchsia_io_FilesystemInfo info; 50 zx_status_t status; 51 fzl::FdioCaller caller(fbl::move(fd)); 52 ASSERT_EQ(fuchsia_io_DirectoryAdminQueryFilesystem(caller.borrow_channel(), &status, &info), 53 ZX_OK); 54 ASSERT_EQ(status, ZX_OK); 55 ASSERT_EQ(strncmp(fs_name, reinterpret_cast<char*>(info.name), strlen(fs_name)), 0); 56 ASSERT_LE(info.used_nodes, info.total_nodes, "Used nodes greater than free nodes"); 57 ASSERT_LE(info.used_bytes, info.total_bytes, "Used bytes greater than free bytes"); 58 // TODO(planders): eventually check that total/used counts are > 0 59 END_HELPER; 60} 61 62bool MountUnmountShared(size_t block_size) { 63 BEGIN_HELPER; 64 char ramdisk_path[PATH_MAX]; 65 const char* mount_path = "/tmp/mount_unmount"; 66 67 ASSERT_EQ(create_ramdisk(block_size, 1 << 16, ramdisk_path), 0); 68 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 69 ZX_OK); 70 ASSERT_EQ(mkdir(mount_path, 0666), 0); 71 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 72 int fd = open(ramdisk_path, O_RDWR); 73 ASSERT_GT(fd, 0); 74 ASSERT_EQ(mount(fd, mount_path, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 75 ZX_OK); 76 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 77 ASSERT_EQ(umount(mount_path), ZX_OK); 78 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 79 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 80 ASSERT_EQ(unlink(mount_path), 0); 81 END_HELPER; 82} 83 84bool MountUnmount() { 85 BEGIN_TEST; 86 ASSERT_TRUE(MountUnmountShared(512)); 87 END_TEST; 88} 89 90bool MountUnmountLargeBlock() { 91 BEGIN_TEST; 92 ASSERT_TRUE(MountUnmountShared(8192)); 93 END_TEST; 94} 95 96bool MountMkdirUnmount() { 97 char ramdisk_path[PATH_MAX]; 98 const char* mount_path = "/tmp/mount_mkdir_unmount"; 99 100 BEGIN_TEST; 101 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 102 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 103 ZX_OK); 104 int fd = open(ramdisk_path, O_RDWR); 105 ASSERT_GT(fd, 0); 106 mount_options_t options = default_mount_options; 107 options.create_mountpoint = true; 108 ASSERT_EQ(mount(fd, mount_path, DISK_FORMAT_MINFS, &options, launch_stdio_async), ZX_OK); 109 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 110 ASSERT_EQ(umount(mount_path), ZX_OK); 111 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 112 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 113 ASSERT_EQ(unlink(mount_path), 0); 114 END_TEST; 115} 116 117bool FmountFunmount() { 118 char ramdisk_path[PATH_MAX]; 119 const char* mount_path = "/tmp/mount_unmount"; 120 121 BEGIN_TEST; 122 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 123 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 124 ZX_OK); 125 ASSERT_EQ(mkdir(mount_path, 0666), 0); 126 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 127 int fd = open(ramdisk_path, O_RDWR); 128 ASSERT_GT(fd, 0); 129 130 int mountfd = open(mount_path, O_RDONLY | O_DIRECTORY | O_ADMIN); 131 ASSERT_GT(mountfd, 0, "Couldn't open mount point"); 132 ASSERT_EQ(fmount(fd, mountfd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 133 ZX_OK); 134 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 135 ASSERT_EQ(fumount(mountfd), ZX_OK); 136 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 137 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 138 ASSERT_EQ(close(mountfd), 0, "Couldn't close ex-mount point"); 139 ASSERT_EQ(unlink(mount_path), 0); 140 END_TEST; 141} 142 143// All "parent" filesystems attempt to mount a MinFS ramdisk under malicious 144// conditions. 145// 146// Note: For cases where "fmount" fails, we briefly sleep to allow the 147// filesystem to unmount itself and relinquish control of the block device. 148bool DoMountEvil(const char* parentfs_name, const char* mount_path) { 149 BEGIN_HELPER; 150 char ramdisk_path[PATH_MAX]; 151 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 152 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 153 ZX_OK); 154 ASSERT_EQ(mkdir(mount_path, 0666), 0); 155 156 int fd = open(ramdisk_path, O_RDWR); 157 ASSERT_GT(fd, 0); 158 159 int mountfd = open(mount_path, O_RDONLY | O_DIRECTORY | O_ADMIN); 160 ASSERT_GT(mountfd, 0, "Couldn't open mount point"); 161 162 // Everything *would* be perfect to call fmount, when suddenly... 163 ASSERT_EQ(rmdir(mount_path), 0); 164 // The directory was unlinked! We can't mount now! 165 ASSERT_EQ(fmount(fd, mountfd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 166 ZX_ERR_NOT_DIR); 167 usleep(10000); 168 ASSERT_NE(fumount(mountfd), ZX_OK); 169 ASSERT_EQ(close(mountfd), 0, "Couldn't close unlinked not-mount point"); 170 171 // Re-acquire the ramdisk mount point; it's always consumed... 172 fd = open(ramdisk_path, O_RDWR); 173 ASSERT_GT(fd, 0); 174 175 // Okay, okay, let's get a new mount path... 176 mountfd = open(mount_path, O_CREAT | O_RDWR); 177 ASSERT_GT(mountfd, 0); 178 // Wait a sec, that was a file, not a directory! We can't mount that! 179 ASSERT_EQ(fmount(fd, mountfd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 180 ZX_ERR_ACCESS_DENIED); 181 usleep(10000); 182 ASSERT_NE(fumount(mountfd), ZX_OK); 183 ASSERT_EQ(close(mountfd), 0, "Couldn't close file not-mount point"); 184 ASSERT_EQ(unlink(mount_path), 0); 185 186 // Re-acquire the ramdisk mount point again... 187 fd = open(ramdisk_path, O_RDWR); 188 ASSERT_GT(fd, 0); 189 ASSERT_EQ(mkdir(mount_path, 0666), 0); 190 // Try mounting without O_ADMIN (which is disallowed) 191 mountfd = open(mount_path, O_RDONLY | O_DIRECTORY); 192 ASSERT_GT(mountfd, 0, "Couldn't open mount point"); 193 ASSERT_EQ(fmount(fd, mountfd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 194 ZX_ERR_ACCESS_DENIED); 195 usleep(10000); 196 ASSERT_EQ(close(mountfd), 0, "Couldn't close the unpriviledged mount point"); 197 198 // Okay, fine, let's mount successfully... 199 fd = open(ramdisk_path, O_RDWR); 200 ASSERT_GT(fd, 0); 201 mountfd = open(mount_path, O_RDONLY | O_DIRECTORY | O_ADMIN); 202 ASSERT_GT(mountfd, 0, "Couldn't open mount point"); 203 ASSERT_EQ(fmount(fd, mountfd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 204 ZX_OK); 205 // Awesome, that worked. But we shouldn't be able to mount again! 206 fd = open(ramdisk_path, O_RDWR); 207 ASSERT_GT(fd, 0); 208 ASSERT_EQ(fmount(fd, mountfd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 209 ZX_ERR_BAD_STATE); 210 usleep(10000); 211 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 212 213 // Let's try removing the mount point (we shouldn't be allowed to do so) 214 ASSERT_EQ(rmdir(mount_path), -1); 215 ASSERT_EQ(errno, EBUSY); 216 217 // Let's try telling the target filesystem to shut down 218 // WITHOUT O_ADMIN 219 fbl::unique_fd badfd(open(mount_path, O_RDONLY | O_DIRECTORY)); 220 ASSERT_TRUE(badfd); 221 zx_status_t status; 222 fzl::FdioCaller caller(fbl::move(badfd)); 223 ASSERT_EQ(fuchsia_io_DirectoryAdminUnmount(caller.borrow_channel(), &status), ZX_OK); 224 ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED); 225 ASSERT_EQ(close(caller.release().release()), 0); 226 227 // Let's try unmounting the filesystem WITHOUT O_ADMIN 228 // (unpinning the remote handle from the parent FS). 229 badfd.reset(open(mount_path, O_RDONLY | O_DIRECTORY)); 230 ASSERT_TRUE(badfd); 231 zx_handle_t h; 232 caller.reset(fbl::move(badfd)); 233 ASSERT_EQ(fuchsia_io_DirectoryAdminUnmountNode(caller.borrow_channel(), &status, &h), ZX_OK); 234 ASSERT_EQ(h, ZX_HANDLE_INVALID); 235 ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED); 236 ASSERT_EQ(close(caller.release().release()), 0); 237 238 // When we unmount with an O_ADMIN handle, it should successfully detach. 239 ASSERT_EQ(fumount(mountfd), ZX_OK); 240 ASSERT_TRUE(CheckMountedFs(mount_path, parentfs_name, strlen(parentfs_name))); 241 ASSERT_EQ(close(mountfd), 0); 242 ASSERT_EQ(rmdir(mount_path), 0); 243 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 244 END_HELPER; 245} 246 247bool MountEvilMemfs() { 248 BEGIN_TEST; 249 const char* mount_path = "/tmp/mount_evil"; 250 ASSERT_TRUE(DoMountEvil("memfs", mount_path)); 251 END_TEST; 252} 253 254bool MountEvilMinfs() { 255 char ramdisk_path[PATH_MAX]; 256 257 BEGIN_TEST; 258 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 259 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 260 ZX_OK); 261 const char* parent_path = "/tmp/parent"; 262 ASSERT_EQ(mkdir(parent_path, 0666), 0); 263 int mountfd = open(parent_path, O_RDONLY | O_DIRECTORY | O_ADMIN); 264 ASSERT_GT(mountfd, 0, "Couldn't open mount point"); 265 int ramdiskfd = open(ramdisk_path, O_RDWR); 266 ASSERT_GT(ramdiskfd, 0); 267 ASSERT_EQ( 268 fmount(ramdiskfd, mountfd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 269 ZX_OK); 270 ASSERT_EQ(close(mountfd), 0); 271 272 const char* mount_path = "/tmp/parent/mount_evil"; 273 ASSERT_TRUE(DoMountEvil("minfs", mount_path)); 274 275 ASSERT_EQ(umount(parent_path), 0); 276 ASSERT_EQ(rmdir(parent_path), 0); 277 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 278 END_TEST; 279} 280 281bool UmountTestEvil() { 282 char ramdisk_path[PATH_MAX]; 283 const char* mount_path = "/tmp/umount_test_evil"; 284 285 BEGIN_TEST; 286 287 // Create a ramdisk, mount minfs 288 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 289 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 290 ZX_OK); 291 ASSERT_EQ(mkdir(mount_path, 0666), 0); 292 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 293 int fd = open(ramdisk_path, O_RDWR); 294 ASSERT_GT(fd, 0); 295 ASSERT_EQ(mount(fd, mount_path, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 296 ZX_OK); 297 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 298 299 // Try re-opening the root without O_ADMIN. We shouldn't be able to umount. 300 fbl::unique_fd weak_root_fd(open(mount_path, O_RDONLY | O_DIRECTORY)); 301 ASSERT_TRUE(weak_root_fd); 302 zx_status_t status; 303 fzl::FdioCaller caller(fbl::move(weak_root_fd)); 304 ASSERT_EQ(fuchsia_io_DirectoryAdminUnmount(caller.borrow_channel(), &status), ZX_OK); 305 ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED); 306 weak_root_fd.reset(caller.release().release()); 307 308 // Try opening a non-root directory without O_ADMIN. We shouldn't be able 309 // to umount. 310 ASSERT_EQ(mkdirat(weak_root_fd.get(), "subdir", 0666), 0); 311 fbl::unique_fd weak_subdir_fd(openat(weak_root_fd.get(), "subdir", O_RDONLY | O_DIRECTORY)); 312 ASSERT_TRUE(weak_subdir_fd); 313 caller.reset(fbl::move(weak_subdir_fd)); 314 ASSERT_EQ(fuchsia_io_DirectoryAdminUnmount(caller.borrow_channel(), &status), ZX_OK); 315 ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED); 316 317 // Try opening a new directory with O_ADMIN. It shouldn't open. 318 weak_subdir_fd.reset(openat(weak_root_fd.get(), "subdir", O_RDONLY | O_DIRECTORY | O_ADMIN)); 319 ASSERT_FALSE(weak_subdir_fd); 320 321 // Finally, umount using O_NOREMOTE and acquiring the connection 322 // that has "O_ADMIN" set. 323 ASSERT_EQ(umount(mount_path), ZX_OK); 324 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 325 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 326 ASSERT_EQ(unlink(mount_path), 0); 327 END_TEST; 328} 329 330bool DoubleMountRoot() { 331 char ramdisk_path[PATH_MAX]; 332 const char* mount_path = "/tmp/double_mount_root"; 333 334 BEGIN_TEST; 335 336 // Create a ramdisk, mount minfs 337 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 338 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 339 ZX_OK); 340 ASSERT_EQ(mkdir(mount_path, 0666), 0); 341 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 342 int fd = open(ramdisk_path, O_RDWR); 343 ASSERT_GE(fd, 0); 344 ASSERT_EQ(mount(fd, mount_path, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 345 ZX_OK); 346 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 347 348 // Create ANOTHER ramdisk, ready to be mounted... 349 // Try mounting again on top Minfs' remote root. 350 char ramdisk_path2[PATH_MAX]; 351 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path2), 0); 352 ASSERT_EQ(mkfs(ramdisk_path2, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 353 ZX_OK); 354 355 // Try mounting on the mount point (locally; should fail because something is already mounted) 356 int mount_fd = open(mount_path, O_RDONLY | O_NOREMOTE | O_ADMIN); 357 ASSERT_GE(mount_fd, 0); 358 fd = open(ramdisk_path2, O_RDWR); 359 ASSERT_GE(fd, 0); 360 ASSERT_NE(fmount(fd, mount_fd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 361 ZX_OK); 362 ASSERT_EQ(close(mount_fd), 0); 363 364 // Try mounting on the mount root (remote; should fail because MinFS doesn't allow mounting 365 // on top of the root directory). 366 mount_fd = open(mount_path, O_RDONLY | O_ADMIN); 367 ASSERT_GE(mount_fd, 0); 368 fd = open(ramdisk_path2, O_RDWR); 369 ASSERT_GE(fd, 0); 370 ASSERT_NE(fmount(fd, mount_fd, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 371 ZX_OK); 372 ASSERT_EQ(close(mount_fd), 0); 373 374 ASSERT_EQ(umount(mount_path), ZX_OK); 375 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 376 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 377 ASSERT_EQ(destroy_ramdisk(ramdisk_path2), 0); 378 ASSERT_EQ(rmdir(mount_path), 0); 379 END_TEST; 380} 381 382bool MountRemount() { 383 char ramdisk_path[PATH_MAX]; 384 const char* mount_path = "/tmp/mount_remount"; 385 386 BEGIN_TEST; 387 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 388 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 389 ZX_OK); 390 ASSERT_EQ(mkdir(mount_path, 0666), 0); 391 392 // We should still be able to mount and unmount the filesystem multiple times 393 for (size_t i = 0; i < 10; i++) { 394 int fd = open(ramdisk_path, O_RDWR); 395 ASSERT_GE(fd, 0); 396 ASSERT_EQ( 397 mount(fd, mount_path, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 398 ZX_OK); 399 ASSERT_EQ(umount(mount_path), ZX_OK); 400 } 401 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 402 ASSERT_EQ(unlink(mount_path), 0); 403 END_TEST; 404} 405 406bool MountFsck() { 407 char ramdisk_path[PATH_MAX]; 408 const char* mount_path = "/tmp/mount_fsck"; 409 410 BEGIN_TEST; 411 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 412 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 413 ZX_OK); 414 ASSERT_EQ(mkdir(mount_path, 0666), 0); 415 int fd = open(ramdisk_path, O_RDWR); 416 ASSERT_GE(fd, 0, "Could not open ramdisk device"); 417 ASSERT_EQ(mount(fd, mount_path, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 418 ZX_OK); 419 ASSERT_EQ(umount(mount_path), ZX_OK); 420 // fsck shouldn't require any user input for a newly mkfs'd filesystem 421 ASSERT_EQ(fsck(ramdisk_path, DISK_FORMAT_MINFS, &default_fsck_options, launch_stdio_sync), 422 ZX_OK); 423 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 424 ASSERT_EQ(unlink(mount_path), 0); 425 END_TEST; 426} 427 428bool MountGetDevice() { 429 char ramdisk_path[PATH_MAX]; 430 const char* mount_path = "/tmp/mount_get_device"; 431 432 BEGIN_TEST; 433 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 434 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 435 ZX_OK); 436 ASSERT_EQ(mkdir(mount_path, 0666), 0); 437 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 438 439 fbl::unique_fd mountfd(open(mount_path, O_RDONLY | O_ADMIN)); 440 ASSERT_TRUE(mountfd); 441 char device_buffer[1024]; 442 char* device_path = static_cast<char*>(device_buffer); 443 zx_status_t status; 444 size_t path_len; 445 fzl::FdioCaller caller(fbl::move(mountfd)); 446 ASSERT_EQ(fuchsia_io_DirectoryAdminGetDevicePath(caller.borrow_channel(), &status, 447 device_path, sizeof(device_buffer), 448 &path_len), ZX_OK); 449 ASSERT_EQ(status, ZX_ERR_NOT_SUPPORTED); 450 451 int fd = open(ramdisk_path, O_RDWR); 452 ASSERT_GT(fd, 0); 453 ASSERT_EQ(mount(fd, mount_path, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 454 ZX_OK); 455 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 456 457 mountfd.reset(open(mount_path, O_RDONLY | O_ADMIN)); 458 ASSERT_TRUE(mountfd); 459 caller.reset(fbl::move(mountfd)); 460 ASSERT_EQ(fuchsia_io_DirectoryAdminGetDevicePath(caller.borrow_channel(), &status, 461 device_path, sizeof(device_buffer), 462 &path_len), ZX_OK); 463 ASSERT_EQ(status, ZX_OK); 464 ASSERT_GT(path_len, 0, "Device path not found"); 465 ASSERT_EQ(strncmp(ramdisk_path, device_path, path_len), 0, "Unexpected device path"); 466 467 mountfd.reset(open(mount_path, O_RDONLY)); 468 ASSERT_TRUE(mountfd); 469 caller.reset(fbl::move(mountfd)); 470 ASSERT_EQ(fuchsia_io_DirectoryAdminGetDevicePath(caller.borrow_channel(), &status, 471 device_path, sizeof(device_buffer), 472 &path_len), ZX_OK); 473 ASSERT_EQ(status, ZX_ERR_ACCESS_DENIED); 474 475 ASSERT_EQ(umount(mount_path), ZX_OK); 476 ASSERT_TRUE(CheckMountedFs(mount_path, "memfs", strlen("memfs"))); 477 478 mountfd.reset(open(mount_path, O_RDONLY | O_ADMIN)); 479 ASSERT_TRUE(mountfd); 480 caller.reset(fbl::move(mountfd)); 481 ASSERT_EQ(fuchsia_io_DirectoryAdminGetDevicePath(caller.borrow_channel(), &status, 482 device_path, sizeof(device_buffer), 483 &path_len), ZX_OK); 484 ASSERT_EQ(status, ZX_ERR_NOT_SUPPORTED); 485 486 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 487 ASSERT_EQ(unlink(mount_path), 0); 488 END_TEST; 489} 490 491// Mounts a minfs formatted partition to the desired point. 492bool MountMinfs(int block_fd, bool read_only, const char* mount_path) { 493 BEGIN_HELPER; 494 mount_options_t options; 495 memcpy(&options, &default_mount_options, sizeof(mount_options_t)); 496 options.readonly = read_only; 497 498 ASSERT_EQ(mount(block_fd, mount_path, DISK_FORMAT_MINFS, &options, launch_stdio_async), ZX_OK); 499 ASSERT_TRUE(CheckMountedFs(mount_path, "minfs", strlen("minfs"))); 500 END_HELPER; 501} 502 503// Formats the ramdisk with minfs, and writes a small file to it. 504bool CreateTestFile(const char* ramdisk_path, const char* mount_path, const char* file_name) { 505 BEGIN_HELPER; 506 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 507 ZX_OK); 508 ASSERT_EQ(mkdir(mount_path, 0666), 0); 509 510 int fd = open(ramdisk_path, O_RDWR); 511 ASSERT_GT(fd, 0); 512 ASSERT_TRUE(MountMinfs(fd, false, mount_path)); 513 514 int root_fd = open(mount_path, O_RDONLY | O_DIRECTORY); 515 ASSERT_GE(root_fd, 0); 516 fd = openat(root_fd, file_name, O_CREAT | O_RDWR); 517 ASSERT_GE(fd, 0); 518 ASSERT_EQ(write(fd, "hello", 6), 6); 519 520 ASSERT_EQ(close(fd), 0); 521 ASSERT_EQ(close(root_fd), 0); 522 ASSERT_EQ(umount(mount_path), ZX_OK); 523 END_HELPER; 524} 525 526// Tests that setting read-only on the mount options works as expected. 527bool MountReadonly() { 528 char ramdisk_path[PATH_MAX]; 529 const char* mount_path = "/tmp/mount_readonly"; 530 const char file_name[] = "some_file"; 531 532 BEGIN_TEST; 533 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 534 ASSERT_TRUE(CreateTestFile(ramdisk_path, mount_path, file_name)); 535 536 int fd = open(ramdisk_path, O_RDWR); 537 ASSERT_GT(fd, 0); 538 539 bool read_only = true; 540 ASSERT_TRUE(MountMinfs(fd, read_only, mount_path)); 541 542 int root_fd = open(mount_path, O_RDONLY | O_DIRECTORY); 543 ASSERT_GE(root_fd, 0); 544 fd = openat(root_fd, file_name, O_CREAT | O_RDWR); 545 546 // We can no longer open the file as writable 547 ASSERT_LT(fd, 0); 548 549 // We CAN open it as readable though 550 fd = openat(root_fd, file_name, O_RDONLY); 551 ASSERT_GT(fd, 0); 552 ASSERT_LT(write(fd, "hello", 6), 0); 553 char buf[6]; 554 ASSERT_EQ(read(fd, buf, 6), 6); 555 ASSERT_EQ(memcmp(buf, "hello", 6), 0); 556 557 ASSERT_LT(renameat(root_fd, file_name, root_fd, "new_file"), 0); 558 ASSERT_LT(unlinkat(root_fd, file_name, 0), 0); 559 560 ASSERT_EQ(close(fd), 0); 561 ASSERT_EQ(close(root_fd), 0); 562 ASSERT_EQ(umount(mount_path), ZX_OK); 563 564 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 565 ASSERT_EQ(unlink(mount_path), 0); 566 567 END_TEST; 568} 569 570// Test that when a block device claims to be read-only, the filesystem is mounted as read-only. 571bool MountBlockReadonly() { 572 char ramdisk_path[PATH_MAX]; 573 const char* mount_path = "/tmp/mount_readonly"; 574 const char file_name[] = "some_file"; 575 576 BEGIN_TEST; 577 578 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 579 ASSERT_TRUE(CreateTestFile(ramdisk_path, mount_path, file_name)); 580 581 int fd = open(ramdisk_path, O_RDWR); 582 ASSERT_GT(fd, 0); 583 584 uint32_t flags = BLOCK_FLAG_READONLY; 585 ASSERT_EQ(0, ioctl_ramdisk_set_flags(fd, &flags)); 586 587 bool read_only = false; 588 ASSERT_TRUE(MountMinfs(fd, read_only, mount_path)); 589 590 // We can't modify the file. 591 int root_fd = open(mount_path, O_RDONLY | O_DIRECTORY); 592 ASSERT_GE(root_fd, 0); 593 fd = openat(root_fd, file_name, O_CREAT | O_RDWR); 594 ASSERT_LT(fd, 0); 595 596 // We can open it as read-only. 597 fd = openat(root_fd, file_name, O_RDONLY); 598 ASSERT_GT(fd, 0); 599 ASSERT_EQ(close(fd), 0); 600 ASSERT_EQ(close(root_fd), 0); 601 ASSERT_EQ(umount(mount_path), ZX_OK); 602 603 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 604 ASSERT_EQ(unlink(mount_path), 0); 605 606 END_TEST; 607} 608 609bool StatfsTest() { 610 char ramdisk_path[PATH_MAX]; 611 const char* mount_path = "/tmp/mount_unmount"; 612 613 BEGIN_TEST; 614 ASSERT_EQ(create_ramdisk(512, 1 << 16, ramdisk_path), 0); 615 ASSERT_EQ(mkfs(ramdisk_path, DISK_FORMAT_MINFS, launch_stdio_sync, &default_mkfs_options), 616 ZX_OK); 617 ASSERT_EQ(mkdir(mount_path, 0666), 0); 618 int fd = open(ramdisk_path, O_RDWR); 619 ASSERT_GT(fd, 0); 620 ASSERT_EQ(mount(fd, mount_path, DISK_FORMAT_MINFS, &default_mount_options, launch_stdio_async), 621 ZX_OK); 622 623 struct statfs stats; 624 int rc = statfs("", &stats); 625 int err = errno; 626 ASSERT_EQ(rc, -1); 627 ASSERT_EQ(err, ENOENT); 628 629 rc = statfs(mount_path, &stats); 630 ASSERT_EQ(rc, 0); 631 632 // Verify that at least some values make sense, without making the test too brittle. 633 ASSERT_EQ(stats.f_type, VFS_TYPE_MINFS); 634 ASSERT_NE(stats.f_fsid.__val[0] | stats.f_fsid.__val[1], 0); 635 ASSERT_EQ(stats.f_bsize, 8192u); 636 ASSERT_EQ(stats.f_namelen, 255u); 637 ASSERT_GT(stats.f_bavail, 0u); 638 ASSERT_GT(stats.f_ffree, 0u); 639 640 ASSERT_EQ(umount(mount_path), ZX_OK); 641 ASSERT_EQ(destroy_ramdisk(ramdisk_path), 0); 642 ASSERT_EQ(unlink(mount_path), 0); 643 END_TEST; 644} 645 646bool GetPartitionSliceCount(int partition_fd, size_t* out_count) { 647 BEGIN_HELPER; 648 649 fvm_info_t fvm_info; 650 ASSERT_GE(ioctl_block_fvm_query(partition_fd, &fvm_info), ZX_OK); 651 652 query_request_t request; 653 query_response_t response; 654 memset(&request, 0, sizeof(request)); 655 memset(&response, 0, sizeof(response)); 656 request.count = 1; 657 658 size_t allocated_slices = 0; 659 size_t end = 0; 660 for (size_t curr_slice = 0; curr_slice < fvm_info.vslice_count; curr_slice = end) { 661 request.vslice_start[0] = curr_slice; 662 ASSERT_GE(ioctl_block_fvm_vslice_query(partition_fd, &request, &response), ZX_OK); 663 end = curr_slice + response.vslice_range[0].count; 664 if (response.vslice_range[0].allocated) { 665 allocated_slices += response.vslice_range[0].count; 666 } 667 } 668 *out_count = allocated_slices; 669 END_HELPER; 670} 671 672// Reformat the partition using a number of slices and verify that there are as many slices as 673// originally pre-allocated. 674bool MkfsMinfsWithMinFvmSlices(fs_test_utils::Fixture* fixture) { 675 BEGIN_TEST; 676 mkfs_options_t options = default_mkfs_options; 677 size_t base_slices = 0; 678 ASSERT_OK( 679 mkfs(fixture->partition_path().c_str(), DISK_FORMAT_MINFS, launch_stdio_sync, 680 &default_mkfs_options)); 681 fbl::unique_fd partition_fd(open(fixture->partition_path().c_str(), O_RDONLY)); 682 ASSERT_TRUE(partition_fd); 683 ASSERT_TRUE(GetPartitionSliceCount(partition_fd.get(), &base_slices)); 684 options.fvm_data_slices += 10; 685 686 ASSERT_TRUE(partition_fd); 687 688 ASSERT_OK( 689 mkfs(fixture->partition_path().c_str(), DISK_FORMAT_MINFS, launch_stdio_sync, &options)); 690 size_t allocated_slices = 0; 691 ASSERT_TRUE(GetPartitionSliceCount(partition_fd.get(), &allocated_slices)); 692 EXPECT_GE(allocated_slices, base_slices + 10); 693 694 disk_format_t actual_format = detect_disk_format(partition_fd.get()); 695 ASSERT_EQ(actual_format, DISK_FORMAT_MINFS); 696 END_TEST; 697} 698 699} // namespace 700 701BEGIN_TEST_CASE(fs_management_tests) 702RUN_TEST_MEDIUM(MountUnmount) 703RUN_TEST_MEDIUM(MountUnmountLargeBlock) 704RUN_TEST_MEDIUM(MountMkdirUnmount) 705RUN_TEST_MEDIUM(FmountFunmount) 706RUN_TEST_MEDIUM(MountEvilMemfs) 707RUN_TEST_MEDIUM(MountEvilMinfs) 708RUN_TEST_MEDIUM(UmountTestEvil) 709RUN_TEST_MEDIUM(DoubleMountRoot) 710RUN_TEST_MEDIUM(MountRemount) 711RUN_TEST_MEDIUM(MountFsck) 712RUN_TEST_MEDIUM(MountGetDevice) 713RUN_TEST_MEDIUM(MountReadonly) 714RUN_TEST_MEDIUM(MountBlockReadonly) 715RUN_TEST_MEDIUM(StatfsTest) 716END_TEST_CASE(fs_management_tests) 717 718BEGIN_FS_TEST_CASE(fs_management_mkfs_tests, PartitionOverFvmWithRamdisk) 719RUN_FS_TEST_F(MkfsMinfsWithMinFvmSlices) 720END_FS_TEST_CASE(fs_management_mkfs_tests, PartitionOverFvmWithRamdisk) 721 722int main(int argc, char** argv) { 723 return fs_test_utils::RunWithMemFs( 724 [argc, argv]() { return unittest_run_all_tests(argc, argv) ? 0 : -1; }); 725} 726