diff options
author | Simon McVittie <smcv@collabora.com> | 2021-06-23 10:17:42 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-23 10:17:42 +0100 |
commit | 80dc9b5e86e4abc8b7ea78c703564259cde955ed (patch) | |
tree | daaada3d844cff5ade11c7fe96a3c96e351634b7 | |
parent | 79e9a0712c4e3418ba4993abcfdb86a68f9c4507 (diff) | |
parent | 04c0ca17ad945c50aaff61abad475bbd627e0584 (diff) | |
download | bubblewrap-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.c | 28 | ||||
-rw-r--r-- | bubblewrap.c | 8 | ||||
-rw-r--r-- | utils.c | 31 | ||||
-rw-r--r-- | utils.h | 2 |
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, @@ -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) @@ -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, |