From 4fbe411873d44109669215ee59f79369a1ea8b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= Date: Mon, 19 May 2025 09:12:27 +0200 Subject: [PATCH 1/4] cp/mv: do not fail when copying of trivial NFSv4 ACLs fails Resolves: rhbz#2363149 --- ...ils-9.6-cp-improve-nfsv4-acl-support.patch | 573 ++++++++++++++++++ coreutils.spec | 11 +- 2 files changed, 583 insertions(+), 1 deletion(-) create mode 100644 coreutils-9.6-cp-improve-nfsv4-acl-support.patch diff --git a/coreutils-9.6-cp-improve-nfsv4-acl-support.patch b/coreutils-9.6-cp-improve-nfsv4-acl-support.patch new file mode 100644 index 0000000..f2a3840 --- /dev/null +++ b/coreutils-9.6-cp-improve-nfsv4-acl-support.patch @@ -0,0 +1,573 @@ +From 1cddf45cbba44b2afa34291b1b605d39c8cb061c Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Mon, 7 Apr 2025 01:45:17 -0700 +Subject: [PATCH 1/3] file-has-acl: port symlink code to Cygwin + +Problem reported by Corinna Vinschen in: +https://lists.gnu.org/r/bug-gnulib/2025-03/msg00112.html +* lib/file-has-acl.c (acl_get_link_np): New static function, +defined only if needed; include if needed for this. +(HAVE_ACL_GET_LINK_NP): Define this if defining acl_get_link_np. + +(cherry picked from commit 41e7b7e0d159d8ac0eb385964119f350ac9dfc3f) +--- + lib/file-has-acl.c | 25 ++++++++++++++++++++++++- + 1 file changed, 24 insertions(+), 1 deletion(-) + +diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c +index c02cfee..59ad9b9 100644 +--- a/lib/file-has-acl.c ++++ b/lib/file-has-acl.c +@@ -363,6 +363,29 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes) + } + #endif + ++#if (!USE_LINUX_XATTR && USE_ACL && HAVE_ACL_GET_FD \ ++ && !HAVE_ACL_EXTENDED_FILE && !HAVE_ACL_TYPE_EXTENDED \ ++ && !HAVE_ACL_GET_LINK_NP) ++# include ++# ifdef O_PATH ++ ++/* Like acl_get_file, but do not follow symbolic links. */ ++static acl_t ++acl_get_link_np (char const *name, acl_type_t type) ++{ ++ int fd = open (name, O_PATH | O_NOFOLLOW); ++ if (fd < 0) ++ return NULL; ++ acl_t r = acl_get_fd (fd); ++ int err = errno; ++ close (fd); ++ errno = err; ++ return r; ++} ++# define HAVE_ACL_GET_LINK_NP 1 ++# endif ++#endif ++ + /* Return 1 if NAME has a nontrivial access control list, + 0 if ACLs are not supported, or if NAME has no or only a base ACL, + and -1 (setting errno) on error. Note callers can determine +@@ -468,7 +491,7 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + ret = -1; + # else /* FreeBSD, NetBSD >= 10, IRIX, Tru64, Cygwin >= 2.5 */ + acl_t (*acl_get_file_or_link) (char const *, acl_type_t) = acl_get_file; +-# if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10 */ ++# if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10, Cygwin >= 2.5 */ + if (! (flags & ACL_SYMLINK_FOLLOW)) + acl_get_file_or_link = acl_get_link_np; + # endif +-- +2.49.0 + +From a0e61926b04ff6ec0449607ba306c1b5770660d3 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Fri, 9 May 2025 18:02:29 -0700 +Subject: [PATCH 2/3] qcopy-acl: port better to NFSv4 on GNU/Linux + +Problem reported by Ian Dall in +and by Thomas Clark in . +* lib/file-has-acl.c (smack_new_label_from_file) [!HAVE_SMACK]: +New dummy function. +(has_xattr, get_aclinfo): New arg FD. All callers changed. +Remove some unnecessary MAYBE_UNUSEDs. +(acl_get_fd_np): Fall back on acl_get_fd if this function is +needed but not available. +(acl_get_fdfile): New function, if needed. +(file_has_aclinfo): Reimplement in terms of ... +(fdfile_has_aclinfo): ... this new function, +which also has an FD argument. +* lib/qcopy-acl.c [USE_XATTR]: Include dirent.h, for DT_DIR etc. +(qcopy_acl): If attr_copy_file or attr_copy_fd fail with EOPNOTSUPP, +don’t fail if the source has a trivial ACL (this is the part +that fixes the bug; the rest is optimization). + +(cherry picked from commit 8a356b77717a2e4f735ec06e326880ca1f61aadb) +--- + lib/acl.h | 2 + + lib/copy-acl.c | 1 + + lib/file-has-acl.c | 172 ++++++++++++++++++++++++++++++++------------- + lib/qcopy-acl.c | 29 ++++++-- + 4 files changed, 152 insertions(+), 52 deletions(-) + +diff --git a/lib/acl.h b/lib/acl.h +index 90fd24e..e3c134f 100644 +--- a/lib/acl.h ++++ b/lib/acl.h +@@ -79,6 +79,8 @@ struct aclinfo + bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST; + int file_has_acl (char const *, struct stat const *); + int file_has_aclinfo (char const *restrict, struct aclinfo *restrict, int); ++int fdfile_has_aclinfo (int, char const *restrict, ++ struct aclinfo *restrict, int); + + #if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR + bool aclinfo_has_xattr (struct aclinfo const *, char const *) +diff --git a/lib/copy-acl.c b/lib/copy-acl.c +index c36f64e..2fce6c7 100644 +--- a/lib/copy-acl.c ++++ b/lib/copy-acl.c +@@ -33,6 +33,7 @@ + a valid file descriptor, use file descriptor operations, else use + filename based operations on SRC_NAME. Likewise for DEST_DESC and + DST_NAME. ++ MODE should be the source file's st_mode. + If access control lists are not available, fchmod the target file to + MODE. Also sets the non-permission bits of the destination file + (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set. +diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c +index 59ad9b9..afd951a 100644 +--- a/lib/file-has-acl.c ++++ b/lib/file-has-acl.c +@@ -86,6 +86,13 @@ smack_new_label_from_path (MAYBE_UNUSED const char *path, + { + return -1; + } ++static ssize_t ++smack_new_label_from_file (MAYBE_UNUSED int fd, ++ MAYBE_UNUSED const char *xattr, ++ MAYBE_UNUSED char **label) ++{ ++ return -1; ++} + # endif + static bool + is_smack_enabled (void) +@@ -116,14 +123,16 @@ aclinfo_may_indicate_xattr (struct aclinfo const *ai) + + static bool + has_xattr (char const *xattr, struct aclinfo const *ai, +- MAYBE_UNUSED char const *restrict name, MAYBE_UNUSED int flags) ++ int fd, char const *restrict name, int flags) + { + if (ai && aclinfo_has_xattr (ai, xattr)) + return true; + else if (!ai || aclinfo_may_indicate_xattr (ai)) + { +- int ret = ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr) +- (name, xattr, NULL, 0)); ++ int ret = (fd < 0 ++ ? ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr) ++ (name, xattr, NULL, 0)) ++ : fgetxattr (fd, xattr, NULL, 0)); + if (0 <= ret || (errno == ERANGE || errno == E2BIG)) + return true; + } +@@ -146,11 +155,12 @@ aclinfo_has_xattr (struct aclinfo const *ai, char const *xattr) + return false; + } + +-/* Get attributes of the file NAME into AI, if USE_ACL. ++/* Get attributes of the file FD aka NAME into AI, if USE_ACL. ++ Ignore FD if it is negative. + If FLAGS & ACL_GET_SCONTEXT, also get security context. + If FLAGS & ACL_SYMLINK_FOLLOW, follow symbolic links. */ + static void +-get_aclinfo (char const *name, struct aclinfo *ai, int flags) ++get_aclinfo (int fd, char const *name, struct aclinfo *ai, int flags) + { + int scontext_err = ENOTSUP; + ai->buf = ai->u.__gl_acl_ch; +@@ -164,7 +174,9 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags) + = (flags & ACL_SYMLINK_FOLLOW ? listxattr : llistxattr); + while (true) + { +- ai->size = lsxattr (name, ai->buf, acl_alloc); ++ ai->size = (fd < 0 ++ ? lsxattr (name, ai->buf, acl_alloc) ++ : flistxattr (fd, ai->buf, acl_alloc)); + if (0 < ai->size) + break; + ai->u.err = ai->size < 0 ? errno : 0; +@@ -172,7 +184,9 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags) + break; + + /* The buffer was too small. Find how large it should have been. */ +- ssize_t size = lsxattr (name, NULL, 0); ++ ssize_t size = (fd < 0 ++ ? lsxattr (name, NULL, 0) ++ : flistxattr (fd, NULL, 0)); + if (size <= 0) + { + ai->size = size; +@@ -215,9 +229,13 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags) + { + if (ai->size < 0 || aclinfo_has_xattr (ai, XATTR_NAME_SMACK)) + { +- ssize_t r = smack_new_label_from_path (name, "security.SMACK64", +- flags & ACL_SYMLINK_FOLLOW, +- &ai->scontext); ++ static char const SMACK64[] = "security.SMACK64"; ++ ssize_t r = ++ (fd < 0 ++ ? smack_new_label_from_path (name, SMACK64, ++ flags & ACL_SYMLINK_FOLLOW, ++ &ai->scontext) ++ : smack_new_label_from_file (fd, SMACK64, &ai->scontext)); + scontext_err = r < 0 ? errno : 0; + } + } +@@ -227,8 +245,10 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags) + if (ai->size < 0 || aclinfo_has_xattr (ai, XATTR_NAME_SELINUX)) + { + ssize_t r = +- ((flags & ACL_SYMLINK_FOLLOW ? getfilecon : lgetfilecon) +- (name, &ai->scontext)); ++ (fd < 0 ++ ? ((flags & ACL_SYMLINK_FOLLOW ? getfilecon : lgetfilecon) ++ (name, &ai->scontext)) ++ : fgetfilecon (fd, &ai->scontext)); + scontext_err = r < 0 ? errno : 0; + # ifndef SE_SELINUX_INLINE + /* Gnulib's selinux-h module is not in use, so getfilecon and +@@ -363,11 +383,13 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes) + } + #endif + +-#if (!USE_LINUX_XATTR && USE_ACL && HAVE_ACL_GET_FD \ +- && !HAVE_ACL_EXTENDED_FILE && !HAVE_ACL_TYPE_EXTENDED \ +- && !HAVE_ACL_GET_LINK_NP) +-# include +-# ifdef O_PATH ++#if (!USE_LINUX_XATTR && USE_ACL && !HAVE_ACL_EXTENDED_FILE \ ++ && !HAVE_ACL_TYPE_EXTENDED) ++ ++# if HAVE_ACL_GET_FD && !HAVE_ACL_GET_LINK_NP ++# include ++# ifdef O_PATH ++# define acl_get_fd_np(fd, type) acl_get_fd (fd) + + /* Like acl_get_file, but do not follow symbolic links. */ + static acl_t +@@ -382,8 +404,24 @@ acl_get_link_np (char const *name, acl_type_t type) + errno = err; + return r; + } +-# define HAVE_ACL_GET_LINK_NP 1 ++# define HAVE_ACL_GET_LINK_NP 1 ++# endif + # endif ++ ++static acl_t ++acl_get_fdfile (int fd, char const *name, acl_type_t type, int flags) ++{ ++ acl_t (*get) (char const *, acl_type_t) = acl_get_file; ++# if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10, Cygwin >= 2.5 */ ++ if (0 <= fd) ++ return acl_get_fd_np (fd, type); ++ if (! (flags & ACL_SYMLINK_FOLLOW)) ++ get = acl_get_link_np; ++# else ++ /* Ignore FD and FLAGS, unfortunately. */ ++# endif ++ return get (name, type); ++} + #endif + + /* Return 1 if NAME has a nontrivial access control list, +@@ -399,14 +437,35 @@ acl_get_link_np (char const *name, acl_type_t type) + If the d_type value is not known, use DT_UNKNOWN though this may be less + efficient. */ + int +-file_has_aclinfo (MAYBE_UNUSED char const *restrict name, ++file_has_aclinfo (char const *restrict name, + struct aclinfo *restrict ai, int flags) ++{ ++ return fdfile_has_aclinfo (-1, name, ai, flags); ++} ++ ++/* Return 1 if FD aka NAME has a nontrivial access control list, ++ 0 if ACLs are not supported, or if NAME has no or only a base ACL, ++ and -1 (setting errno) on error. Note callers can determine ++ if ACLs are not supported as errno is set in that case also. ++ Ignore FD if it is negative. ++ Set *AI to ACL info regardless of return value. ++ FLAGS should be a d_type value, optionally ORed with ++ - _GL_DT_NOTDIR if it is known that NAME is not a directory, ++ - ACL_GET_SCONTEXT to retrieve security context and return 1 if present, ++ - ACL_SYMLINK_FOLLOW to follow the link if NAME is a symbolic link; ++ otherwise do not follow them if possible. ++ If the d_type value is not known, use DT_UNKNOWN though this may be less ++ efficient. */ ++int ++fdfile_has_aclinfo (MAYBE_UNUSED int fd, ++ MAYBE_UNUSED char const *restrict name, ++ struct aclinfo *restrict ai, int flags) + { + MAYBE_UNUSED unsigned char d_type = flags & UCHAR_MAX; + + #if USE_LINUX_XATTR + int initial_errno = errno; +- get_aclinfo (name, ai, flags); ++ get_aclinfo (fd, name, ai, flags); + + if (!aclinfo_may_indicate_xattr (ai) && ai->size <= 0) + { +@@ -419,11 +478,11 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + In earlier Fedora the two types of ACLs were mutually exclusive. + Attempt to work correctly on both kinds of systems. */ + +- if (!has_xattr (XATTR_NAME_NFSV4_ACL, ai, name, flags)) ++ if (!has_xattr (XATTR_NAME_NFSV4_ACL, ai, fd, name, flags)) + return +- (has_xattr (XATTR_NAME_POSIX_ACL_ACCESS, ai, name, flags) ++ (has_xattr (XATTR_NAME_POSIX_ACL_ACCESS, ai, fd, name, flags) + || ((d_type == DT_DIR || d_type == DT_UNKNOWN) +- && has_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, ai, name, flags))); ++ && has_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, ai, fd, name, flags))); + + /* A buffer large enough to hold any trivial NFSv4 ACL. + The max length of a trivial NFSv4 ACL is 6 words for owner, +@@ -433,8 +492,10 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + everyone is another word to hold "EVERYONE@". */ + uint32_t buf[2 * (6 + 6 + 7)]; + +- int ret = ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr) +- (name, XATTR_NAME_NFSV4_ACL, buf, sizeof buf)); ++ int ret = (fd < 0 ++ ? ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr) ++ (name, XATTR_NAME_NFSV4_ACL, buf, sizeof buf)) ++ : fgetxattr (fd, XATTR_NAME_NFSV4_ACL, buf, sizeof buf)); + if (ret < 0) + switch (errno) + { +@@ -468,20 +529,23 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + /* On Linux, acl_extended_file is an optimized function: It only + makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for + ACL_TYPE_DEFAULT. */ +- ret = ((flags & ACL_SYMLINK_FOLLOW +- ? acl_extended_file +- : acl_extended_file_nofollow) +- (name)); ++ ret = (fd < 0 ++ ? ((flags & ACL_SYMLINK_FOLLOW ++ ? acl_extended_file ++ : acl_extended_file_nofollow) ++ (name)) ++ : acl_extended_fd (fd)); + # elif HAVE_ACL_TYPE_EXTENDED /* Mac OS X */ + /* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS) + and acl_get_file (name, ACL_TYPE_DEFAULT) + always return NULL / EINVAL. There is no point in making + these two useless calls. The real ACL is retrieved through +- acl_get_file (name, ACL_TYPE_EXTENDED). */ +- acl_t acl = ((flags & ACL_SYMLINK_FOLLOW +- ? acl_get_file +- : acl_get_link_np) +- (name, ACL_TYPE_EXTENDED)); ++ ACL_TYPE_EXTENDED. */ ++ acl_t acl = ++ (fd < 0 ++ ? ((flags & ACL_SYMLINK_FOLLOW ? acl_get_file : acl_get_link_np) ++ (name, ACL_TYPE_EXTENDED)) ++ : acl_get_fd_np (fd, ACL_TYPE_EXTENDED)); + if (acl) + { + ret = acl_extended_nontrivial (acl); +@@ -490,13 +554,8 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + else + ret = -1; + # else /* FreeBSD, NetBSD >= 10, IRIX, Tru64, Cygwin >= 2.5 */ +- acl_t (*acl_get_file_or_link) (char const *, acl_type_t) = acl_get_file; +-# if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10, Cygwin >= 2.5 */ +- if (! (flags & ACL_SYMLINK_FOLLOW)) +- acl_get_file_or_link = acl_get_link_np; +-# endif + +- acl_t acl = acl_get_file_or_link (name, ACL_TYPE_ACCESS); ++ acl_t acl = acl_get_fdfile (fd, name, ACL_TYPE_ACCESS, flags); + if (acl) + { + ret = acl_access_nontrivial (acl); +@@ -518,7 +577,7 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + && (d_type == DT_DIR + || (d_type == DT_UNKNOWN && !(flags & _GL_DT_NOTDIR)))) + { +- acl = acl_get_file_or_link (name, ACL_TYPE_DEFAULT); ++ acl = acl_get_fdfile (fd, name, ACL_TYPE_DEFAULT, flags); + if (acl) + { + # ifdef __CYGWIN__ /* Cygwin >= 2.5 */ +@@ -563,7 +622,10 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + + /* Solaris 10 (newer version), which has additional API declared in + (acl_t) and implemented in libsec (acl_set, acl_trivial, +- acl_fromtext, ...). */ ++ acl_fromtext, ...). ++ ++ Ignore FD, unfortunately. That is better than mishandling ++ ZFS-style ACLs, as the general case code does. */ + return acl_trivial (name); + + # else /* Solaris, Cygwin, general case */ +@@ -587,7 +649,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + + for (;;) + { +- count = acl (name, GETACL, alloc, entries); ++ count = (fd < 0 ++ ? acl (name, GETACL, alloc, entries) ++ : facl (fd, GETACL, alloc, entries)); + if (count < 0 && errno == ENOSPC) + { + /* Increase the size of the buffer. */ +@@ -658,7 +722,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + + for (;;) + { +- count = acl (name, ACE_GETACL, alloc, entries); ++ count = (fd < 0 ++ ? acl (name, ACE_GETACL, alloc, entries) ++ : facl (fd, ACE_GETACL, alloc, entries)); + if (count < 0 && errno == ENOSPC) + { + /* Increase the size of the buffer. */ +@@ -723,7 +789,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + struct acl_entry entries[NACLENTRIES]; + int count; + +- count = getacl (name, NACLENTRIES, entries); ++ count = (fd < 0 ++ ? getacl (name, NACLENTRIES, entries) ++ : fgetacl (fd, NACLENTRIES, entries)); + + if (count < 0) + { +@@ -752,7 +820,8 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + { + struct stat statbuf; + +- if (stat (name, &statbuf) == -1 && errno != EOVERFLOW) ++ if ((fd < 0 ? stat (name, &statbuf) : fstat (fd, &statbuf)) < 0 ++ && errno != EOVERFLOW) + return -1; + + return acl_nontrivial (count, entries); +@@ -766,6 +835,7 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + struct acl entries[NACLVENTRIES]; + int count; + ++ /* Ignore FD, unfortunately. */ + count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries); + + if (count < 0) +@@ -810,7 +880,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + /* The docs say that type being 0 is equivalent to ACL_ANY, but it + is not true, in AIX 5.3. */ + type.u64 = ACL_ANY; +- if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0) ++ if (0 <= (fd < 0 ++ ? aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) ++ : aclx_fget (fd, 0, &type, aclbuf, &aclsize, &mode))) + break; + if (errno == ENOSYS) + return 0; +@@ -856,7 +928,10 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + + union { struct acl a; char room[4096]; } u; + +- if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0) ++ if ((fd < 0 ++ ? statacl ((char *) name, STX_NORMAL, &u.a, sizeof u) ++ : fstatacl (fd, STX_NORMAL, &u.a, sizeof u)) ++ < 0) + return -1; + + return acl_nontrivial (&u.a); +@@ -867,6 +942,7 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name, + struct acl entries[NACLENTRIES]; + int count; + ++ /* Ignore FD, unfortunately. */ + count = acl ((char *) name, ACL_GET, NACLENTRIES, entries); + + if (count < 0) +diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c +index ad79661..282f4b2 100644 +--- a/lib/qcopy-acl.c ++++ b/lib/qcopy-acl.c +@@ -26,6 +26,7 @@ + #if USE_XATTR + + # include ++# include + # include + + # if HAVE_LINUX_XATTR_H +@@ -61,6 +62,7 @@ is_attr_permissions (const char *name, struct error_context *ctx) + a valid file descriptor, use file descriptor operations, else use + filename based operations on SRC_NAME. Likewise for DEST_DESC and + DST_NAME. ++ MODE should be the source file's st_mode. + If access control lists are not available, fchmod the target file to + MODE. Also sets the non-permission bits of the destination file + (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set. +@@ -86,10 +88,29 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name, + Functions attr_copy_* return 0 in case we copied something OR nothing + to copy */ + if (ret == 0) +- ret = source_desc <= 0 || dest_desc <= 0 +- ? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL) +- : attr_copy_fd (src_name, source_desc, dst_name, dest_desc, +- is_attr_permissions, NULL); ++ { ++ ret = source_desc <= 0 || dest_desc <= 0 ++ ? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL) ++ : attr_copy_fd (src_name, source_desc, dst_name, dest_desc, ++ is_attr_permissions, NULL); ++ ++ /* Copying can fail with EOPNOTSUPP even when the source ++ permissions are trivial (Bug#78328). Don't report an error ++ in this case, as the chmod_or_fchmod suffices. */ ++ if (ret < 0 && errno == EOPNOTSUPP) ++ { ++ /* fdfile_has_aclinfo cares only about DT_DIR, _GL_DT_NOTDIR, ++ and DT_LNK (but DT_LNK is not possible here), ++ so use _GL_DT_NOTDIR | DT_UNKNOWN for other file types. */ ++ int flags = S_ISDIR (mode) ? DT_DIR : _GL_DT_NOTDIR | DT_UNKNOWN; ++ ++ struct aclinfo ai; ++ if (!fdfile_has_aclinfo (source_desc, src_name, &ai, flags)) ++ ret = 0; ++ aclinfo_free (&ai); ++ errno = EOPNOTSUPP; ++ } ++ } + #else + /* no XATTR, so we proceed the old dusty way */ + struct permission_context ctx; +-- +2.49.0 + +From 6595a08347c03321e1061ae747f02e4fe67e2073 Mon Sep 17 00:00:00 2001 +From: Paul Eggert +Date: Fri, 9 May 2025 18:48:03 -0700 +Subject: [PATCH 3/3] acl-tests: link with $(FILE_HAS_ACL_LIB) + +* modules/acl-tests (test_copy_acl_LDADD): Add +$(FILE_HAS_ACL_LIB), since qcopy-acl depends on file-has-acl. +Although this suggests that QCOPY_ACL_LIB should contain +FILE_HAS_ACL_LIB, I’m not sure whether that’s the right course of +action and anyway this is good enough for coreutils. + +(cherry picked from commit 955360a66c99bdd9ac3688519a8b521b06958fd3) +--- + gnulib-tests/gnulib.mk | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gnulib-tests/gnulib.mk b/gnulib-tests/gnulib.mk +index eab1c6b..a5fd178 100644 +--- a/gnulib-tests/gnulib.mk ++++ b/gnulib-tests/gnulib.mk +@@ -99,7 +99,7 @@ TESTS += \ + TESTS_ENVIRONMENT += USE_ACL=$(USE_ACL) + check_PROGRAMS += test-set-mode-acl test-copy-acl test-sameacls + test_set_mode_acl_LDADD = $(LDADD) $(LIB_ACL) $(LIBUNISTRING) @LIBINTL@ $(MBRTOWC_LIB) $(LIBC32CONV) +-test_copy_acl_LDADD = $(LDADD) $(LIB_ACL) $(QCOPY_ACL_LIB) $(LIBUNISTRING) @LIBINTL@ $(MBRTOWC_LIB) $(LIBC32CONV) ++test_copy_acl_LDADD = $(LDADD) $(LIB_ACL) $(QCOPY_ACL_LIB) $(FILE_HAS_ACL_LIB) $(LIBUNISTRING) @LIBINTL@ $(MBRTOWC_LIB) $(LIBC32CONV) + test_sameacls_LDADD = $(LDADD) $(LIB_ACL) @LIBINTL@ $(MBRTOWC_LIB) + EXTRA_DIST += test-set-mode-acl.sh test-set-mode-acl-1.sh test-set-mode-acl-2.sh test-copy-acl.sh test-copy-acl-1.sh test-copy-acl-2.sh test-set-mode-acl.c test-copy-acl.c test-sameacls.c macros.h + +-- +2.49.0 + diff --git a/coreutils.spec b/coreutils.spec index 23eb924..b0b2230 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.6 -Release: 2%{?dist} +Release: 3%{?dist} # some used parts of gnulib are under various variants of LGPL License: GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later Url: https://www.gnu.org/software/coreutils/ @@ -40,6 +40,12 @@ Patch105: coreutils-9.6-ls-selinux-crash.patch # https://git.savannah.gnu.org/cgit/coreutils.git/patch/?id=24450e5eecf012bc1ea8cab8d677a45fa42c1778 Patch106: coreutils-9.6-who-m-systemd.patch +# cp/mv: do not fail when copying of trivial NFSv4 ACLs fails (rhbz#2363149) +# https://git.savannah.gnu.org/cgit/gnulib.git/patch?id=41e7b7e0d159d8ac0eb385964119f350ac9dfc3f +# https://git.savannah.gnu.org/cgit/gnulib.git/patch?id=8a356b77717a2e4f735ec06e326880ca1f61aadb +# https://git.savannah.gnu.org/cgit/gnulib.git/patch?id=955360a66c99bdd9ac3688519a8b521b06958fd3 +Patch107: coreutils-9.6-cp-improve-nfsv4-acl-support.patch + # (sb) lin18nux/lsb compliance - multibyte functionality patch Patch800: coreutils-i18n.patch @@ -286,6 +292,9 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Mon May 19 2025 Lukáš Zaoral - 9.6-3 +- cp/mv: do not fail when copying of trivial NFSv4 ACLs fails (rhbz#2363149) + * Tue Feb 25 2025 Lukáš Zaoral - 9.6-2 - fix 'who -m' with guessed tty names (rhbz#2343998) From 808a3165673f80423f6576b734c91ea50a8ca8c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= Date: Wed, 28 May 2025 10:19:41 +0200 Subject: [PATCH 2/4] sort: fix buffer under-read Resolves: CVE-2025-5278 Resolves: rhbz#2368767 --- coreutils-CVE-2025-5278.patch | 107 ++++++++++++++++++++++++++++++++++ coreutils-i18n.patch | 64 ++++++++++---------- coreutils.spec | 9 ++- 3 files changed, 147 insertions(+), 33 deletions(-) create mode 100644 coreutils-CVE-2025-5278.patch diff --git a/coreutils-CVE-2025-5278.patch b/coreutils-CVE-2025-5278.patch new file mode 100644 index 0000000..af81286 --- /dev/null +++ b/coreutils-CVE-2025-5278.patch @@ -0,0 +1,107 @@ +From 701a9bdbf78f869e0fb778ed5aede00e42517add Mon Sep 17 00:00:00 2001 +From: Pádraig Brady +Date: Tue, 20 May 2025 16:03:44 +0100 +Subject: [PATCH] sort: fix buffer under-read (CWE-127) + +* src/sort.c (begfield): Check pointer adjustment +to avoid Out-of-range pointer offset (CWE-823). +(limfield): Likewise. +* tests/sort/sort-field-limit.sh: Add a new test, +which triggers with ASAN or Valgrind. +* tests/local.mk: Reference the new test. +Fixes https://bugs.gnu.org/78507 + +(cherry picked from commit 8c9602e3a145e9596dc1a63c6ed67865814b6633) +--- + src/sort.c | 12 ++++++++++-- + tests/local.mk | 1 + + tests/sort/sort-field-limit.sh | 35 ++++++++++++++++++++++++++++++++++ + 3 files changed, 46 insertions(+), 2 deletions(-) + create mode 100755 tests/sort/sort-field-limit.sh + +diff --git a/src/sort.c b/src/sort.c +index b10183b..7af1a25 100644 +--- a/src/sort.c ++++ b/src/sort.c +@@ -1644,7 +1644,11 @@ begfield (struct line const *line, struct keyfield const *key) + ++ptr; + + /* Advance PTR by SCHAR (if possible), but no further than LIM. */ +- ptr = MIN (lim, ptr + schar); ++ size_t remaining_bytes = lim - ptr; ++ if (schar < remaining_bytes) ++ ptr += schar; ++ else ++ ptr = lim; + + return ptr; + } +@@ -1746,7 +1750,11 @@ limfield (struct line const *line, struct keyfield const *key) + ++ptr; + + /* Advance PTR by ECHAR (if possible), but no further than LIM. */ +- ptr = MIN (lim, ptr + echar); ++ size_t remaining_bytes = lim - ptr; ++ if (echar < remaining_bytes) ++ ptr += echar; ++ else ++ ptr = lim; + } + + return ptr; +diff --git a/tests/local.mk b/tests/local.mk +index 4da6756..642d225 100644 +--- a/tests/local.mk ++++ b/tests/local.mk +@@ -388,6 +388,7 @@ all_tests = \ + tests/sort/sort-debug-keys.sh \ + tests/sort/sort-debug-warn.sh \ + tests/sort/sort-discrim.sh \ ++ tests/sort/sort-field-limit.sh \ + tests/sort/sort-files0-from.pl \ + tests/sort/sort-float.sh \ + tests/sort/sort-h-thousands-sep.sh \ +diff --git a/tests/sort/sort-field-limit.sh b/tests/sort/sort-field-limit.sh +new file mode 100755 +index 0000000..52d8e1d +--- /dev/null ++++ b/tests/sort/sort-field-limit.sh +@@ -0,0 +1,35 @@ ++#!/bin/sh ++# From 7.2-9.7, this would trigger an out of bounds mem read ++ ++# Copyright (C) 2025 Free Software Foundation, Inc. ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 3 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src ++print_ver_ sort ++getlimits_ ++ ++# This issue triggers with valgrind or ASAN ++valgrind --error-exitcode=1 sort --version 2>/dev/null && ++ VALGRIND='valgrind --error-exitcode=1' ++ ++{ printf '%s\n' aa bb; } > in || framework_failure_ ++ ++_POSIX2_VERSION=200809 $VALGRIND sort +0.${SIZE_MAX}R in > out || fail=1 ++compare in out || fail=1 ++ ++_POSIX2_VERSION=200809 $VALGRIND sort +1 -1.${SIZE_MAX}R in > out || fail=1 ++compare in out || fail=1 ++ ++Exit $fail +-- +2.49.0 + diff --git a/coreutils-i18n.patch b/coreutils-i18n.patch index e7699c1..13e36d7 100644 --- a/coreutils-i18n.patch +++ b/coreutils-i18n.patch @@ -1,4 +1,4 @@ -From a153c65067f6c09cf2cf38dc7c149aa1521c615a Mon Sep 17 00:00:00 2001 +From 26b941130b4bba79d1b3e5cf0c352a0887c97d80 Mon Sep 17 00:00:00 2001 From: rpm-build Date: Wed, 30 Aug 2023 17:19:58 +0200 Subject: [PATCH] coreutils-i18n.patch @@ -3008,7 +3008,7 @@ index e7081a0..19e0268 100644 looking for more options and printing the next batch of files. diff --git a/src/sort.c b/src/sort.c -index 0928fd5..8c43fd4 100644 +index d059826..132f9bc 100644 --- a/src/sort.c +++ b/src/sort.c @@ -29,6 +29,14 @@ @@ -3265,7 +3265,7 @@ index 0928fd5..8c43fd4 100644 ++ptr; if (ptr < lim) ++ptr; -@@ -1650,12 +1799,71 @@ begfield (struct line const *line, struct keyfield const *key) +@@ -1654,12 +1803,71 @@ begfield (struct line const *line, struct keyfield const *key) return ptr; } @@ -3338,7 +3338,7 @@ index 0928fd5..8c43fd4 100644 { char *ptr = line->text, *lim = ptr + line->length - 1; size_t eword = key->eword, echar = key->echar; -@@ -1670,10 +1878,10 @@ limfield (struct line const *line, struct keyfield const *key) +@@ -1674,10 +1882,10 @@ limfield (struct line const *line, struct keyfield const *key) 'beginning' is the first character following the delimiting TAB. Otherwise, leave PTR pointing at the first 'blank' character after the preceding field. */ @@ -3351,7 +3351,7 @@ index 0928fd5..8c43fd4 100644 ++ptr; if (ptr < lim && (eword || echar)) ++ptr; -@@ -1719,10 +1927,10 @@ limfield (struct line const *line, struct keyfield const *key) +@@ -1723,10 +1931,10 @@ limfield (struct line const *line, struct keyfield const *key) */ /* Make LIM point to the end of (one byte past) the current field. */ @@ -3364,7 +3364,7 @@ index 0928fd5..8c43fd4 100644 if (newlim) lim = newlim; } -@@ -1753,6 +1961,130 @@ limfield (struct line const *line, struct keyfield const *key) +@@ -1761,6 +1969,130 @@ limfield (struct line const *line, struct keyfield const *key) return ptr; } @@ -3495,7 +3495,7 @@ index 0928fd5..8c43fd4 100644 /* Fill BUF reading from FP, moving buf->left bytes from the end of buf->buf to the beginning first. If EOF is reached and the file wasn't terminated by a newline, supply one. Set up BUF's line -@@ -1839,8 +2171,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *file) +@@ -1847,8 +2179,22 @@ fillbuf (struct buffer *buf, FILE *fp, char const *file) else { if (key->skipsblanks) @@ -3520,7 +3520,7 @@ index 0928fd5..8c43fd4 100644 line->keybeg = line_start; } } -@@ -1978,12 +2324,10 @@ find_unit_order (char const *number) +@@ -1986,12 +2332,10 @@ find_unit_order (char const *number) ATTRIBUTE_PURE static int @@ -3536,7 +3536,7 @@ index 0928fd5..8c43fd4 100644 int diff = find_unit_order (a) - find_unit_order (b); return (diff ? diff : strnumcmp (a, b, decimal_point, thousands_sep)); -@@ -1995,7 +2339,7 @@ human_numcompare (char const *a, char const *b) +@@ -2003,7 +2347,7 @@ human_numcompare (char const *a, char const *b) ATTRIBUTE_PURE static int @@ -3545,7 +3545,7 @@ index 0928fd5..8c43fd4 100644 { while (blanks[to_uchar (*a)]) a++; -@@ -2005,6 +2349,25 @@ numcompare (char const *a, char const *b) +@@ -2013,6 +2357,25 @@ numcompare (char const *a, char const *b) return strnumcmp (a, b, decimal_point, thousands_sep); } @@ -3571,7 +3571,7 @@ index 0928fd5..8c43fd4 100644 static int nan_compare (long double a, long double b) { -@@ -2046,7 +2409,7 @@ general_numcompare (char const *sa, char const *sb) +@@ -2054,7 +2417,7 @@ general_numcompare (char const *sa, char const *sb) Return 0 if the name in S is not recognized. */ static int @@ -3580,7 +3580,7 @@ index 0928fd5..8c43fd4 100644 { size_t lo = 0; size_t hi = MONTHS_PER_YEAR; -@@ -2385,15 +2748,14 @@ debug_key (struct line const *line, struct keyfield const *key) +@@ -2393,15 +2756,14 @@ debug_key (struct line const *line, struct keyfield const *key) char saved = *lim; *lim = '\0'; @@ -3598,7 +3598,7 @@ index 0928fd5..8c43fd4 100644 else if (key->general_numeric) ignore_value (strtold (beg, &tighter_lim)); else if (key->numeric || key->human_numeric) -@@ -2539,7 +2901,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) +@@ -2547,7 +2909,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) /* Warn about significant leading blanks. */ bool implicit_skip = key_numeric (key) || key->month; bool line_offset = key->eword == 0 && key->echar != 0; /* -k1.x,1.y */ @@ -3607,7 +3607,7 @@ index 0928fd5..8c43fd4 100644 && ((!key->skipsblanks && !implicit_skip) || (!key->skipsblanks && key->schar) || (!key->skipeblanks && key->echar))) -@@ -2587,9 +2949,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) +@@ -2595,9 +2957,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) bool number_locale_warned = false; if (basic_numeric_field_span) { @@ -3620,7 +3620,7 @@ index 0928fd5..8c43fd4 100644 { error (0, 0, _("field separator %s is treated as a " -@@ -2600,9 +2962,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) +@@ -2608,9 +2970,9 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) } if (basic_numeric_field_span || general_numeric_field_span) { @@ -3633,7 +3633,7 @@ index 0928fd5..8c43fd4 100644 { error (0, 0, _("field separator %s is treated as a " -@@ -2610,19 +2972,19 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) +@@ -2618,19 +2980,19 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) quote (((char []) {decimal_point, 0}))); number_locale_warned = true; } @@ -3657,7 +3657,7 @@ index 0928fd5..8c43fd4 100644 } } -@@ -2633,7 +2995,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) +@@ -2641,7 +3003,7 @@ key_warnings (struct keyfield const *gkey, bool gkey_only) { error (0, 0, _("%snumbers use %s as a decimal point in this locale"), @@ -3666,7 +3666,7 @@ index 0928fd5..8c43fd4 100644 quote (((char []) {decimal_point, 0}))); } -@@ -2675,11 +3037,87 @@ diff_reversed (int diff, bool reversed) +@@ -2683,11 +3045,87 @@ diff_reversed (int diff, bool reversed) return reversed ? (diff < 0) - (diff > 0) : diff; } @@ -3755,7 +3755,7 @@ index 0928fd5..8c43fd4 100644 { struct keyfield *key = keylist; -@@ -2760,7 +3198,7 @@ keycompare (struct line const *a, struct line const *b) +@@ -2768,7 +3206,7 @@ keycompare (struct line const *a, struct line const *b) else if (key->human_numeric) diff = human_numcompare (ta, tb); else if (key->month) @@ -3764,7 +3764,7 @@ index 0928fd5..8c43fd4 100644 else if (key->random) diff = compare_random (ta, tlena, tb, tlenb); else if (key->version) -@@ -2870,6 +3308,211 @@ keycompare (struct line const *a, struct line const *b) +@@ -2878,6 +3316,211 @@ keycompare (struct line const *a, struct line const *b) return diff_reversed (diff, key->reverse); } @@ -3976,7 +3976,7 @@ index 0928fd5..8c43fd4 100644 /* Compare two lines A and B, returning negative, zero, or positive depending on whether A compares less than, equal to, or greater than B. */ -@@ -2897,7 +3540,7 @@ compare (struct line const *a, struct line const *b) +@@ -2905,7 +3548,7 @@ compare (struct line const *a, struct line const *b) diff = - NONZERO (blen); else if (blen == 0) diff = 1; @@ -3985,7 +3985,7 @@ index 0928fd5..8c43fd4 100644 { /* xmemcoll0 is a performance enhancement as it will not unconditionally write '\0' after the -@@ -4285,6 +4928,7 @@ set_ordering (char const *s, struct keyfield *key, enum blanktype blanktype) +@@ -4293,6 +4936,7 @@ set_ordering (char const *s, struct keyfield *key, enum blanktype blanktype) break; case 'f': key->translate = fold_toupper; @@ -3993,7 +3993,7 @@ index 0928fd5..8c43fd4 100644 break; case 'g': key->general_numeric = true; -@@ -4364,7 +5008,7 @@ main (int argc, char **argv) +@@ -4372,7 +5016,7 @@ main (int argc, char **argv) initialize_exit_failure (SORT_FAILURE); hard_LC_COLLATE = hard_locale (LC_COLLATE); @@ -4002,7 +4002,7 @@ index 0928fd5..8c43fd4 100644 hard_LC_TIME = hard_locale (LC_TIME); #endif -@@ -4387,6 +5031,29 @@ main (int argc, char **argv) +@@ -4395,6 +5039,29 @@ main (int argc, char **argv) thousands_sep = NON_CHAR; } @@ -4032,7 +4032,7 @@ index 0928fd5..8c43fd4 100644 have_read_stdin = false; inittables (); -@@ -4657,13 +5324,34 @@ main (int argc, char **argv) +@@ -4665,13 +5332,34 @@ main (int argc, char **argv) case 't': { @@ -4071,7 +4071,7 @@ index 0928fd5..8c43fd4 100644 else { /* Provoke with 'sort -txx'. Complain about -@@ -4674,9 +5362,11 @@ main (int argc, char **argv) +@@ -4682,9 +5370,11 @@ main (int argc, char **argv) quote (optarg)); } } @@ -4528,11 +4528,11 @@ index 0000000..26c95de + +Exit $fail diff --git a/tests/local.mk b/tests/local.mk -index 12e30b4..1529db6 100644 +index 864cd16..eb898ab 100644 --- a/tests/local.mk +++ b/tests/local.mk -@@ -390,6 +390,8 @@ all_tests = \ - tests/sort/sort-discrim.sh \ +@@ -391,6 +391,8 @@ all_tests = \ + tests/sort/sort-field-limit.sh \ tests/sort/sort-files0-from.pl \ tests/sort/sort-float.sh \ + tests/misc/sort-mb-tests.sh \ @@ -4540,7 +4540,7 @@ index 12e30b4..1529db6 100644 tests/sort/sort-h-thousands-sep.sh \ tests/sort/sort-merge.pl \ tests/sort/sort-merge-fdlimit.sh \ -@@ -593,6 +595,7 @@ all_tests = \ +@@ -594,6 +596,7 @@ all_tests = \ tests/du/threshold.sh \ tests/du/trailing-slash.sh \ tests/du/two-args.sh \ @@ -4548,7 +4548,7 @@ index 12e30b4..1529db6 100644 tests/id/gnu-zero-uids.sh \ tests/id/no-context.sh \ tests/id/context.sh \ -@@ -749,6 +752,7 @@ all_tests = \ +@@ -750,6 +753,7 @@ all_tests = \ tests/touch/read-only.sh \ tests/touch/relative.sh \ tests/touch/trailing-slash.sh \ @@ -5180,5 +5180,5 @@ index 0000000..8a82d74 +LC_ALL=C unexpand in in > out || fail=1 +compare exp out > /dev/null 2>&1 || fail=1 -- -2.48.1 +2.49.0 diff --git a/coreutils.spec b/coreutils.spec index b0b2230..2340126 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.6 -Release: 3%{?dist} +Release: 4%{?dist} # some used parts of gnulib are under various variants of LGPL License: GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later Url: https://www.gnu.org/software/coreutils/ @@ -46,6 +46,10 @@ Patch106: coreutils-9.6-who-m-systemd.patch # https://git.savannah.gnu.org/cgit/gnulib.git/patch?id=955360a66c99bdd9ac3688519a8b521b06958fd3 Patch107: coreutils-9.6-cp-improve-nfsv4-acl-support.patch +# sort: fix buffer under-read (CVE-2025-5278) +# https://cgit.git.savannah.gnu.org/cgit/coreutils.git/patch/?id=8c9602e3a145e9596dc1a63c6ed67865814b6633 +Patch108: coreutils-CVE-2025-5278.patch + # (sb) lin18nux/lsb compliance - multibyte functionality patch Patch800: coreutils-i18n.patch @@ -292,6 +296,9 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Wed May 28 2025 Lukáš Zaoral - 9.6-4 +- sort: fix buffer under-read (CVE-2025-5278) + * Mon May 19 2025 Lukáš Zaoral - 9.6-3 - cp/mv: do not fail when copying of trivial NFSv4 ACLs fails (rhbz#2363149) From dfeff61db9c78840ec66990989c5f8ab5f5f012f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= Date: Tue, 8 Jul 2025 13:14:50 +0200 Subject: [PATCH 3/4] ls: fix crash on systems with SELinux but without xattr support Resolves: rhbz#2376721 --- coreutils-9.6-ls-selinux-crash-2.patch | 37 ++++++++++++++++++++++++++ coreutils.spec | 9 ++++++- 2 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 coreutils-9.6-ls-selinux-crash-2.patch diff --git a/coreutils-9.6-ls-selinux-crash-2.patch b/coreutils-9.6-ls-selinux-crash-2.patch new file mode 100644 index 0000000..8c6de3c --- /dev/null +++ b/coreutils-9.6-ls-selinux-crash-2.patch @@ -0,0 +1,37 @@ +From b54c3d30b0447b69d9bb405d2adb830ae1172dce Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?P=C3=A1draig=20Brady?= +Date: Thu, 20 Mar 2025 18:40:01 +0000 +Subject: [PATCH] ls: fix crash on systems with SELinux but without xattr + support + +This was seen on termux on Android with ./configure --disable-xattr +where listxattr() and getxattr() returned ENOTSUP. +Then the valid security context obtained by file_has_aclinfo() +was discounted, and problematically then freed multiple times. +Reported at https://github.com/termux/termux-packages/issues/23752 + +* src/ls.c (file_has_aclinfo_cache): Only discount the returned +acl info when all components are defaulted due to being unsupported. + +(cherry picked from commit cb2abbac7f9e40e0f0d6183bf9b11e80b0cad8ef) +--- + src/ls.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/ls.c b/src/ls.c +index f67167f..97cf46a 100644 +--- a/src/ls.c ++++ b/src/ls.c +@@ -3322,7 +3322,8 @@ file_has_aclinfo_cache (char const *file, struct fileinfo *f, + errno = 0; + int n = file_has_aclinfo (file, ai, flags); + int err = errno; +- if (f->stat_ok && n <= 0 && !acl_errno_valid (err)) ++ if (f->stat_ok && n <= 0 && !acl_errno_valid (err) ++ && (!(flags & ACL_GET_SCONTEXT) || !acl_errno_valid (ai->scontext_err))) + { + unsupported_return = n; + unsupported_scontext = ai->scontext; +-- +2.50.0 + diff --git a/coreutils.spec b/coreutils.spec index 2340126..47c546e 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.6 -Release: 4%{?dist} +Release: 5%{?dist} # some used parts of gnulib are under various variants of LGPL License: GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later Url: https://www.gnu.org/software/coreutils/ @@ -50,6 +50,10 @@ Patch107: coreutils-9.6-cp-improve-nfsv4-acl-support.patch # https://cgit.git.savannah.gnu.org/cgit/coreutils.git/patch/?id=8c9602e3a145e9596dc1a63c6ed67865814b6633 Patch108: coreutils-CVE-2025-5278.patch +# ls: fix crash on systems with SELinux but without xattr support (rhbz#2376721) +# https://cgit.git.savannah.gnu.org/cgit/coreutils.git/patch/?id=cb2abbac7f9e40e0f0d6183bf9b11e80b0cad8ef +Patch109: coreutils-9.6-ls-selinux-crash-2.patch + # (sb) lin18nux/lsb compliance - multibyte functionality patch Patch800: coreutils-i18n.patch @@ -296,6 +300,9 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Tue Jul 08 2025 Lukáš Zaoral - 9.6-5 +- ls: fix crash on systems with SELinux but without xattr support (rhbz#2376721) + * Wed May 28 2025 Lukáš Zaoral - 9.6-4 - sort: fix buffer under-read (CVE-2025-5278) From 370c5aa4ee4bfa13f60db48576a674b84261a2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Zaoral?= Date: Mon, 29 Sep 2025 13:44:38 +0200 Subject: [PATCH 4/4] require gnulib-l10n for translations of gnulib messages Resolves: rhbz#2393892 --- coreutils.spec | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/coreutils.spec b/coreutils.spec index 47c546e..9d0aec8 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.6 -Release: 5%{?dist} +Release: 6%{?dist} # some used parts of gnulib are under various variants of LGPL License: GPL-3.0-or-later AND GFDL-1.3-no-invariants-or-later AND LGPL-2.1-or-later AND LGPL-3.0-or-later Url: https://www.gnu.org/software/coreutils/ @@ -142,6 +142,9 @@ packaged as a single multicall binary. # https://bugzilla.redhat.com/show_bug.cgi?id=1107973#c7 Obsoletes: %{name} < 8.24-100 +# Gnulib translations are maintained seprately since coreutils 9.6 (#2393892) +Requires: gnulib-l10n + # info doc refers to "Specifying the Time Zone" from glibc-doc (#959597) Suggests: glibc-doc @@ -300,6 +303,9 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Mon Sep 29 2025 Lukáš Zaoral - 9.6-6 +- require gnulib-l10n for translations of gnulib messages (rhbz#2393892) + * Tue Jul 08 2025 Lukáš Zaoral - 9.6-5 - ls: fix crash on systems with SELinux but without xattr support (rhbz#2376721)