Hello community, here is the log from the commit of package fuse-overlayfs for openSUSE:Factory checked in at 2020-07-15 11:30:01 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/fuse-overlayfs (Old) and /work/SRC/openSUSE:Factory/.fuse-overlayfs.new.3060 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "fuse-overlayfs" Wed Jul 15 11:30:01 2020 rev:12 rq:819290 version:1.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/fuse-overlayfs/fuse-overlayfs.changes 2020-04-25 20:08:53.471617868 +0200 +++ /work/SRC/openSUSE:Factory/.fuse-overlayfs.new.3060/fuse-overlayfs.changes 2020-07-15 11:32:27.782046890 +0200 @@ -1,0 +2,12 @@ +Wed Jun 24 13:10:52 UTC 2020 - Ralf Haferkamp <rha...@suse.com> + +- Update to v1.1.0 + - use openat2(2) when available. + - accept "ro" as mount option. + - fix set mtime for a symlink. + - fix some issues reported by static analysis. + - fix potential infinite loop on a short read. + - fix creating a directory if the destination already exists + in the upper layer. + +------------------------------------------------------------------- Old: ---- fuse-overlayfs-1.0.0.tar.xz New: ---- fuse-overlayfs-1.1.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ fuse-overlayfs.spec ++++++ --- /var/tmp/diff_new_pack.NUNBiv/_old 2020-07-15 11:32:28.938048106 +0200 +++ /var/tmp/diff_new_pack.NUNBiv/_new 2020-07-15 11:32:28.942048110 +0200 @@ -17,7 +17,7 @@ Name: fuse-overlayfs -Version: 1.0.0 +Version: 1.1.0 Release: 0 Summary: FUSE implementation for overlayfs License: GPL-3.0-only ++++++ _service ++++++ --- /var/tmp/diff_new_pack.NUNBiv/_old 2020-07-15 11:32:28.970048139 +0200 +++ /var/tmp/diff_new_pack.NUNBiv/_new 2020-07-15 11:32:28.970048139 +0200 @@ -3,8 +3,8 @@ <param name="url">https://github.com/containers/fuse-overlayfs.git</param> <param name="scm">git</param> <param name="filename">fuse-overlayfs</param> - <param name="versionformat">1.0.0</param> - <param name="revision">v1.0.0</param> + <param name="versionformat">1.1.0</param> + <param name="revision">v1.1.0</param> </service> <service name="set_version" mode="disabled"> <param name="basename">fuse-overlayfs</param> ++++++ fuse-overlayfs-1.0.0.tar.xz -> fuse-overlayfs-1.1.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/.travis.yml new/fuse-overlayfs-1.1.0/.travis.yml --- old/fuse-overlayfs-1.0.0/.travis.yml 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/.travis.yml 2020-06-18 09:15:04.000000000 +0200 @@ -34,7 +34,7 @@ - (git clone --depth 1 -b 0.51.1 https://github.com/mesonbuild/meson.git; cd meson; sudo python3.5 ./setup.py install) - (git clone --depth 1 https://github.com/bats-core/bats-core; cd bats-core; sudo ./install.sh /usr/local) - ($GO get github.com/containers/storage; cd $GOPATH/src/github.com/containers/storage; sed -i -e 's|^AUTOTAGS.*$|AUTOTAGS := exclude_graphdriver_devicemapper exclude_graphdriver_btrfs|' Makefile; make GO=$GO GO111MODULE=on containers-storage) - - (wget https://github.com/libfuse/libfuse/releases/download/fuse-3.6.2/fuse-3.6.2.tar.xz; tar xf fuse-3.6.2.tar.xz; cd fuse-3.6.2; mkdir build; cd build; meson .. --prefix /usr && ninja && sudo ninja install) + - (wget https://github.com/libfuse/libfuse/releases/download/fuse-3.9.1/fuse-3.9.1.tar.xz; tar xf fuse-3.9.1.tar.xz; cd fuse-3.9.1; mkdir build; cd build; meson .. --prefix /usr && ninja && sudo ninja install) script: - ./autogen.sh || travis_terminate 1; - ./configure || travis_terminate 1; @@ -44,6 +44,6 @@ - (cd /unionmount-testsuite; sudo FUSE_OVERLAYFS_DISABLE_OVL_WHITEOUT=1 unshare -m ./run --ov --fuse=fuse-overlayfs --xdev) || travis_terminate 1; - sudo tests/fedora-installs.sh || travis_terminate 1; - sudo tests/unlink.sh || travis_terminate 1; - - (cd $GOPATH/src/github.com/containers/storage/tests; sudo STORAGE_OPTION=overlay.mount_program=/sbin/fuse-overlayfs STORAGE_DRIVER=overlay unshare -m ./test_runner.bash) || travis_terminate 1; - - (cd $GOPATH/src/github.com/containers/storage/tests; sudo FUSE_OVERLAYFS_DISABLE_OVL_WHITEOUT=1 STORAGE_OPTION=overlay.mount_program=/sbin/fuse-overlayfs STORAGE_DRIVER=overlay unshare -m ./test_runner.bash) || travis_terminate 1; + - (cd $GOPATH/src/github.com/containers/storage/tests; sudo JOBS=1 STORAGE_OPTION=overlay.mount_program=/sbin/fuse-overlayfs STORAGE_DRIVER=overlay unshare -m ./test_runner.bash) || travis_terminate 1; + - (cd $GOPATH/src/github.com/containers/storage/tests; sudo JOBS=1 FUSE_OVERLAYFS_DISABLE_OVL_WHITEOUT=1 STORAGE_OPTION=overlay.mount_program=/sbin/fuse-overlayfs STORAGE_DRIVER=overlay unshare -m ./test_runner.bash) || travis_terminate 1; - docker run --rm -v $(pwd):/fuse-overlayfs alpine-build sh -c 'cd /fuse-overlayfs; ./autogen.sh && ./configure && make clean && make' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/NEWS new/fuse-overlayfs-1.1.0/NEWS --- old/fuse-overlayfs-1.0.0/NEWS 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/NEWS 2020-06-18 09:15:04.000000000 +0200 @@ -1,3 +1,12 @@ +* fuse-overlayfs-1.1.0 + +- use openat2(2) when available. +- accept "ro" as mount option. +- fix set mtime for a symlink. +- fix some issues reported by static analysis. +- fix potential infinite loop on a short read. +- fix creating a directory if the destination already exists in the upper layer. + * fuse-overlayfs-1.0.0 - fix portability issue to 32 bits archs. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/SECURITY.md new/fuse-overlayfs-1.1.0/SECURITY.md --- old/fuse-overlayfs-1.0.0/SECURITY.md 1970-01-01 01:00:00.000000000 +0100 +++ new/fuse-overlayfs-1.1.0/SECURITY.md 2020-06-18 09:15:04.000000000 +0200 @@ -0,0 +1,3 @@ +## Security and Disclosure Information Policy for the fuse-overlayfs Project + +The fuse-overlayfs Project follows the [Security and Disclosure Information Policy](https://github.com/containers/common/blob/master/SECURITY.md) for the Containers Projects. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/configure.ac new/fuse-overlayfs-1.1.0/configure.ac --- old/fuse-overlayfs-1.0.0/configure.ac 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/configure.ac 2020-06-18 09:15:04.000000000 +0200 @@ -1,5 +1,5 @@ AC_PREREQ([2.69]) -AC_INIT([fuse-overlayfs], [1.0.0], [giuse...@scrivano.org]) +AC_INIT([fuse-overlayfs], [1.1.0], [giuse...@scrivano.org]) AC_CONFIG_SRCDIR([main.c]) AC_CONFIG_HEADERS([config.h]) @@ -75,8 +75,7 @@ AC_SEARCH_LIBS([dlopen], [dl], [], [AC_MSG_ERROR([unable to find dlopen()])]) AC_FUNC_ERROR_AT_LINE -AC_FUNC_MALLOC -AC_CHECK_FUNCS([open_by_handle_at error memset strdup copy_file_range statx]) +AC_CHECK_FUNCS([malloc open_by_handle_at error memset strdup copy_file_range statx]) AC_CONFIG_FILES([Makefile lib/Makefile]) AC_OUTPUT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/direct.c new/fuse-overlayfs-1.1.0/direct.c --- old/fuse-overlayfs-1.0.0/direct.c 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/direct.c 2020-06-18 09:15:04.000000000 +0200 @@ -129,7 +129,7 @@ cleanup_close int cleanup_fd = -1; DIR *dp = NULL; - cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, path, O_DIRECTORY)); + cleanup_fd = TEMP_FAILURE_RETRY (safe_openat (l->fd, path, O_DIRECTORY, 0)); if (cleanup_fd < 0) return NULL; @@ -151,7 +151,7 @@ static int direct_openat (struct ovl_layer *l, const char *path, int flags, mode_t mode) { - return TEMP_FAILURE_RETRY (openat (l->fd, path, flags, mode)); + return TEMP_FAILURE_RETRY (safe_openat (l->fd, path, flags, mode)); } static ssize_t diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/main.c new/fuse-overlayfs-1.1.0/main.c --- old/fuse-overlayfs-1.0.0/main.c 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/main.c 2020-06-18 09:15:04.000000000 +0200 @@ -494,7 +494,7 @@ return -1; } create_opq_whiteout: - opq_whiteout_fd = TEMP_FAILURE_RETRY (openat (fd, OPAQUE_WHITEOUT, O_CREAT|O_WRONLY|O_NONBLOCK, 0700)); + opq_whiteout_fd = TEMP_FAILURE_RETRY (safe_openat (fd, OPAQUE_WHITEOUT, O_CREAT|O_WRONLY|O_NONBLOCK, 0700)); return (opq_whiteout_fd >= 0 || ret == 0) ? 0 : -1; } @@ -823,7 +823,7 @@ } static int -direct_renameat2 (struct ovl_layer *l, int olddirfd, const char *oldpath, +direct_renameat2 (int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags) { return syscall (SYS_renameat2, olddirfd, oldpath, newdirfd, newpath, flags); @@ -1097,19 +1097,13 @@ new_name = strdup (name); if (new_name == NULL) - { - free (ret); - return NULL; - } + return NULL; + node_set_name (ret, new_name); ret->path = strdup (path); if (ret->path == NULL) - { - free (new_name); - free (ret); - return NULL; - } + return NULL; ret->whiteout = 1; ret->ino = &dummy_ino; @@ -1225,7 +1219,6 @@ for (it = layer; it; it = it->next) { ssize_t s; - bool stat_only = false; cleanup_free char *val = NULL; cleanup_free char *origin = NULL; cleanup_close int fd = -1; @@ -1275,12 +1268,6 @@ ret->last_layer = it; } - if (stat_only) - { - has_origin = false; - goto no_fd; - } - s = safe_read_xattr (&val, fd, PRIVILEGED_ORIGIN_XATTR, PATH_MAX); if (s > 0) { @@ -1766,7 +1753,7 @@ char whpath[PATH_MAX]; const char *wh_name; - if (pnode && pnode->last_layer == it) + if (pnode->last_layer == it) stop_lookup = true; strconcat3 (path, PATH_MAX, pnode->path, "/", name); @@ -2406,6 +2393,67 @@ return 0; } +static int +empty_dirfd (int fd) +{ + cleanup_dir DIR *dp = NULL; + struct dirent *dent; + + dp = fdopendir (fd); + if (dp == NULL) + { + close (fd); + return -1; + } + + for (;;) + { + int ret; + + errno = 0; + dent = readdir (dp); + if (dent == NULL) + { + if (errno) + return -1; + + break; + } + if (strcmp (dent->d_name, ".") == 0) + continue; + if (strcmp (dent->d_name, "..") == 0) + continue; + + ret = unlinkat (dirfd (dp), dent->d_name, 0); + if (ret < 0 && errno == EISDIR) + { + ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR); + if (ret < 0 && errno == ENOTEMPTY) + { + int dfd; + + dfd = safe_openat (dirfd (dp), dent->d_name, O_DIRECTORY, 0); + if (dfd < 0) + return -1; + + ret = empty_dirfd (dfd); + if (ret < 0) + return -1; + + ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR); + if (ret < 0) + return -1; + + continue; + } + } + if (ret < 0) + return ret; + } + + return 0; +} + static int create_node_directory (struct ovl_data *lo, struct ovl_node *src); static int @@ -2445,7 +2493,7 @@ if (ret < 0) goto out; - ret = dfd = TEMP_FAILURE_RETRY (openat (lo->workdir_fd, wd_tmp_file_name, O_RDONLY)); + ret = dfd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, O_RDONLY, 0)); if (ret < 0) goto out; @@ -2495,6 +2543,24 @@ ret = renameat (lo->workdir_fd, wd_tmp_file_name, dirfd, name); if (ret < 0) { + if (errno == EEXIST) + { + int dfd = -1; + + ret = direct_renameat2 (lo->workdir_fd, wd_tmp_file_name, dirfd, name, RENAME_EXCHANGE); + if (ret < 0) + goto out; + + dfd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, O_DIRECTORY, 0)); + if (dfd < 0) + return -1; + + ret = empty_dirfd (dfd); + if (ret < 0) + goto out; + + return unlinkat (lo->workdir_fd, wd_tmp_file_name, AT_REMOVEDIR); + } if (errno == ENOTDIR) unlinkat (dirfd, name, 0); if (errno == ENOENT && parent) @@ -2570,12 +2636,14 @@ break; written = 0; - { - ret = TEMP_FAILURE_RETRY (write (dfd, buf + written, nread)); - if (ret < 0) - return ret; - nread -= ret; - } + do + { + ret = TEMP_FAILURE_RETRY (write (dfd, buf + written, nread)); + if (ret < 0) + return ret; + nread -= ret; + written += ret; + } while (nread); } return 0; @@ -2645,11 +2713,11 @@ goto success; } - ret = sfd = node->layer->ds->openat (node->layer, node->path, O_RDONLY|O_NONBLOCK, 0755); + ret = sfd = node->layer->ds->openat (node->layer, node->path, O_RDONLY|O_NONBLOCK, 0); if (sfd < 0) goto exit; - ret = dfd = TEMP_FAILURE_RETRY (openat (lo->workdir_fd, wd_tmp_file_name, O_CREAT|O_WRONLY, st.st_mode)); + ret = dfd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, O_CREAT|O_WRONLY, st.st_mode)); if (dfd < 0) goto exit; @@ -2715,7 +2783,8 @@ if (ret < 0) goto exit; - if (set_fd_origin (dfd, node->path) < 0) + ret = set_fd_origin (dfd, node->path); + if (ret < 0) goto exit; /* Finally, move the file to its destination. */ @@ -2827,73 +2896,12 @@ } static int -empty_dirfd (int fd) -{ - cleanup_dir DIR *dp = NULL; - struct dirent *dent; - - dp = fdopendir (fd); - if (dp == NULL) - { - close (fd); - return -1; - } - - for (;;) - { - int ret; - - errno = 0; - dent = readdir (dp); - if (dent == NULL) - { - if (errno) - return -1; - - break; - } - if (strcmp (dent->d_name, ".") == 0) - continue; - if (strcmp (dent->d_name, "..") == 0) - continue; - - ret = unlinkat (dirfd (dp), dent->d_name, 0); - if (ret < 0 && errno == EISDIR) - { - ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR); - if (ret < 0 && errno == ENOTEMPTY) - { - int dfd; - - dfd = openat (dirfd (dp), dent->d_name, O_DIRECTORY); - if (dfd < 0) - return -1; - - ret = empty_dirfd (dfd); - if (ret < 0) - return -1; - - ret = unlinkat (dirfd (dp), dent->d_name, AT_REMOVEDIR); - if (ret < 0) - return -1; - - continue; - } - } - if (ret < 0) - return ret; - } - - return 0; -} - -static int empty_dir (struct ovl_layer *l, const char *path) { cleanup_close int cleanup_fd = -1; int ret; - cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, path, O_DIRECTORY)); + cleanup_fd = TEMP_FAILURE_RETRY (safe_openat (l->fd, path, O_DIRECTORY, 0)); if (cleanup_fd < 0) return -1; @@ -3171,7 +3179,7 @@ /* try to create directly the file if it doesn't need to be chowned. */ if (uid == lo->uid && gid == lo->gid) { - ret = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, path, flags, mode)); + ret = TEMP_FAILURE_RETRY (safe_openat (get_upper_layer (lo)->fd, path, flags, mode)); if (ret >= 0) return ret; /* if it fails (e.g. there is a whiteout) then fallback to create it in @@ -3180,7 +3188,7 @@ sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); - fd = TEMP_FAILURE_RETRY (openat (lo->workdir_fd, wd_tmp_file_name, flags, mode)); + fd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, flags, mode)); if (fd < 0) return -1; if (uid != lo->uid || gid != lo->gid) @@ -3590,7 +3598,7 @@ switch (mode & S_IFMT) { case S_IFREG: - cleaned_up_fd = fd = TEMP_FAILURE_RETRY (openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK|(to_set & FUSE_SET_ATTR_SIZE ? O_WRONLY : 0))); + cleaned_up_fd = fd = TEMP_FAILURE_RETRY (safe_openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK|(to_set & FUSE_SET_ATTR_SIZE ? O_WRONLY : 0), 0)); if (fd < 0) { fuse_reply_err (req, errno); @@ -3599,7 +3607,7 @@ break; case S_IFDIR: - cleaned_up_fd = fd = TEMP_FAILURE_RETRY (openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK)); + cleaned_up_fd = fd = TEMP_FAILURE_RETRY (safe_openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK, 0)); if (fd < 0) { if (errno != ELOOP) @@ -3611,7 +3619,7 @@ break; case S_IFLNK: - cleaned_up_fd = TEMP_FAILURE_RETRY (openat (dirfd, node->path, O_PATH|O_NOFOLLOW|O_NONBLOCK)); + cleaned_up_fd = TEMP_FAILURE_RETRY (safe_openat (dirfd, node->path, O_PATH|O_NOFOLLOW|O_NONBLOCK, 0)); if (cleaned_up_fd < 0) { fuse_reply_err (req, errno); @@ -3646,7 +3654,7 @@ if (fd >= 0) ret = futimens (fd, times); else - ret = utimensat (AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW); + ret = utimensat (AT_FDCWD, path, times, 0); if (ret < 0) { fuse_reply_err (req, errno); @@ -3981,7 +3989,7 @@ if (pnode == NULL) goto error; - ret = TEMP_FAILURE_RETRY (openat (node_dirfd (pnode), pnode->path, O_DIRECTORY)); + ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (pnode), pnode->path, O_DIRECTORY, 0)); if (ret < 0) goto error; srcfd = ret; @@ -3990,7 +3998,7 @@ if (destpnode == NULL) goto error; - ret = TEMP_FAILURE_RETRY (openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY)); + ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY, 0)); if (ret < 0) goto error; destfd = ret; @@ -4016,7 +4024,7 @@ goto error; - ret = direct_renameat2 (node->layer, srcfd, name, destfd, newname, flags); + ret = direct_renameat2 (srcfd, name, destfd, newname, flags); if (ret < 0) goto error; @@ -4106,7 +4114,7 @@ if (pnode == NULL) goto error; - ret = TEMP_FAILURE_RETRY (openat (node_dirfd (pnode), pnode->path, O_DIRECTORY)); + ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (pnode), pnode->path, O_DIRECTORY, 0)); if (ret < 0) goto error; srcfd = ret; @@ -4115,7 +4123,7 @@ if (destpnode == NULL) goto error; - ret = TEMP_FAILURE_RETRY (openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY)); + ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY, 0)); if (ret < 0) goto error; destfd = ret; @@ -4189,7 +4197,7 @@ so that with one operation we get both the rename and the whiteout created. */ if (destnode_is_whiteout) { - ret = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd, newname, flags|RENAME_EXCHANGE); + ret = direct_renameat2 (srcfd, name, destfd, newname, flags|RENAME_EXCHANGE); if (ret == 0) goto done; @@ -4209,11 +4217,11 @@ /* Try to create the whiteout atomically, if it fails do the rename+mknod separately. */ - ret = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd, + ret = direct_renameat2 (srcfd, name, destfd, newname, flags|RENAME_WHITEOUT); if (ret < 0) { - ret = direct_renameat2 (get_upper_layer (lo), srcfd, name, destfd, + ret = direct_renameat2 (srcfd, name, destfd, newname, flags); if (ret < 0) goto error; @@ -4622,7 +4630,7 @@ if (fd < 0) { - cfd = openat (l->fd, path, O_NOFOLLOW|O_DIRECTORY); + cfd = safe_openat (l->fd, path, O_NOFOLLOW|O_DIRECTORY, 0); if (cfd < 0) return cfd; fd = cfd; @@ -4707,7 +4715,7 @@ } static void -ovl_ioctl (fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, +ovl_ioctl (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi, unsigned int flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz) { @@ -4813,7 +4821,7 @@ } dirfd = node_dirfd (node); - fd = openat (dirfd, node->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0755); + fd = safe_openat (dirfd, node->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0); if (fd < 0) { fuse_reply_err (req, errno); @@ -4878,7 +4886,7 @@ return; } - fd_dest = TEMP_FAILURE_RETRY (openat (node_dirfd (dnode), dnode->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY)); + fd_dest = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (dnode), dnode->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0)); if (fd_dest < 0) { fuse_reply_err (req, errno); @@ -4993,6 +5001,8 @@ return 1; if (strcmp (arg, "max_write") == 0) return 1; + if (strcmp (arg, "ro") == 0) + return 1; if (key == FUSE_OPT_KEY_NONOPT) { @@ -5013,7 +5023,12 @@ get_new_args (int *argc, char **argv) { int i; - char **newargv = malloc (sizeof (char *) * (*argc + 2)); + char **newargv; + + newargv = malloc (sizeof (char *) * (*argc + 2)); + if (newargv == NULL) + error (EXIT_FAILURE, 0, "error allocating memory"); + newargv[0] = argv[0]; if (geteuid() == 0) newargv[1] = "-odefault_permissions,allow_other,suid,noatime,lazytime"; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/tests/fedora-installs.sh new/fuse-overlayfs-1.1.0/tests/fedora-installs.sh --- old/fuse-overlayfs-1.0.0/tests/fedora-installs.sh 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/tests/fedora-installs.sh 2020-06-18 09:15:04.000000000 +0200 @@ -169,3 +169,22 @@ rm -rf merged/a/3 test $(stat -c %h merged/a) = 4 + +# symlink mtime + +touch merged/afile +ln -s afile merged/alink +touch -h -d "2020-01-02 12:13:14" merged/alink +stat --format "%y" merged/alink | grep "12:13:14" +stat --format "%x" merged/alink | grep "12:13:14" + +# file mtime +touch -h -d "2020-01-02 11:12:13" merged/afile +stat --format "%y" merged/afile | grep "11:12:13" +stat --format "%x" merged/afile | grep "11:12:13" + +# dir mtime +mkdir merged/adir +touch -h -d "2020-01-02 10:11:12" merged/adir +stat --format "%y" merged/adir | grep "10:11:12" +stat --format "%x" merged/adir | grep "10:11:12" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/tests/unlink.sh new/fuse-overlayfs-1.1.0/tests/unlink.sh --- old/fuse-overlayfs-1.0.0/tests/unlink.sh 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/tests/unlink.sh 2020-06-18 09:15:04.000000000 +0200 @@ -1,5 +1,7 @@ #!/bin/sh +rm -rf lower upper workdir merged + mkdir lower upper workdir merged touch lower/a diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/utils.c new/fuse-overlayfs-1.1.0/utils.c --- old/fuse-overlayfs-1.0.0/utils.c 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/utils.c 2020-06-18 09:15:04.000000000 +0200 @@ -25,6 +25,10 @@ #include <fcntl.h> #include <string.h> #include <sys/sysmacros.h> +#include <sys/syscall.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> #ifndef TEMP_FAILURE_RETRY #define TEMP_FAILURE_RETRY(expression) \ @@ -35,6 +39,62 @@ __result; })) #endif +#ifndef RESOLVE_IN_ROOT +# define RESOLVE_IN_ROOT 0x10 +#endif +#ifndef __NR_openat2 +# define __NR_openat2 437 +#endif + +/* List of all valid flags for the open/openat flags argument: */ +#define VALID_OPEN_FLAGS \ + (O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \ + O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | O_SYNC | O_DSYNC | \ + FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \ + O_NOATIME | O_CLOEXEC | O_PATH | O_TMPFILE) + +static int +syscall_openat2 (int dirfd, const char *path, uint64_t flags, uint64_t mode, uint64_t resolve) +{ + struct openat2_open_how + { + uint64_t flags; + uint64_t mode; + uint64_t resolve; + } + how = + { + .flags = flags & VALID_OPEN_FLAGS, + .mode = (flags & O_CREAT) ? (mode & 07777) : 0, + .resolve = resolve, + }; + + return (int) syscall (__NR_openat2, dirfd, path, &how, sizeof (how), 0); +} + +int +safe_openat (int dirfd, const char *pathname, int flags, mode_t mode) +{ + static bool openat2_supported = true; + + if (openat2_supported) + { + int ret; + + ret = syscall_openat2 (dirfd, pathname, flags, mode, RESOLVE_IN_ROOT); + if (ret < 0) + { + if (errno == ENOSYS) + openat2_supported = false; + if (errno == ENOSYS || errno == EINVAL) + goto fallback; + } + return ret; + } + fallback: + return openat (dirfd, pathname, flags, mode); +} + int file_exists_at (int dirfd, const char *pathname) { @@ -148,7 +208,7 @@ { out[0] = '\0'; - *fd = l->ds->openat (l, path, O_NONBLOCK|O_NOFOLLOW|flags, 0755); + *fd = l->ds->openat (l, path, O_NONBLOCK|O_NOFOLLOW|flags, 0); if (*fd < 0 && (errno == ELOOP || errno == EISDIR || errno == ENXIO)) { strconcat3 (out, PATH_MAX, l->path, "/", path); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/fuse-overlayfs-1.0.0/utils.h new/fuse-overlayfs-1.1.0/utils.h --- old/fuse-overlayfs-1.0.0/utils.h 2020-04-17 11:10:44.000000000 +0200 +++ new/fuse-overlayfs-1.1.0/utils.h 2020-06-18 09:15:04.000000000 +0200 @@ -53,4 +53,6 @@ void statx_to_stat (struct statx *stx, struct stat *st); # endif +int safe_openat (int dirfd, const char *pathname, int flags, mode_t mode); + #endif