summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2021-06-23 10:17:42 +0100
committerGitHub <noreply@github.com>2021-06-23 10:17:42 +0100
commit80dc9b5e86e4abc8b7ea78c703564259cde955ed (patch)
treedaaada3d844cff5ade11c7fe96a3c96e351634b7
parent79e9a0712c4e3418ba4993abcfdb86a68f9c4507 (diff)
parent04c0ca17ad945c50aaff61abad475bbd627e0584 (diff)
downloadbubblewrap-80dc9b5e86e4abc8b7ea78c703564259cde955ed.tar.gz
Merge pull request #403 from RyuzakiKK/case_insensitive_fs
Add support for bind-mount on case-insensitive filesystems
-rw-r--r--bind-mount.c28
-rw-r--r--bubblewrap.c8
-rw-r--r--utils.c31
-rw-r--r--utils.h2
4 files changed, 59 insertions, 10 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 &&
diff --git a/bubblewrap.c b/bubblewrap.c
index 6b91f22..3bca513 100644
--- a/bubblewrap.c
+++ b/bubblewrap.c
@@ -866,14 +866,6 @@ get_newroot_path (const char *path)
return strconcat ("/newroot/", path);
}
-static char *
-get_oldroot_path (const char *path)
-{
- while (*path == '/')
- path++;
- return strconcat ("/oldroot/", path);
-}
-
static void
write_uid_gid_map (uid_t sandbox_uid,
uid_t parent_uid,
diff --git a/utils.c b/utils.c
index ea15158..e4ca332 100644
--- a/utils.c
+++ b/utils.c
@@ -769,6 +769,37 @@ read_pid_from_socket (int socket)
die ("No pid returned on socket");
}
+/* Sets errno on error (== NULL),
+ * Always ensures terminating zero */
+char *
+readlink_malloc (const char *pathname)
+{
+ size_t size = 50;
+ ssize_t n;
+ cleanup_free char *value = NULL;
+
+ do
+ {
+ size *= 2;
+ value = xrealloc (value, size);
+ n = readlink (pathname, value, size - 1);
+ if (n < 0)
+ return NULL;
+ }
+ while (size - 2 < n);
+
+ value[n] = 0;
+ return steal_pointer (&value);
+}
+
+char *
+get_oldroot_path (const char *path)
+{
+ while (*path == '/')
+ path++;
+ return strconcat ("/oldroot/", path);
+}
+
int
raw_clone (unsigned long flags,
void *child_stack)
diff --git a/utils.h b/utils.h
index 8c4db61..c90c8d7 100644
--- a/utils.h
+++ b/utils.h
@@ -112,6 +112,8 @@ int mkdir_with_parents (const char *pathname,
void create_pid_socketpair (int sockets[2]);
void send_pid_on_socket (int socket);
int read_pid_from_socket (int socket);
+char *get_oldroot_path (const char *path);
+char *readlink_malloc (const char *pathname);
/* syscall wrappers */
int raw_clone (unsigned long flags,