On 08/01/2025 19:41, Paul Eggert wrote:
On 2025-01-08 06:24, Pádraig Brady wrote:
The EACCES is returned from both llistxattr and listxattr.
Is flistxattr the same?
You need read permission to get xattrs on local or nfs.
Isn't it more complicated than that, for local file systems? Here's what
I observe on Fedora 41 with a local ext4 file system. Sometimes I need
read permission, sometimes I don't. (Is any of this stuff documented?)
$ touch ghijkl
$ setfattr -n user.foo -v bar ghijkl
$ chmod 0 ghijkl
$ strace -o tr ls -l ghijkl
----------. 1 eggert eggert 0 Jan 8 11:27 ghijkl
$ grep xattr tr
llistxattr("ghijkl", "security.selinux\0user.foo\0", 152) = 26
lgetxattr("ghijkl", "security.selinux",
"unconfined_u:object_r:user_home_"..., 255) = 37
$ strace -o tr2 getfattr -n security.selinux ghijkl
# file: ghijkl
security.selinux="unconfined_u:object_r:user_home_t:s0"
$ grep xattr tr2
getxattr("ghijkl", "security.selinux", NULL, 0) = 37
getxattr("ghijkl", "security.selinux",
"unconfined_u:object_r:user_home_"..., 256) = 37
Indeed the GET permissions are more nuanced,
and seem to vary based on the namespace.
`getfattr` seems to infer the namespace to use automatically,
whereas the `attr` tool I was using requires more manual specifications:
~$ chmod 0 nfs/file
~$ strace -e trace=/.*xattr.* attr -g security.selinux nfs/file
lgetxattr("nfs/file", "user.security.selinux", 0x55ecedbfd430, 65536) = -1
EACCES (Permission denied)
~$ strace -e trace=/.*xattr.* getfattr -n security.selinux nfs/file
getxattr("nfs/file", "security.selinux", NULL, 0) = 37
getxattr("nfs/file", "security.selinux", "unconfined_u:object_r:user_home_"...,
256) = 37
~$ strace -e trace=/.*xattr.* attr -S -g selinux nfs/file
lgetxattr("nfs/file", "security.selinux",
"unconfined_u:object_r:user_home_"..., 65536) = 37
I.E. locally at least the user permissions are applied for GET only for the
"user." namespace.
So this looks like an inconsistency in nfs,
but also a common scenario I expect.
Yes, unfortunately.
So I would think we should ignore the EACCES from listxattr()
For ls at least, any real permission issues would be diagnosed with
stat() etc.
Ignoring EACCES doesn't sound right. This situation differs from the
other ones noted in lib/acl-errno-valid.c. In those situations, a file
system or kernel issues a weird errno value when ACLs aren't supported,
and so it's appropriate to treat those errno values as if they were ENOTSUP.
Here, if I understand things correctly, the file system supports ACLs
but it doesn't want to give you the information. That's something I'd
want to know about if I am the 'ls' user.
How about something like the attached patch instead? It's incomplete
(needs doc) and untested but I hope it gives you the basic idea, which
is to put '?' in the ACL column when you lack permissions to find out
whether ACLs are present.
Yes that does sound better than ignoring that info.
We would still output '?' whereas coreutils < 9.3 did not,
but that would be much less intrusive and contained to the files in question.
So ls now does:
$ src/ls -l /mnt/nfs
----------? 1 padraig padraig 0 Jan 8 20:42 file
The attached does that and adds docs.
Marking this as done.
cheers,
Pádraig
From 97aa65af528362107633ebbc3b27da952e026774 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Wed, 8 Jan 2025 21:46:05 +0000
Subject: [PATCH] ls: suppress "Permission Denied" errors on NFS
NFS (on Linux 6.12 at least) was seen to return EACCES
from listxattr() for files without read access.
We started using listxattr() in coreutils 9.4.
* src/ls.c (gobble_file): Map EACCES from file_has_aclinfo()
to '?', rather than displaying the error.
* doc/coreutils.texi (ls invocation): Document the '?' flag.
* NEWS: Mention the bug fix.
Addresses https://bugs.gnu.org/74692
---
NEWS | 6 ++++++
doc/coreutils.texi | 4 ++++
src/ls.c | 13 +++++++++++--
3 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index 31093fb4f..793745de6 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,12 @@ GNU coreutils NEWS -*- outline -*-
first and last characters, and single quotes in the string.
[bug introduced in coreutils-8.26]
+ ls -l will now mark files with a '?' character after the mode bits
+ if it is unable to read alternate access method details, which may
+ happen on NFS with files without read permission.
+ Previously ls would have output "Permission denied" errors.
+ [bug introduced in coreutils-9.4]
+
mv works again with macFUSE file systems. Previously it would
have exited with a "Function not implemented" error.
[bug introduced in coreutils-8.28]
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 585760741..ec58f6cf2 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -8084,6 +8084,10 @@ with a security context, but no other alternate access method.
A file with any other combination of alternate access methods
is marked with a @samp{+} character.
+@command{ls} uses a @samp{?} character to indicate it is unable to determine
+whether alternate access methods apply to the file, which may happen for
+example with some NFS setups with files without read permission.
+
@item -n
@itemx --numeric-uid-gid
@opindex -n
diff --git a/src/ls.c b/src/ls.c
index 0cdaacb93..5588c6746 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -199,6 +199,7 @@ static char const d_type_filetype[UCHAR_MAX + 1] =
enum acl_type
{
ACL_T_NONE,
+ ACL_T_UNKNOWN,
ACL_T_LSM_CONTEXT_ONLY,
ACL_T_YES
};
@@ -3518,14 +3519,20 @@ gobble_file (char const *name, enum filetype type, ino_t inode,
int n = file_has_aclinfo_cache (full_name, f, &ai, aclinfo_flags);
bool have_acl = 0 < n;
bool have_scontext = !ai.scontext_err;
+
+ /* Let the user know via '?' if errno is EACCES, which can
+ happen with Linux kernel 6.12 on an NFS file system.
+ That's better than a longwinded diagnostic. */
+ bool cannot_access_acl = n < 0 && errno == EACCES;
+
f->acl_type = (!have_scontext && !have_acl
- ? ACL_T_NONE
+ ? (cannot_access_acl ? ACL_T_UNKNOWN : ACL_T_NONE)
: (have_scontext && !have_acl
? ACL_T_LSM_CONTEXT_ONLY
: ACL_T_YES));
any_has_acl |= f->acl_type != ACL_T_NONE;
- if (format == long_format && n < 0)
+ if (format == long_format && n < 0 && !cannot_access_acl)
error (0, ai.u.err, "%s", quotef (full_name));
else
{
@@ -4302,6 +4309,8 @@ print_long_format (const struct fileinfo *f)
modebuf[10] = '.';
else if (f->acl_type == ACL_T_YES)
modebuf[10] = '+';
+ else if (f->acl_type == ACL_T_UNKNOWN)
+ modebuf[10] = '?';
switch (time_type)
{
--
2.47.1