Kernel+Userland: Support remounting filesystems :^)

This makes it possible to change flags of a mount after the fact, with the
caveats outlined in the man page.
This commit is contained in:
Sergey Bugaev 2020-05-28 21:12:13 +03:00 committed by Andreas Kling
parent d395b93b15
commit 3847d00727
8 changed files with 58 additions and 0 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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<NonnullRefPtr<FileDescription>> open(StringView path, int options, mode_t mode, Custody& base, Optional<UidAndGid> = {});

View file

@ -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())

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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());
}