[PATCH 15/15] smb: client: support trusted EAs on POSIX mounts
Ze Tan <[email protected]> Fri, 24 Jul 2026 18:40:09 +0800
| Newsgroups | org.kernel.vger.linux-cifs |
|---|---|
| Message-ID | <492de6f2817478ffee14dadea67822060b6f15c9.1784888897.git.tanze@kylinos.cn> |
Register the trusted xattr handler and add trusted.* to the native prefix table. The handler sends native trusted names only on negotiated SMB3 POSIX mounts; non-POSIX user.trusted.* EAs retain their existing user namespace mapping. Hide native trusted names from listxattr callers without CAP_SYS_ADMIN. Reject the XFS trusted.SGI_ACL_* names before matching the trusted prefix. Run the following as root on a POSIX mount to check that a write clears security.capability without removing trusted.name: $ CIFS_MNT=/path/to/cifs-mount $ file="$CIFS_MNT/trusted-preserve" $ touch "$file" $ setfattr -n trusted.name -v value "$file" $ printf 'data\n' >> "$file" Signed-off-by: Ze Tan <[email protected]> --- fs/smb/client/cifsfs.h | 1 + fs/smb/client/smb2ops.c | 3 +++ fs/smb/client/xattr.c | 51 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 4ab1a203be3e..1c04dc07a2ff 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -136,6 +136,7 @@ int cifs_symlink(struct mnt_idmap *idmap, struct inode *inode, enum cifs_ea_name_type { CIFS_EA_USER, CIFS_EA_NATIVE, + CIFS_EA_HIDDEN, }; enum cifs_ea_name_type diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index fd778d903e93..f38230e4c31d 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1103,6 +1103,8 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size, name_type = cifs_ea_name_type(name, name_len, posix_extensions); + if (name_type == CIFS_EA_HIDDEN) + goto next; if (name_type == CIFS_EA_NATIVE) user_name_len = name_len + 1; else @@ -1130,6 +1132,7 @@ move_smb2_ea_to_cifs(char *dst, size_t dst_size, } } +next: if (!src->next_entry_offset) break; diff --git a/fs/smb/client/xattr.c b/fs/smb/client/xattr.c index 59f6655a1b34..4b6736a6b375 100644 --- a/fs/smb/client/xattr.c +++ b/fs/smb/client/xattr.c @@ -7,6 +7,7 @@ */ #include <linux/fs.h> +#include <linux/capability.h> #include <linux/posix_acl_xattr.h> #include <linux/slab.h> #include <linux/xattr.h> @@ -36,7 +37,7 @@ #define SMB3_XATTR_CIFS_NTSD_FULL "system.smb3_ntsd_full" /* owner/DACL/SACL */ #define SMB3_XATTR_ATTRIB "smb3.dosattrib" /* full name: user.smb3.dosattrib */ #define SMB3_XATTR_CREATETIME "smb3.creationtime" /* user.smb3.creationtime */ -enum { XATTR_USER, XATTR_SECURITY, +enum { XATTR_USER, XATTR_TRUSTED, XATTR_SECURITY, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT, XATTR_CIFS_NTSD_SACL, XATTR_CIFS_NTSD_OWNER, XATTR_CIFS_NTSD, XATTR_CIFS_NTSD_FULL }; @@ -46,6 +47,15 @@ static const char * const cifs_native_xattr_names[] = { XATTR_SECURITY_PREFIX "xfstests", }; +static const char * const cifs_native_xattr_prefixes[] = { + XATTR_TRUSTED_PREFIX, +}; + +static const char * const cifs_unsupported_xattr_names[] = { + XATTR_TRUSTED_PREFIX "SGI_ACL_FILE", + XATTR_TRUSTED_PREFIX "SGI_ACL_DEFAULT", +}; + enum cifs_ea_name_type cifs_ea_name_type(const char *name, size_t name_len, bool posix_extensions) { @@ -54,6 +64,14 @@ cifs_ea_name_type(const char *name, size_t name_len, bool posix_extensions) if (!posix_extensions) return CIFS_EA_USER; + for (i = 0; i < ARRAY_SIZE(cifs_unsupported_xattr_names); i++) { + size_t xattr_len = strlen(cifs_unsupported_xattr_names[i]); + + if (name_len == xattr_len && + !memcmp(name, cifs_unsupported_xattr_names[i], name_len)) + return CIFS_EA_HIDDEN; + } + for (i = 0; i < ARRAY_SIZE(cifs_native_xattr_names); i++) { size_t xattr_len = strlen(cifs_native_xattr_names[i]); @@ -62,6 +80,15 @@ cifs_ea_name_type(const char *name, size_t name_len, bool posix_extensions) return CIFS_EA_NATIVE; } + for (i = 0; i < ARRAY_SIZE(cifs_native_xattr_prefixes); i++) { + size_t prefix_len = strlen(cifs_native_xattr_prefixes[i]); + + if (name_len > prefix_len && + !memcmp(name, cifs_native_xattr_prefixes[i], prefix_len)) + return capable(CAP_SYS_ADMIN) ? CIFS_EA_NATIVE : + CIFS_EA_HIDDEN; + } + return CIFS_EA_USER; } @@ -76,6 +103,10 @@ static int cifs_build_ea_name(int xattr_flag, const char *name, char *ea_name, prefix = XATTR_SECURITY_PREFIX; prefix_len = XATTR_SECURITY_PREFIX_LEN; break; + case XATTR_TRUSTED: + prefix = XATTR_TRUSTED_PREFIX; + prefix_len = XATTR_TRUSTED_PREFIX_LEN; + break; default: return -EOPNOTSUPP; } @@ -186,6 +217,7 @@ static int cifs_xattr_set(const struct xattr_handler *handler, } switch (handler->flags) { + case XATTR_TRUSTED: case XATTR_SECURITY: if (!pTcon->posix_extensions) goto out; @@ -195,8 +227,8 @@ static int cifs_xattr_set(const struct xattr_handler *handler, goto out; server_ea_name = ea_name; lease_inode = inode; - cifs_dbg(FYI, "%s: setting security xattr %s\n", - __func__, name); + cifs_dbg(FYI, "%s: setting native xattr %s\n", + __func__, server_ea_name); goto set_ea; case XATTR_USER: @@ -372,6 +404,7 @@ static int cifs_xattr_get(const struct xattr_handler *handler, /* return alt name if available as pseudo attr */ switch (handler->flags) { + case XATTR_TRUSTED: case XATTR_SECURITY: if (!pTcon->posix_extensions) goto out; @@ -381,8 +414,8 @@ static int cifs_xattr_get(const struct xattr_handler *handler, goto out; server_ea_name = ea_name; lease_inode = inode; - cifs_dbg(FYI, "%s: querying security xattr %s\n", - __func__, name); + cifs_dbg(FYI, "%s: querying native xattr %s\n", + __func__, server_ea_name); goto query_ea; case XATTR_USER: @@ -531,6 +564,13 @@ static const struct xattr_handler cifs_user_xattr_handler = { .set = cifs_xattr_set, }; +static const struct xattr_handler cifs_trusted_xattr_handler = { + .prefix = XATTR_TRUSTED_PREFIX, + .flags = XATTR_TRUSTED, + .get = cifs_xattr_get, + .set = cifs_xattr_set, +}; + static const struct xattr_handler cifs_security_xattr_handler = { .prefix = XATTR_SECURITY_PREFIX, .flags = XATTR_SECURITY, @@ -622,6 +662,7 @@ static const struct xattr_handler smb3_ntsd_full_xattr_handler = { const struct xattr_handler * const cifs_xattr_handlers[] = { &cifs_user_xattr_handler, + &cifs_trusted_xattr_handler, &cifs_security_xattr_handler, &cifs_os2_xattr_handler, &cifs_cifs_acl_xattr_handler, -- 2.43.0