Be able to get the security context even if configured with --disable-acl, as security contexts are not ACLs, and the main reason for --disable-acl was for efficiency with GNU ls -l, a concern that does not apply to security contexts (which are needed only with ls -Z). Problem reported by Pádraig Brady <https://bugs.gnu.org/73418#52>. * lib/acl.h (ACL_GET_SCONTEXT): New constant. (aclinfo_free, aclinfo_scontext_free): Declare even if !USE_ACL. * lib/file-has-acl.c (USE_LINUX_XATTR): No longer false merely because !USE_ACL, because we need xattr to get scontext. (get_aclinfo): Support new ACL_GET_SCONTEXT flag. --- ChangeLog | 15 ++++++++ lib/acl.h | 17 ++++++--- lib/file-has-acl.c | 93 +++++++++++++++++++++++++--------------------- 3 files changed, 77 insertions(+), 48 deletions(-)
diff --git a/ChangeLog b/ChangeLog index afce32cf8b..3ae5107c7a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2024-11-11 Paul Eggert <egg...@cs.ucla.edu> + + file-has-acl: scontext even if --disable-acl + Be able to get the security context even if configured with + --disable-acl, as security contexts are not ACLs, and the + main reason for --disable-acl was for efficiency with GNU ls -l, + a concern that does not apply to security contexts (which are + needed only with ls -Z). Problem reported by Pádraig Brady + <https://bugs.gnu.org/73418#52>. + * lib/acl.h (ACL_GET_SCONTEXT): New constant. + (aclinfo_free, aclinfo_scontext_free): Declare even if !USE_ACL. + * lib/file-has-acl.c (USE_LINUX_XATTR): No longer false merely + because !USE_ACL, because we need xattr to get scontext. + (get_aclinfo): Support new ACL_GET_SCONTEXT flag. + 2024-11-11 Bruno Haible <br...@clisp.org> nproc: Use affinity mask even in out-of-memory situations. diff --git a/lib/acl.h b/lib/acl.h index ca74fe6de8..1d52345c66 100644 --- a/lib/acl.h +++ b/lib/acl.h @@ -32,9 +32,16 @@ extern "C" { #endif -/* Follow symlinks when getting an ACL. This is a bitmask that is guaranteed - not to collide with any <dirent.h> DT_* or _GL_DT_* value. */ -enum { ACL_SYMLINK_FOLLOW = 0x10000 }; +/* file_has_acl flags guaranteed to not collide with any <dirent.h> + DT_* or _GL_DT_* value. */ +enum + { + /* Get scontext information as well. */ + ACL_GET_SCONTEXT = 0x10000, + + /* Follow symlinks. */ + ACL_SYMLINK_FOLLOW = 0x20000, + }; /* Information about an ACL. */ struct aclinfo @@ -73,7 +80,7 @@ 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); -#if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR +#if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR bool aclinfo_has_xattr (struct aclinfo const *, char const *) _GL_ATTRIBUTE_PURE; void aclinfo_free (struct aclinfo *); @@ -81,7 +88,7 @@ void aclinfo_free (struct aclinfo *); # define aclinfo_has_xattr(ai, xattr) false # define aclinfo_free(ai) ((void) 0) #endif -#if (USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR \ +#if (HAVE_LINUX_XATTR_H && HAVE_LISTXATTR \ && (HAVE_SMACK || USE_SELINUX_SELINUX_H)) void aclinfo_scontext_free (char *); #else diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c index 7e05d39131..2cbc20b38d 100644 --- a/lib/file-has-acl.c +++ b/lib/file-has-acl.c @@ -39,7 +39,7 @@ static_assert (ACL_SYMLINK_FOLLOW & ~ (unsigned char) -1); static char const UNKNOWN_SECURITY_CONTEXT[] = "?"; -#if USE_ACL && HAVE_LINUX_XATTR_H && HAVE_LISTXATTR +#if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR # define USE_LINUX_XATTR true #else # define USE_LINUX_XATTR false @@ -109,7 +109,8 @@ aclinfo_has_xattr (struct aclinfo const *ai, char const *xattr) return false; } -/* Get attributes of the file NAME into AI. +/* Get attributes of the file NAME into AI, if USE_ACL. + 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) @@ -118,53 +119,58 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags) ai->buf = ai->u.__gl_acl_ch; ssize_t acl_alloc = sizeof ai->u.__gl_acl_ch; - ssize_t (*lsxattr) (char const *, char *, size_t) - = (flags & ACL_SYMLINK_FOLLOW ? listxattr : llistxattr); - while (true) + if (! (USE_ACL || flags & ACL_GET_SCONTEXT)) + ai->size = 0; + else { - ai->size = lsxattr (name, ai->buf, acl_alloc); - if (0 < ai->size) - break; - ai->u.err = ai->size < 0 ? errno : 0; - if (! (ai->size < 0 && ai->u.err == ERANGE && acl_alloc < SSIZE_MAX)) - break; - - /* The buffer was too small. Find how large it should have been. */ - ssize_t size = lsxattr (name, NULL, 0); - if (size <= 0) + ssize_t (*lsxattr) (char const *, char *, size_t) + = (flags & ACL_SYMLINK_FOLLOW ? listxattr : llistxattr); + while (true) { - ai->size = size; - ai->u.err = size < 0 ? errno : 0; - break; - } + ai->size = lsxattr (name, ai->buf, acl_alloc); + if (0 < ai->size) + break; + ai->u.err = ai->size < 0 ? errno : 0; + if (! (ai->size < 0 && ai->u.err == ERANGE && acl_alloc < SSIZE_MAX)) + break; - /* Grow allocation to at least 'size'. Grow it by a nontrivial - amount, to defend against denial of service by an adversary - that fiddles with ACLs. */ - if (ai->buf != ai->u.__gl_acl_ch) - { - free (ai->buf); - ai->buf = ai->u.__gl_acl_ch; - } - if (ckd_add (&acl_alloc, acl_alloc, acl_alloc >> 1)) - acl_alloc = SSIZE_MAX; - if (acl_alloc < size) - acl_alloc = size; - if (SIZE_MAX < acl_alloc) - { - ai->u.err = ENOMEM; - break; - } - char *newbuf = malloc (acl_alloc); - if (!newbuf) - { - ai->u.err = errno; - break; + /* The buffer was too small. Find how large it should have been. */ + ssize_t size = lsxattr (name, NULL, 0); + if (size <= 0) + { + ai->size = size; + ai->u.err = size < 0 ? errno : 0; + break; + } + + /* Grow allocation to at least 'size'. Grow it by a nontrivial + amount, to defend against denial of service by an adversary + that fiddles with ACLs. */ + if (ai->buf != ai->u.__gl_acl_ch) + { + free (ai->buf); + ai->buf = ai->u.__gl_acl_ch; + } + if (ckd_add (&acl_alloc, acl_alloc, acl_alloc >> 1)) + acl_alloc = SSIZE_MAX; + if (acl_alloc < size) + acl_alloc = size; + if (SIZE_MAX < acl_alloc) + { + ai->u.err = ENOMEM; + break; + } + char *newbuf = malloc (acl_alloc); + if (!newbuf) + { + ai->u.err = errno; + break; + } + ai->buf = newbuf; } - ai->buf = newbuf; } - if (0 < ai->size) + if (0 < ai->size && flags & ACL_GET_SCONTEXT) { if (is_smack_enabled ()) { @@ -325,6 +331,7 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes) Set *AI to ACL info regardless of return value. FLAGS should be a <dirent.h> d_type value, optionally ORed with - _GL_DT_NOTDIR if it is known that NAME is not a directory, + - ACL_GET_SCONTEXT to retrieve extended attributes, - ACL_SYMLINK_FOLLOW to follow the link if NAME is a symbolic link. If the d_type value is not known, use DT_UNKNOWN though this may be less efficient. -- 2.47.0