#13 Fix cp -p not copying NFSv4 acls
Merged 9 months ago by lzaoral. Opened 9 months ago by lzaoral.
rpms/ lzaoral/coreutils bz2160675  into  f39

@@ -0,0 +1,217 @@ 

+ commit ccda8a2aedad84d9b730fdd6b36baa9582f54bfd

+ Author: rpm-build <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 <stdckdint.h>

+  # include <string.h>

+  # include <arpa/inet.h>

+  # include <sys/xattr.h>

+ @@ -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 <sys/types.h>

+ -              #include <sys/xattr.h>

+ -              #include <linux/xattr.h>

+ -            ]],

+ -            [[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])

+  ])

file modified
+8 -1
@@ -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 @@ 

  # 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 @@ 

  %license COPYING

  

  %changelog

+ * Mon Sep 11 2023 Lukáš Zaoral <lzaoral@redhat.com> - 9.3-4

+ - fix cp -p not copying NFSv4 acls (rhbz#2160675)

+ 

  * Thu Aug 31 2023 Lukáš Zaoral <lzaoral@redhat.com> - 9.3-3

  - copy: reduce verbosity of -i and -u with --verbose (#2236321)