[PATCH 08/15] ksmbd: set security.capability on POSIX EA handles

Ze Tan <[email protected]> Fri, 24 Jul 2026 18:40:02 +0800
Newsgroups org.kernel.vger.linux-cifs
Message-ID <47538d9ace8608e24cae15c2ad7c20cf3ec7df8b.1784888897.git.tanze@kylinos.cn>
Map security.capability directly to its native backing xattr when the
file handle was opened with an SMB3 POSIX create context. Ordinary EAs
and non-POSIX handles retain the existing user namespace mapping.

Pass the ksmbd_work and per-open POSIX state through smb2_set_ea() from
both the CREATE and SET_INFO paths. This lets
ksmbd_map_ea_name_to_xattr() apply the same root or admin authorization
used by native queries.

Return native mapping errors to the caller instead of replacing them
with -EINVAL.

Signed-off-by: Ze Tan <[email protected]>
---
 fs/smb/server/smb2pdu.c | 43 +++++++++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 10 deletions(-)

diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 7fdc6df6310a..6baeac99b12f 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2680,9 +2680,27 @@ static int ksmbd_check_native_xattr(struct ksmbd_work *work,
 	return 1;
 }
 
-static int ksmbd_map_ea_name_to_xattr(const char *ea_name,
-				      size_t ea_name_len, char *attr_name)
+static int ksmbd_map_ea_name_to_xattr(struct ksmbd_work *work,
+				      bool native_xattrs,
+				      const char *ea_name, size_t ea_name_len,
+				      char *attr_name)
 {
+	int rc;
+
+	if (native_xattrs) {
+		rc = ksmbd_check_native_xattr(work, ea_name, ea_name_len);
+		if (rc < 0)
+			return rc;
+		if (rc) {
+			if (ea_name_len > XATTR_NAME_MAX)
+				return -EINVAL;
+
+			memcpy(attr_name, ea_name, ea_name_len);
+			attr_name[ea_name_len] = '\0';
+			return ea_name_len;
+		}
+	}
+
 	if (ea_name_len > XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)
 		return -EINVAL;
 
@@ -2728,15 +2746,18 @@ static bool ksmbd_is_visible_ea_name(struct ksmbd_work *work,
 /**
  * smb2_set_ea() - handler for setting extended attributes using set
  *		info command
+ * @work:	smb work containing session and tree information
  * @eabuf:	set info command buffer
  * @buf_len:	set info command buffer length
  * @path:	dentry path for get ea
  * @get_write:	get write access to a mount
+ * @native_xattrs:	the open included an SMB3 POSIX create context
  *
  * Return:	0 on success, otherwise error
  */
-static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
-		       const struct path *path, bool get_write)
+static int smb2_set_ea(struct ksmbd_work *work, struct smb2_ea_info *eabuf,
+		       unsigned int buf_len, const struct path *path,
+		       bool get_write, bool native_xattrs)
 {
 	struct mnt_idmap *idmap = mnt_idmap(path->mnt);
 	char *attr_name = NULL, *value;
@@ -2762,11 +2783,12 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
 			    le16_to_cpu(eabuf->EaValueLength),
 			    le32_to_cpu(eabuf->NextEntryOffset));
 
-		attr_name_len = ksmbd_map_ea_name_to_xattr(eabuf->name,
+		attr_name_len = ksmbd_map_ea_name_to_xattr(work, native_xattrs,
+							   eabuf->name,
 							   eabuf->EaNameLength,
 							   attr_name);
 		if (attr_name_len < 0) {
-			rc = -EINVAL;
+			rc = attr_name_len;
 			break;
 		}
 
@@ -3742,9 +3764,9 @@ int smb2_open(struct ksmbd_work *work)
 				goto err_out;
 			}
 
-			rc = smb2_set_ea(&ea_buf->ea,
+			rc = smb2_set_ea(work, &ea_buf->ea,
 					 le32_to_cpu(ea_buf->ccontext.DataLength),
-					 &path, true);
+					 &path, true, posix_ctxt);
 			if (rc == -EOPNOTSUPP)
 				rc = 0;
 			else if (rc)
@@ -7132,8 +7154,9 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
 		if (buf_len < sizeof(struct smb2_ea_info))
 			return -EMSGSIZE;
 
-		return smb2_set_ea((struct smb2_ea_info *)buffer,
-				   buf_len, &fp->filp->f_path, true);
+		return smb2_set_ea(work, (struct smb2_ea_info *)buffer,
+				   buf_len, &fp->filp->f_path, true,
+				   fp->is_posix_ctxt);
 	}
 	case FILE_POSITION_INFORMATION:
 	{
-- 
2.43.0