diff --git a/SOURCES/fuse-overlayfs-1803495.patch b/SOURCES/fuse-overlayfs-1803495.patch new file mode 100644 index 0000000..f7f7862 --- /dev/null +++ b/SOURCES/fuse-overlayfs-1803495.patch @@ -0,0 +1,267 @@ +From a68c9d75b592eba68026661877c7a0aed5dabf41 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Sat, 15 Feb 2020 12:33:52 +0100 +Subject: [PATCH] main: force timeout 0 for ovl_link + +There is an issue on RHEL 8.1 where the nlink counter is always +incremented by one, no matter what is specified in e.attr.st_nlink. + +Always set timeout to 0 to force a new stat on the inode. + +Closes: https://bugzilla.redhat.com/show_bug.cgi?id=1802907 +Closes: https://github.com/containers/fuse-overlayfs/issues/183 + +Signed-off-by: Giuseppe Scrivano +--- + main.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/main.c b/main.c +index b1bdfa4..7a6eae4 100644 +--- a/main.c ++++ b/main.c +@@ -3615,235 +3615,240 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru + ret = truncate (path, attr->st_size); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } + } + + if (uid != -1 || gid != -1) + { + if (fd >= 0) + ret = fchown (fd, uid, gid); + else + ret = chown (path, uid, gid); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } + } + + if (do_getattr (req, &e, node, fd, path) < 0) + { + fuse_reply_err (req, errno); + return; + } + + fuse_reply_attr (req, &e.attr, get_timeout (lo)); + } + + static int + direct_linkat (struct ovl_layer *l, const char *oldpath, const char *newpath, int flags) + { + return linkat (l->fd, oldpath, l->fd, newpath, 0); + } + + static void + ovl_link (fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname) + { + cleanup_lock int l = enter_big_lock (); + struct ovl_data *lo = ovl_data (req); + struct ovl_node *node, *newparentnode, *destnode; + cleanup_free char *path = NULL; + int ret; + struct fuse_entry_param e; + char wd_tmp_file_name[32]; + + if (UNLIKELY (ovl_debug (req))) + fprintf (stderr, "ovl_link(ino=%" PRIu64 "s, newparent=%" PRIu64 "s, newname=%s)\n", ino, newparent, newname); + + node = do_lookup_file (lo, ino, NULL); + if (node == NULL) + { + fuse_reply_err (req, ENOENT); + return; + } + + node = get_node_up (lo, node); + if (node == NULL) + { + fuse_reply_err (req, errno); + return; + } + + newparentnode = do_lookup_file (lo, newparent, NULL); + if (newparentnode == NULL) + { + fuse_reply_err (req, ENOENT); + return; + } + + destnode = do_lookup_file (lo, newparent, newname); + if (destnode && !destnode->whiteout) + { + fuse_reply_err (req, EEXIST); + return; + } + + newparentnode = get_node_up (lo, newparentnode); + if (newparentnode == NULL) + { + fuse_reply_err (req, errno); + return; + } + + if (delete_whiteout (lo, -1, newparentnode, newname) < 0) + { + fuse_reply_err (req, errno); + return; + } + + sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); + + ret = asprintf (&path, "%s/%s", newparentnode->path, newname); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } + ++ /* ++ There is an issue on RHEL 8.1 where the nlink counter is always ++ incremented by one, no matter what is specified in e.attr.st_nlink. ++ In this function we always set timeout to 0 to force a new stat on the inode. ++ */ + ret = direct_linkat (get_upper_layer (lo), node->path, path, 0); + if (ret < 0) + { + fuse_reply_err (req, errno); + return; + } + + node = make_ovl_node (lo, path, get_upper_layer (lo), newname, node->tmp_ino, node->tmp_dev, false, newparentnode, lo->fast_ino_check); + if (node == NULL) + { + fuse_reply_err (req, ENOMEM); + return; + } + if (destnode && !destnode->whiteout) + node->last_layer = get_upper_layer (lo); + + node = insert_node (newparentnode, node, true); + if (node == NULL) + { + fuse_reply_err (req, ENOMEM); + return; + } + + memset (&e, 0, sizeof (e)); + + ret = rpl_stat (req, node, -1, NULL, NULL, &e.attr); + if (ret) + { + fuse_reply_err (req, errno); + return; + } + + e.ino = node_to_inode (node); + node->ino->lookups++; +- e.attr_timeout = get_timeout (lo); ++ e.attr_timeout = 0; + e.entry_timeout = get_timeout (lo); + fuse_reply_entry (req, &e); + } + + static int + direct_symlinkat (struct ovl_layer *l, const char *target, const char *linkpath, uid_t uid, gid_t gid) + { + struct ovl_data *lo = l->ovl_data; + char wd_tmp_file_name[32]; + int ret; + + sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); + + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); + ret = symlinkat (linkpath, lo->workdir_fd, wd_tmp_file_name); + if (ret < 0) + return ret; + + if (uid != lo->uid || gid != lo->gid) + { + ret = fchownat (lo->workdir_fd, wd_tmp_file_name, uid, gid, AT_SYMLINK_NOFOLLOW); + if (ret < 0) + { + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); + return ret; + } + } + + ret = renameat (lo->workdir_fd, wd_tmp_file_name, get_upper_layer (lo)->fd, target); + if (ret < 0) + { + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); + return ret; + } + + return 0; + } + + static void + ovl_symlink (fuse_req_t req, const char *link, fuse_ino_t parent, const char *name) + { + cleanup_lock int l = enter_big_lock (); + struct ovl_data *lo = ovl_data (req); + struct ovl_node *pnode, *node; + int ret; + struct fuse_entry_param e; + const struct fuse_ctx *ctx = fuse_req_ctx (req); + char wd_tmp_file_name[32]; + bool need_delete_whiteout = true; + cleanup_free char *path = NULL; + + if (UNLIKELY (ovl_debug (req))) + fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name); + + pnode = do_lookup_file (lo, parent, NULL); + if (pnode == NULL) + { + fuse_reply_err (req, ENOENT); + return; + } + + pnode = get_node_up (lo, pnode); + if (pnode == NULL) + { + fuse_reply_err (req, errno); + return; + } + + node = do_lookup_file (lo, parent, name); + if (node != NULL && !node->whiteout) + { + fuse_reply_err (req, EEXIST); + return; + } + + if (pnode->loaded && node == NULL) + need_delete_whiteout = false; + + ret = asprintf (&path, "%s/%s", pnode->path, name); + if (ret < 0) + { + fuse_reply_err (req, ENOMEM); + return; + } + + ret = direct_symlinkat (get_upper_layer (lo), path, link, get_uid (lo, ctx->uid), get_gid (lo, ctx->gid)); + if (ret < 0) + { + fuse_reply_err (req, ENOMEM); + return; + } + + if (need_delete_whiteout && delete_whiteout (lo, -1, pnode, name) < 0) + { + unlinkat (lo->workdir_fd, wd_tmp_file_name, 0); + fuse_reply_err (req, errno); + return; + } + + node = make_ovl_node (lo, path, get_upper_layer (lo), name, 0, 0, false, pnode, lo->fast_ino_check); +-- +2.18.1 + diff --git a/SOURCES/fuse-overlayfs-1804849.patch b/SOURCES/fuse-overlayfs-1804849.patch new file mode 100644 index 0000000..bf75003 --- /dev/null +++ b/SOURCES/fuse-overlayfs-1804849.patch @@ -0,0 +1,189 @@ +From 214d606084453f0d2831317a9048a3cbc554fcc4 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Wed, 15 Jan 2020 00:02:43 +0100 +Subject: [PATCH 1/2] main: check if file is whiteout + +when doing a lookup, make sure the returned file is not a whiteout for +functions that expect the file to exist. + +Close: https://github.com/containers/fuse-overlayfs/issues/169 + +Signed-off-by: Giuseppe Scrivano +--- + main.c | 34 +++++++++++++++++----------------- + 1 file changed, 17 insertions(+), 17 deletions(-) + + +From ce93abae5fcb3be98867bbfd8e13abb2c086d1c2 Mon Sep 17 00:00:00 2001 +From: Giuseppe Scrivano +Date: Wed, 15 Jan 2020 17:52:13 +0100 +Subject: [PATCH 2/2] main: do not copyup opaque xattr + +when performing the copyup, do not copy the private xattrs. + +Signed-off-by: Giuseppe Scrivano +--- + main.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff -up ./fuse-overlayfs-8c59873b00b3e8ee98be998fec8dbce4cfe984cc/main.c.1804849 ./fuse-overlayfs-8c59873b00b3e8ee98be998fec8dbce4cfe984cc/main.c +--- fuse-overlayfs-8c59873b00b3e8ee98be998fec8dbce4cfe984cc/main.c.1804849 2020-02-20 14:38:04.204508810 +0100 ++++ fuse-overlayfs-8c59873b00b3e8ee98be998fec8dbce4cfe984cc/main.c 2020-02-20 14:38:04.208508867 +0100 +@@ -2265,7 +2265,7 @@ ovl_getxattr (fuse_req_t req, fuse_ino_t + } + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -2334,7 +2334,13 @@ copy_xattr (int sfd, int dfd, char *buf, + for (it = buf; it - buf < xattr_len; it += strlen (it) + 1) + { + cleanup_free char *v = NULL; +- ssize_t s = safe_read_xattr (&v, sfd, it, 256); ++ ssize_t s; ++ ++ if (has_prefix (it, XATTR_PREFIX) ++ || has_prefix (it, PRIVILEGED_XATTR_PREFIX)) ++ continue; ++ ++ s = safe_read_xattr (&v, sfd, it, 256); + if (s < 0) + return -1; + +@@ -2858,7 +2864,7 @@ do_rm (fuse_req_t req, fuse_ino_t parent + struct ovl_node key, *rm; + + node = do_lookup_file (lo, parent, name); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -2904,7 +2910,7 @@ do_rm (fuse_req_t req, fuse_ino_t parent + } + + pnode = do_lookup_file (lo, parent, NULL); +- if (pnode == NULL) ++ if (pnode == NULL || pnode->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3009,7 +3015,7 @@ ovl_setxattr (fuse_req_t req, fuse_ino_t + } + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3069,7 +3075,7 @@ ovl_removexattr (fuse_req_t req, fuse_in + fprintf (stderr, "ovl_removexattr(ino=%" PRIu64 "s, name=%s)\n", ino, name); + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3447,7 +3453,7 @@ ovl_getattr (fuse_req_t req, fuse_ino_t + fprintf (stderr, "ovl_getattr(ino=%" PRIu64 ")\n", ino); + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3481,7 +3487,7 @@ ovl_setattr (fuse_req_t req, fuse_ino_t + fprintf (stderr, "ovl_setattr(ino=%" PRIu64 "s, to_set=%d)\n", ino, to_set); + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3663,7 +3669,7 @@ ovl_link (fuse_req_t req, fuse_ino_t ino + fprintf (stderr, "ovl_link(ino=%" PRIu64 "s, newparent=%" PRIu64 "s, newname=%s)\n", ino, newparent, newname); + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3677,7 +3683,7 @@ ovl_link (fuse_req_t req, fuse_ino_t ino + } + + newparentnode = do_lookup_file (lo, newparent, NULL); +- if (newparentnode == NULL) ++ if (newparentnode == NULL || newparentnode->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3802,7 +3808,7 @@ ovl_symlink (fuse_req_t req, const char + fprintf (stderr, "ovl_symlink(link=%s, ino=%" PRIu64 "s, name=%s)\n", link, parent, name); + + pnode = do_lookup_file (lo, parent, NULL); +- if (pnode == NULL) ++ if (pnode == NULL || pnode->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -3896,7 +3902,7 @@ ovl_rename_exchange (fuse_req_t req, fus + char *tmp; + + node = do_lookup_file (lo, parent, name); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -4255,7 +4261,7 @@ ovl_readlink (fuse_req_t req, fuse_ino_t + fprintf (stderr, "ovl_readlink(ino=%" PRIu64 "s)\n", ino); + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -4661,7 +4667,7 @@ ovl_ioctl (fuse_req_t req, fuse_ino_t in + ino, cmd, arg, fi, flags, in_buf, in_bufsz, out_bufsz); + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -4730,7 +4736,7 @@ ovl_fallocate (fuse_req_t req, fuse_ino_ + ino, mode, offset, length, fi); + + node = do_lookup_file (lo, ino, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; +@@ -4781,14 +4787,14 @@ ovl_copy_file_range (fuse_req_t req, fus + ino_in, off_in, fi_in, ino_out, off_out, fi_out, len, flags); + + node = do_lookup_file (lo, ino_in, NULL); +- if (node == NULL) ++ if (node == NULL || node->whiteout) + { + fuse_reply_err (req, ENOENT); + return; + } + + dnode = do_lookup_file (lo, ino_out, NULL); +- if (dnode == NULL) ++ if (dnode == NULL || dnode->whiteout) + { + fuse_reply_err (req, ENOENT); + return; diff --git a/SPECS/fuse-overlayfs.spec b/SPECS/fuse-overlayfs.spec index 439aeb3..f8bae4b 100644 --- a/SPECS/fuse-overlayfs.spec +++ b/SPECS/fuse-overlayfs.spec @@ -4,12 +4,18 @@ Name: fuse-overlayfs Version: 0.7.2 -Release: 1%{?dist} +Release: 5%{?dist} Summary: FUSE overlay+shiftfs implementation for rootless containers License: GPLv3+ URL: %{git0} ExclusiveArch: aarch64 %{arm} ppc64le s390x x86_64 Source0: %{git0}/archive/%{commit0}/%{name}-%{shortcommit0}.tar.gz +# related bug: https://bugzilla.redhat.com/show_bug.cgi?id=1802907 +# backported: https://patch-diff.githubusercontent.com/raw/containers/fuse-overlayfs/pull/184.patch +Patch0: fuse-overlayfs-1803495.patch +# related bug: https://bugzilla.redhat.com/show_bug.cgi?id=1804849 +# patch: https://bugzilla.redhat.com/attachment.cgi?id=1666385 +Patch1: fuse-overlayfs-1804849.patch BuildRequires: autoconf BuildRequires: automake BuildRequires: fuse3-devel @@ -56,6 +62,22 @@ make DESTDIR=%{buildroot} install install-man %{_mandir}/man1/%{name}.1.gz %changelog +* Thu Mar 26 2020 Jindrich Novy - 0.7.2-5 +- be sure to work properly also with older rhel8 kernels, thanks to Giuseppe Scrivano +- Resolves: #1803495 + +* Tue Mar 24 2020 Jindrich Novy - 0.7.2-4 +- latest iteration of segfault fix patch, thanks to Giuseppe Scrivano +- Resolves: #1803495 + +* Thu Feb 20 2020 Jindrich Novy - 0.7.2-3 +- fix "fuse-overlayfs segfault" +- Resolves: #1805016 + +* Mon Feb 17 2020 Jindrich Novy - 0.7.2-2 +- fix "useradd and groupadd fail under rootless Buildah and podman" +- Resolves: #1803495 + * Fri Nov 29 2019 Jindrich Novy - 0.7.2-1 - update to 0.7.2 - Related: RHELPLAN-25138