|
|
b8c242 |
From 397aaad6da5c4bfb160adca7a68f865086f2ed0a Mon Sep 17 00:00:00 2001
|
|
|
b8c242 |
From: Franck Bui <fbui@suse.com>
|
|
|
b8c242 |
Date: Thu, 30 Sep 2021 14:05:36 +0200
|
|
|
b8c242 |
Subject: [PATCH] mount-util: fix fd_is_mount_point() when both the parent and
|
|
|
b8c242 |
directory are network fs
|
|
|
b8c242 |
|
|
|
b8c242 |
The second call to name_to_handle_at_loop() didn't check for the specific
|
|
|
b8c242 |
errors that can happen when the parent dir is mounted by nfs and instead of
|
|
|
b8c242 |
falling back like it's done for the child dir, fd_is_mount_point() failed in
|
|
|
b8c242 |
this case.
|
|
|
b8c242 |
|
|
|
b8c242 |
(cherry picked from commit 964ccab8286a7e75d7e9107f574f5cb23752bd5d)
|
|
|
b8c242 |
|
|
|
b8c242 |
Resolves: #2015057
|
|
|
b8c242 |
---
|
|
|
b8c242 |
src/basic/mount-util.c | 71 ++++++++++++++++++++++++------------------
|
|
|
b8c242 |
1 file changed, 41 insertions(+), 30 deletions(-)
|
|
|
b8c242 |
|
|
|
b8c242 |
diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c
|
|
|
b8c242 |
index 45348bf878..0c709001be 100644
|
|
|
b8c242 |
--- a/src/basic/mount-util.c
|
|
|
b8c242 |
+++ b/src/basic/mount-util.c
|
|
|
b8c242 |
@@ -139,6 +139,19 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id
|
|
|
b8c242 |
return safe_atoi(p, mnt_id);
|
|
|
b8c242 |
}
|
|
|
b8c242 |
|
|
|
b8c242 |
+static bool is_name_to_handle_at_fatal_error(int err) {
|
|
|
b8c242 |
+ /* name_to_handle_at() can return "acceptable" errors that are due to the context. For
|
|
|
b8c242 |
+ * example the kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall
|
|
|
b8c242 |
+ * was blocked (EACCES/EPERM; maybe through seccomp, because we are running inside of a
|
|
|
b8c242 |
+ * container), or the mount point is not triggered yet (EOVERFLOW, think nfs4), or some
|
|
|
b8c242 |
+ * general name_to_handle_at() flakiness (EINVAL). However other errors are not supposed to
|
|
|
b8c242 |
+ * happen and therefore are considered fatal ones. */
|
|
|
b8c242 |
+
|
|
|
b8c242 |
+ assert(err < 0);
|
|
|
b8c242 |
+
|
|
|
b8c242 |
+ return !IN_SET(err, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL);
|
|
|
b8c242 |
+}
|
|
|
b8c242 |
+
|
|
|
b8c242 |
int fd_is_mount_point(int fd, const char *filename, int flags) {
|
|
|
b8c242 |
_cleanup_free_ struct file_handle *h = NULL, *h_parent = NULL;
|
|
|
b8c242 |
int mount_id = -1, mount_id_parent = -1;
|
|
|
b8c242 |
@@ -173,42 +186,40 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
|
|
|
b8c242 |
* real mounts of their own. */
|
|
|
b8c242 |
|
|
|
b8c242 |
r = name_to_handle_at_loop(fd, filename, &h, &mount_id, flags);
|
|
|
b8c242 |
- if (IN_SET(r, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL))
|
|
|
b8c242 |
- /* This kernel does not support name_to_handle_at() at all (ENOSYS), or the syscall was blocked
|
|
|
b8c242 |
- * (EACCES/EPERM; maybe through seccomp, because we are running inside of a container?), or the mount
|
|
|
b8c242 |
- * point is not triggered yet (EOVERFLOW, think nfs4), or some general name_to_handle_at() flakiness
|
|
|
b8c242 |
- * (EINVAL): fall back to simpler logic. */
|
|
|
b8c242 |
- goto fallback_fdinfo;
|
|
|
b8c242 |
- else if (r == -EOPNOTSUPP)
|
|
|
b8c242 |
- /* This kernel or file system does not support name_to_handle_at(), hence let's see if the upper fs
|
|
|
b8c242 |
- * supports it (in which case it is a mount point), otherwise fallback to the traditional stat()
|
|
|
b8c242 |
- * logic */
|
|
|
b8c242 |
+ if (r < 0) {
|
|
|
b8c242 |
+ if (is_name_to_handle_at_fatal_error(r))
|
|
|
b8c242 |
+ return r;
|
|
|
b8c242 |
+ if (r != -EOPNOTSUPP)
|
|
|
b8c242 |
+ goto fallback_fdinfo;
|
|
|
b8c242 |
+
|
|
|
b8c242 |
+ /* This kernel or file system does not support name_to_handle_at(), hence let's see
|
|
|
b8c242 |
+ * if the upper fs supports it (in which case it is a mount point), otherwise fall
|
|
|
b8c242 |
+ * back to the traditional stat() logic */
|
|
|
b8c242 |
nosupp = true;
|
|
|
b8c242 |
- else if (r < 0)
|
|
|
b8c242 |
- return r;
|
|
|
b8c242 |
+ }
|
|
|
b8c242 |
|
|
|
b8c242 |
r = name_to_handle_at_loop(fd, "", &h_parent, &mount_id_parent, AT_EMPTY_PATH);
|
|
|
b8c242 |
- if (r == -EOPNOTSUPP) {
|
|
|
b8c242 |
+ if (r < 0) {
|
|
|
b8c242 |
+ if (is_name_to_handle_at_fatal_error(r))
|
|
|
b8c242 |
+ return r;
|
|
|
b8c242 |
+ if (r != -EOPNOTSUPP)
|
|
|
b8c242 |
+ goto fallback_fdinfo;
|
|
|
b8c242 |
if (nosupp)
|
|
|
b8c242 |
- /* Neither parent nor child do name_to_handle_at()? We have no choice but to fall back. */
|
|
|
b8c242 |
+ /* Both the parent and the directory can't do name_to_handle_at() */
|
|
|
b8c242 |
goto fallback_fdinfo;
|
|
|
b8c242 |
- else
|
|
|
b8c242 |
- /* The parent can't do name_to_handle_at() but the directory we are interested in can? If so,
|
|
|
b8c242 |
- * it must be a mount point. */
|
|
|
b8c242 |
- return 1;
|
|
|
b8c242 |
- } else if (r < 0)
|
|
|
b8c242 |
- return r;
|
|
|
b8c242 |
|
|
|
b8c242 |
- /* The parent can do name_to_handle_at() but the
|
|
|
b8c242 |
- * directory we are interested in can't? If so, it
|
|
|
b8c242 |
- * must be a mount point. */
|
|
|
b8c242 |
+ /* The parent can't do name_to_handle_at() but the directory we are
|
|
|
b8c242 |
+ * interested in can? If so, it must be a mount point. */
|
|
|
b8c242 |
+ return 1;
|
|
|
b8c242 |
+ }
|
|
|
b8c242 |
+
|
|
|
b8c242 |
+ /* The parent can do name_to_handle_at() but the directory we are interested in can't? If
|
|
|
b8c242 |
+ * so, it must be a mount point. */
|
|
|
b8c242 |
if (nosupp)
|
|
|
b8c242 |
return 1;
|
|
|
b8c242 |
|
|
|
b8c242 |
- /* If the file handle for the directory we are
|
|
|
b8c242 |
- * interested in and its parent are identical, we
|
|
|
b8c242 |
- * assume this is the root directory, which is a mount
|
|
|
b8c242 |
- * point. */
|
|
|
b8c242 |
+ /* If the file handle for the directory we are interested in and its parent are identical,
|
|
|
b8c242 |
+ * we assume this is the root directory, which is a mount point. */
|
|
|
b8c242 |
|
|
|
b8c242 |
if (h->handle_bytes == h_parent->handle_bytes &&
|
|
|
b8c242 |
h->handle_type == h_parent->handle_type &&
|
|
|
b8c242 |
@@ -300,10 +311,10 @@ int path_get_mnt_id(const char *path, int *ret) {
|
|
|
b8c242 |
int r;
|
|
|
b8c242 |
|
|
|
b8c242 |
r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
|
|
|
b8c242 |
- if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM, -EOVERFLOW, -EINVAL)) /* kernel/fs don't support this, or seccomp blocks access, or untriggered mount, or name_to_handle_at() is flaky */
|
|
|
b8c242 |
- return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
|
|
|
b8c242 |
+ if (r == 0 || is_name_to_handle_at_fatal_error(r))
|
|
|
b8c242 |
+ return r;
|
|
|
b8c242 |
|
|
|
b8c242 |
- return r;
|
|
|
b8c242 |
+ return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
|
|
|
b8c242 |
}
|
|
|
b8c242 |
|
|
|
b8c242 |
int umount_recursive(const char *prefix, int flags) {
|