diff --git a/Base/usr/share/man/man2/mount.md b/Base/usr/share/man/man2/mount.md index d9bd088e6a..df377bb8f4 100644 --- a/Base/usr/share/man/man2/mount.md +++ b/Base/usr/share/man/man2/mount.md @@ -34,6 +34,7 @@ The following `flags` are supported: * `MS_NOSUID`: Ignore set-user-id bits on executables from this file system. * `MS_BIND`: Perform a bind-mount (see below). * `MS_RDONLY`: Mount the filesystem read-only. +* `MS_REMOUNT`: Remount an already mounted filesystem (see below). These flags can be used as a security measure to limit the possible abuses of the newly mounted file system. @@ -45,6 +46,36 @@ performed instead. In this case, the file or directory specified by `source_fd` is overlayed over `target` — the target appears to be replaced by a copy of the source. This can be used as an alternative to symlinks or hardlinks. +Each bind mount has its own set of flags, independent of the others or the +original file system. It is possible to bind-mount a file or directory over +itself, which may be useful for changing mount flags for a part of a filesystem. + +### Remounting + +If `MS_REMOUNT` is specified in `flags`, `source_fd` and `fs_type` are ignored, +and a remount is performed instead. `target` must point to an existing mount +point. The mount flags for that mount point are reset to `flags` (except the +`MS_REMOUNT` flag itself, which is stripped from the value). + +Note that remounting a file system will only affect future operations with the +file system, not any already opened files. For example, if you open a directory +on a filesystem that's mounted with `MS_NODEV`, then remount the filesystem to +allow opening devices, attempts to open a devices relative to the directory file +descriptor (such as by using `openat()`) will still fail. + +In particular, current working directory and root directory of any already +running processes behave the same way, and don't automatically "pick up" changes +in mount flags of the underlying file system. To "refresh" the working directory +to use the new mount flags after remounting a filesystem, a process can call +`chdir()` with the path to the same directory. + +Similarly, to change the mount flags used by the root directory, a process can +call [`chroot_with_mount_flags`(2)](chroot.md), specifying a single slash (`/`) +as the path along with the desired flags. While is's possible to remount the +root filesystem using `MS_REMOUNT`, it would only have a noticeable effect if +the kernel was to launch more userspace processes directly, the way it does +launch the initial userspace process. + ## Errors * `EFAULT`: The `fs_type` or `target` are invalid strings. diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index df3000e38e..29766e3557 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -91,6 +91,20 @@ KResult VFS::bind_mount(Custody& source, Custody& mount_point, int flags) return KSuccess; } +KResult VFS::remount(Custody& mount_point, int new_flags) +{ + LOCKER(m_lock); + + dbg() << "VFS: Remounting " << mount_point.absolute_path(); + + Mount* mount = find_mount_for_guest(mount_point.inode().identifier()); + if (!mount) + return KResult(-ENODEV); + + mount->set_flags(new_flags); + return KSuccess; +} + KResult VFS::unmount(InodeIdentifier guest_inode_id) { LOCKER(m_lock); diff --git a/Kernel/FileSystem/VirtualFileSystem.h b/Kernel/FileSystem/VirtualFileSystem.h index 4ea33b3d58..ad7cfa5d85 100644 --- a/Kernel/FileSystem/VirtualFileSystem.h +++ b/Kernel/FileSystem/VirtualFileSystem.h @@ -66,6 +66,7 @@ public: String absolute_path() const; int flags() const { return m_flags; } + void set_flags(int flags) { m_flags = flags; } private: InodeIdentifier m_host; @@ -83,6 +84,7 @@ public: bool mount_root(FS&); KResult mount(FS&, Custody& mount_point, int flags); KResult bind_mount(Custody& source, Custody& mount_point, int flags); + KResult remount(Custody& mount_point, int new_flags); KResult unmount(InodeIdentifier guest_inode_id); KResultOr> open(StringView path, int options, mode_t mode, Custody& base, Optional = {}); diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index cd11dd1767..bb9404df05 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -4103,6 +4103,11 @@ int Process::sys$mount(const Syscall::SC_mount_params* user_params) auto& target_custody = custody_or_error.value(); + if (params.flags & MS_REMOUNT) { + // We're not creating a new mount, we're updating an existing one! + return VFS::the().remount(target_custody, params.flags & ~MS_REMOUNT); + } + if (params.flags & MS_BIND) { // We're doing a bind mount. if (description.is_null()) diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h index 6f57ec83b8..f74c28e402 100644 --- a/Kernel/UnixTypes.h +++ b/Kernel/UnixTypes.h @@ -53,6 +53,7 @@ #define MS_NOSUID (1 << 2) #define MS_BIND (1 << 3) #define MS_RDONLY (1 << 4) +#define MS_REMOUNT (1 << 5) #define PERF_EVENT_MALLOC 1 #define PERF_EVENT_FREE 2 diff --git a/Libraries/LibC/unistd.h b/Libraries/LibC/unistd.h index f7c86390d1..86dd1c529f 100644 --- a/Libraries/LibC/unistd.h +++ b/Libraries/LibC/unistd.h @@ -154,6 +154,7 @@ enum { #define MS_NOSUID (1 << 2) #define MS_BIND (1 << 3) #define MS_RDONLY (1 << 4) +#define MS_REMOUNT (1 << 5) /* * We aren't fully compliant (don't support policies, and don't have a wide diff --git a/Userland/chroot.cpp b/Userland/chroot.cpp index d658fa80ef..a8e4c13a64 100644 --- a/Userland/chroot.cpp +++ b/Userland/chroot.cpp @@ -59,6 +59,8 @@ int main(int argc, char** argv) flags |= MS_NOSUID; else if (part == "ro") flags |= MS_RDONLY; + else if (part == "remount") + flags |= MS_REMOUNT; else if (part == "bind") fprintf(stderr, "Ignoring -o bind, as it doesn't make sense for chroot\n"); else diff --git a/Userland/mount.cpp b/Userland/mount.cpp index 35085a0f58..da75ea5e9a 100644 --- a/Userland/mount.cpp +++ b/Userland/mount.cpp @@ -52,6 +52,8 @@ int parse_options(const StringView& options) flags |= MS_BIND; else if (part == "ro") flags |= MS_RDONLY; + else if (part == "remount") + flags |= MS_REMOUNT; else fprintf(stderr, "Ignoring invalid option: %s\n", part.to_string().characters()); }