From effc4950accde39245def1ddc7d0e3ea680ea2ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= Date: Mon, 11 Sep 2023 14:33:56 +0200 Subject: [PATCH] fix cp -p not copying NFSv4 acls Resolves: rhbz#2160675 --- ...ils-9.3-cp--p-should-copy-NFSv4-acls.patch | 217 ++++++++++++++++++ coreutils.spec | 9 +- 2 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 coreutils-9.3-cp--p-should-copy-NFSv4-acls.patch diff --git a/coreutils-9.3-cp--p-should-copy-NFSv4-acls.patch b/coreutils-9.3-cp--p-should-copy-NFSv4-acls.patch new file mode 100644 index 0000000..e1ff720 --- /dev/null +++ b/coreutils-9.3-cp--p-should-copy-NFSv4-acls.patch @@ -0,0 +1,217 @@ +commit ccda8a2aedad84d9b730fdd6b36baa9582f54bfd +Author: rpm-build +Date: Mon Sep 11 14:28:05 2023 +0200 + + coreutils-9.3-cp--p-should-copy-NFSv4-acls.patch + +Cherry picked from the following gnulib upstream commits: +* b851a965da62cd858d71b2e5a7261a211f00b297 ("file-has-acl: port to Fedora 39") +* f01d8792778b637f7464533ac019e42f58adb310 ("file-has-acl: don’t access freed storage") +* 735716931755c74f3788ac83fead717c0bb22dfe ("file-has-acl: improve port to Fedora 39") + +diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c +index b31a2ea..4cddc80 100644 +--- a/lib/file-has-acl.c ++++ b/lib/file-has-acl.c +@@ -29,7 +29,10 @@ + + #include "acl-internal.h" + +-#if USE_ACL && GETXATTR_WITH_POSIX_ACLS ++#include "minmax.h" ++ ++#if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR ++# include + # include + # include + # include +@@ -44,6 +47,20 @@ enum { + ACE4_IDENTIFIER_GROUP = 0x00000040 + }; + ++/* Return true if ATTR is in the set represented by the NUL-terminated ++ strings in LISTBUF, which is of size LISTSIZE. */ ++ ++static bool ++have_xattr (char const *attr, char const *listbuf, ssize_t listsize) ++{ ++ char const *blim = listbuf + listsize; ++ for (char const *b = listbuf; b < blim; b += strlen (b) + 1) ++ for (char const *a = attr; *a == *b; a++, b++) ++ if (!*a) ++ return true; ++ return false; ++} ++ + /* Return 1 if given ACL in XDR format is non-trivial, 0 if it is trivial. + -1 upon failure to determine it. Possibly change errno. Assume that + the ACL is valid, except avoid undefined behavior even if invalid. +@@ -137,37 +154,77 @@ file_has_acl (char const *name, struct stat const *sb) + if (! S_ISLNK (sb->st_mode)) + { + +-# if GETXATTR_WITH_POSIX_ACLS +- +- ssize_t ret; ++# if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR + int initial_errno = errno; + +- ret = getxattr (name, XATTR_NAME_POSIX_ACL_ACCESS, NULL, 0); +- if (ret < 0 && errno == ENODATA) +- ret = 0; +- else if (ret > 0) +- return 1; +- +- if (ret == 0 && S_ISDIR (sb->st_mode)) ++ /* The max length of a trivial NFSv4 ACL is 6 words for owner, ++ 6 for group, 7 for everyone, all times 2 because there are ++ both allow and deny ACEs. There are 6 words for owner ++ because of type, flag, mask, wholen, "OWNER@"+pad and ++ similarly for group; everyone is another word to hold ++ "EVERYONE@". */ ++ typedef uint32_t trivial_NFSv4_xattr_buf[2 * (6 + 6 + 7)]; ++ ++ /* A buffer large enough to hold any trivial NFSv4 ACL, ++ and also useful as a small array of char. */ ++ union { ++ trivial_NFSv4_xattr_buf xattr; ++ char ch[sizeof (trivial_NFSv4_xattr_buf)]; ++ } stackbuf; ++ ++ char *listbuf = stackbuf.ch; ++ ssize_t listbufsize = sizeof stackbuf.ch; ++ char *heapbuf = NULL; ++ ssize_t listsize; ++ ++ /* Use listxattr first, as this means just one syscall in the ++ typical case where the file lacks an ACL. Try stackbuf ++ first, falling back on malloc if stackbuf is too small. */ ++ while ((listsize = listxattr (name, listbuf, listbufsize)) < 0 ++ && errno == ERANGE) + { +- ret = getxattr (name, XATTR_NAME_POSIX_ACL_DEFAULT, NULL, 0); +- if (ret < 0 && errno == ENODATA) +- ret = 0; +- else if (ret > 0) +- return 1; ++ free (heapbuf); ++ ssize_t newsize = listxattr (name, NULL, 0); ++ if (newsize <= 0) ++ return newsize; ++ ++ /* Grow LISTBUFSIZE to at least NEWSIZE. Grow it by a ++ nontrivial amount too, to defend against denial of ++ service by an adversary that fiddles with ACLs. */ ++ bool overflow = ckd_add (&listbufsize, listbufsize, listbufsize >> 1); ++ listbufsize = MAX (listbufsize, newsize); ++ if (overflow || SIZE_MAX < listbufsize) ++ { ++ errno = ENOMEM; ++ return -1; ++ } ++ ++ listbuf = heapbuf = malloc (listbufsize); ++ if (!listbuf) ++ return -1; + } + +- if (ret < 0) ++ /* In Fedora 39, a file can have both NFSv4 and POSIX ACLs, ++ but if it has an NFSv4 ACL that's the one that matters. ++ In earlier Fedora the two types of ACLs were mutually exclusive. ++ Attempt to work correctly on both kinds of systems. */ ++ bool nfsv4_acl ++ = 0 < listsize && have_xattr (XATTR_NAME_NFSV4_ACL, listbuf, listsize); ++ int ret ++ = (listsize <= 0 ? listsize ++ : (nfsv4_acl ++ || have_xattr (XATTR_NAME_POSIX_ACL_ACCESS, listbuf, listsize) ++ || (S_ISDIR (sb->st_mode) ++ && have_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, ++ listbuf, listsize)))); ++ free (heapbuf); ++ ++ /* If there is an NFSv4 ACL, follow up with a getxattr syscall ++ to see whether the NFSv4 ACL is nontrivial. */ ++ if (nfsv4_acl) + { +- /* Check for NFSv4 ACLs. The max length of a trivial +- ACL is 6 words for owner, 6 for group, 7 for everyone, +- all times 2 because there are both allow and deny ACEs. +- There are 6 words for owner because of type, flag, mask, +- wholen, "OWNER@"+pad and similarly for group; everyone is +- another word to hold "EVERYONE@". */ +- uint32_t xattr[2 * (6 + 6 + 7)]; +- +- ret = getxattr (name, XATTR_NAME_NFSV4_ACL, xattr, sizeof xattr); ++ ret = getxattr (name, XATTR_NAME_NFSV4_ACL, ++ stackbuf.xattr, sizeof stackbuf.xattr); + if (ret < 0) + switch (errno) + { +@@ -177,7 +234,7 @@ file_has_acl (char const *name, struct stat const *sb) + else + { + /* It looks like a trivial ACL, but investigate further. */ +- ret = acl_nfs4_nontrivial (xattr, ret); ++ ret = acl_nfs4_nontrivial (stackbuf.xattr, ret); + if (ret < 0) + { + errno = EINVAL; +diff --git a/m4/acl.m4 b/m4/acl.m4 +index dc9853a..3fa0779 100644 +--- a/m4/acl.m4 ++++ b/m4/acl.m4 +@@ -177,37 +177,23 @@ AC_DEFUN([gl_ACL_GET_FILE], + AS_IF([test "$gl_cv_func_working_acl_get_file" != no], [$1], [$2]) + ]) + +-# On GNU/Linux, testing if a file has an acl can be done with the getxattr +-# syscall which doesn't require linking against additional libraries. ++# On GNU/Linux, testing if a file has an acl can be done with the ++# listxattr and getxattr syscalls, which don't require linking ++# against additional libraries. Assume this works if linux/attr.h ++# and listxattr are present. + AC_DEFUN([gl_FILE_HAS_ACL], + [ + AC_REQUIRE([gl_FUNC_ACL_ARG]) +- if test "$enable_acl" != no; then +- AC_CACHE_CHECK([for getxattr with XATTR_NAME_POSIX_ACL macros], +- [gl_cv_getxattr_with_posix_acls], +- [gl_cv_getxattr_with_posix_acls=no +- AC_LINK_IFELSE( +- [AC_LANG_PROGRAM( +- [[#include +- #include +- #include +- ]], +- [[ssize_t a = getxattr (".", XATTR_NAME_POSIX_ACL_ACCESS, 0, 0); +- ssize_t b = getxattr (".", XATTR_NAME_POSIX_ACL_DEFAULT, 0, 0); +- return a < 0 || b < 0; +- ]])], +- [gl_cv_getxattr_with_posix_acls=yes])]) +- fi +- if test "$gl_cv_getxattr_with_posix_acls" = yes; then +- FILE_HAS_ACL_LIB= +- AC_DEFINE([GETXATTR_WITH_POSIX_ACLS], 1, +- [Define to 1 if getxattr works with XATTR_NAME_POSIX_ACL_ACCESS +- and XATTR_NAME_POSIX_ACL_DEFAULT.]) +- else +- dnl Set gl_need_lib_has_acl to a nonempty value, so that any +- dnl later gl_FUNC_ACL call will set FILE_HAS_ACL_LIB=$LIB_ACL. +- gl_need_lib_has_acl=1 +- FILE_HAS_ACL_LIB=$LIB_ACL +- fi ++ AC_CHECK_HEADERS_ONCE([linux/xattr.h]) ++ AC_CHECK_FUNCS_ONCE([listxattr]) ++ FILE_HAS_ACL_LIB= ++ AS_CASE([$enable_acl,$ac_cv_header_linux_xattr_h,$ac_cv_func_listxattr], ++ [no,*,*], [], ++ [*,yes,yes], [], ++ [*], ++ [dnl Set gl_need_lib_has_acl to a nonempty value, so that any ++ dnl later gl_FUNC_ACL call will set FILE_HAS_ACL_LIB=$LIB_ACL. ++ gl_need_lib_has_acl=1 ++ FILE_HAS_ACL_LIB=$LIB_ACL]) + AC_SUBST([FILE_HAS_ACL_LIB]) + ]) diff --git a/coreutils.spec b/coreutils.spec index 2ee1486..ca1c38d 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,7 +1,7 @@ Summary: A set of basic GNU tools commonly used in shell scripts Name: coreutils Version: 9.3 -Release: 3%{?dist} +Release: 4%{?dist} License: GPL-3.0-or-later Url: https://www.gnu.org/software/coreutils/ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz @@ -35,6 +35,10 @@ Patch104: coreutils-df-direct.patch # backport of cc078f747f3db00e70b2ae2ad2ab34e8d54316d3. Patch105: coreutils-9.3-reduce--iu-verbosity-with-verbose.patch +# cp -p should copy NFSv4 acls (#2160675) +# see the patch for the list of backported commits +Patch106: coreutils-9.3-cp--p-should-copy-NFSv4-acls.patch + # (sb) lin18nux/lsb compliance - multibyte functionality patch Patch800: coreutils-i18n.patch @@ -258,6 +262,9 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Mon Sep 11 2023 Lukáš Zaoral - 9.3-4 +- fix cp -p not copying NFSv4 acls (rhbz#2160675) + * Thu Aug 31 2023 Lukáš Zaoral - 9.3-3 - copy: reduce verbosity of -i and -u with --verbose (#2236321)