diff options
author | Ludovico de Nittis <ludovico.denittis@collabora.com> | 2021-02-16 13:46:10 +0100 |
---|---|---|
committer | Ludovico de Nittis <ludovico.denittis@collabora.com> | 2021-02-16 13:46:10 +0100 |
commit | 04c0ca17ad945c50aaff61abad475bbd627e0584 (patch) | |
tree | b3027528f0c21a4af729c9afa1aae9a2cc160c01 /bind-mount.c | |
parent | bae85baf7208c4acddd9cf032059d1429f179e4a (diff) | |
download | bubblewrap-04c0ca17ad945c50aaff61abad475bbd627e0584.tar.gz |
Add support for bind-mount on case-insensitive filesystems
If we are using a case-insensitive filesystem the bind-mount operation
might fail when `/proc/self/mountinfo` is checked.
In a case-insensitive filesystem, if we ask to mount a certain
directory, e.g. '/CI_fs/foo', the kernel might add its entry in
`mountinfo` as '/CI_fs/FOO'. This happens because the kernel populates
`mountinfo` with whatever case combination first appeared in the dcache.
With this patch we open the requested path and look at its
`/proc/self/fd`, using readlink(), to get the path case combination that
the kernel is also expected to be using.
Signed-off-by: Ludovico de Nittis <ludovico.denittis@collabora.com>
Diffstat (limited to 'bind-mount.c')
-rw-r--r-- | bind-mount.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/bind-mount.c b/bind-mount.c index 4bd187d..e692762 100644 --- a/bind-mount.c +++ b/bind-mount.c @@ -385,6 +385,10 @@ bind_mount (int proc_fd, unsigned long current_flags, new_flags; cleanup_mount_tab MountTab mount_tab = NULL; cleanup_free char *resolved_dest = NULL; + cleanup_free char *dest_proc = NULL; + cleanup_free char *oldroot_dest_proc = NULL; + cleanup_free char *kernel_case_combination = NULL; + cleanup_fd int dest_fd = -1; int i; if (src) @@ -399,14 +403,34 @@ bind_mount (int proc_fd, if (resolved_dest == NULL) return 2; - mount_tab = parse_mountinfo (proc_fd, resolved_dest); + dest_fd = open (resolved_dest, O_PATH | O_CLOEXEC); + if (dest_fd < 0) + return 2; + + /* If we are in a case-insensitive filesystem, mountinfo might contain a + * different case combination of the path we requested to mount. + * This is due to the fact that the kernel, as of the beginning of 2021, + * populates mountinfo with whatever case combination first appeared in the + * dcache; kernel developers plan to change this in future so that it + * reflects the on-disk encoding instead. + * To avoid throwing an error when this happens, we use readlink() result + * instead of the provided @root_mount, so that we can compare the mountinfo + * entries with the same case combination that the kernel is expected to + * use. */ + dest_proc = xasprintf ("/proc/self/fd/%d", dest_fd); + oldroot_dest_proc = get_oldroot_path (dest_proc); + kernel_case_combination = readlink_malloc (oldroot_dest_proc); + if (kernel_case_combination == NULL) + die_with_error ("Can't read the link in %s", oldroot_dest_proc); + + mount_tab = parse_mountinfo (proc_fd, kernel_case_combination); if (mount_tab[0].mountpoint == NULL) { errno = EINVAL; return 2; /* No mountpoint at dest */ } - assert (path_equal (mount_tab[0].mountpoint, resolved_dest)); + assert (path_equal (mount_tab[0].mountpoint, kernel_case_combination)); current_flags = mount_tab[0].options; new_flags = current_flags | (devices ? 0 : MS_NODEV) | MS_NOSUID | (readonly ? MS_RDONLY : 0); if (new_flags != current_flags && |