summaryrefslogtreecommitdiff
path: root/bind-mount.c
diff options
context:
space:
mode:
authorLudovico de Nittis <ludovico.denittis@collabora.com>2021-02-16 13:46:10 +0100
committerLudovico de Nittis <ludovico.denittis@collabora.com>2021-02-16 13:46:10 +0100
commit04c0ca17ad945c50aaff61abad475bbd627e0584 (patch)
treeb3027528f0c21a4af729c9afa1aae9a2cc160c01 /bind-mount.c
parentbae85baf7208c4acddd9cf032059d1429f179e4a (diff)
downloadbubblewrap-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.c28
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 &&