Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

smb: client: parse uid, gid, mode and dev from WSL reparse points

Parse the extended attributes from WSL reparse points to correctly
report uid, gid mode and dev from ther instantiated inodes.

Signed-off-by: Paulo Alcantara <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Paulo Alcantara and committed by
Steve French
78e26bec ea41367b

+97 -17
+2 -3
fs/smb/client/inode.c
··· 759 759 fattr->cf_bytes = le64_to_cpu(info->AllocationSize); 760 760 fattr->cf_createtime = le64_to_cpu(info->CreationTime); 761 761 fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks); 762 + fattr->cf_uid = cifs_sb->ctx->linux_uid; 763 + fattr->cf_gid = cifs_sb->ctx->linux_gid; 762 764 763 765 fattr->cf_mode = cifs_sb->ctx->file_mode; 764 766 if (cifs_open_data_reparse(data) && ··· 803 801 fattr->cf_symlink_target = data->symlink_target; 804 802 data->symlink_target = NULL; 805 803 } 806 - 807 - fattr->cf_uid = cifs_sb->ctx->linux_uid; 808 - fattr->cf_gid = cifs_sb->ctx->linux_gid; 809 804 } 810 805 811 806 static int
+2
fs/smb/client/readdir.c
··· 125 125 if (likely(reparse_inode_match(inode, fattr))) { 126 126 fattr->cf_mode = inode->i_mode; 127 127 fattr->cf_rdev = inode->i_rdev; 128 + fattr->cf_uid = inode->i_uid; 129 + fattr->cf_gid = inode->i_gid; 128 130 fattr->cf_eof = CIFS_I(inode)->netfs.remote_i_size; 129 131 fattr->cf_symlink_target = NULL; 130 132 } else {
+64 -14
fs/smb/client/reparse.c
··· 258 258 { 259 259 struct cifs_open_info_data data; 260 260 struct reparse_data_buffer buf; 261 + struct smb2_create_ea_ctx *cc; 261 262 struct inode *new; 263 + unsigned int len; 262 264 struct kvec reparse_iov, xattr_iov; 263 265 int rc; 264 266 ··· 276 274 .reparse_point = true, 277 275 .reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, }, 278 276 }; 277 + 278 + cc = xattr_iov.iov_base; 279 + len = le32_to_cpu(cc->ctx.DataLength); 280 + memcpy(data.wsl.eas, &cc->ea, len); 281 + data.wsl.eas_len = len; 279 282 280 283 new = smb2_get_reparse_inode(&data, inode->i_sb, 281 284 xid, tcon, full_path, ··· 415 408 return parse_reparse_point(buf, plen, cifs_sb, true, data); 416 409 } 417 410 411 + static void wsl_to_fattr(struct cifs_open_info_data *data, 412 + struct cifs_sb_info *cifs_sb, 413 + u32 tag, struct cifs_fattr *fattr) 414 + { 415 + struct smb2_file_full_ea_info *ea; 416 + u32 next = 0; 417 + 418 + switch (tag) { 419 + case IO_REPARSE_TAG_LX_SYMLINK: 420 + fattr->cf_mode |= S_IFLNK; 421 + break; 422 + case IO_REPARSE_TAG_LX_FIFO: 423 + fattr->cf_mode |= S_IFIFO; 424 + break; 425 + case IO_REPARSE_TAG_AF_UNIX: 426 + fattr->cf_mode |= S_IFSOCK; 427 + break; 428 + case IO_REPARSE_TAG_LX_CHR: 429 + fattr->cf_mode |= S_IFCHR; 430 + break; 431 + case IO_REPARSE_TAG_LX_BLK: 432 + fattr->cf_mode |= S_IFBLK; 433 + break; 434 + } 435 + 436 + if (!data->wsl.eas_len) 437 + goto out; 438 + 439 + ea = (struct smb2_file_full_ea_info *)data->wsl.eas; 440 + do { 441 + const char *name; 442 + void *v; 443 + u8 nlen; 444 + 445 + ea = (void *)((u8 *)ea + next); 446 + next = le32_to_cpu(ea->next_entry_offset); 447 + if (!le16_to_cpu(ea->ea_value_length)) 448 + continue; 449 + 450 + name = ea->ea_data; 451 + nlen = ea->ea_name_length; 452 + v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1); 453 + 454 + if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen)) 455 + fattr->cf_uid = wsl_make_kuid(cifs_sb, v); 456 + else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) 457 + fattr->cf_gid = wsl_make_kgid(cifs_sb, v); 458 + else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) 459 + fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v); 460 + else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen)) 461 + fattr->cf_rdev = wsl_mkdev(v); 462 + } while (next); 463 + out: 464 + fattr->cf_dtype = S_DT(fattr->cf_mode); 465 + } 466 + 418 467 bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb, 419 468 struct cifs_fattr *fattr, 420 469 struct cifs_open_info_data *data) ··· 511 448 512 449 switch (tag) { 513 450 case IO_REPARSE_TAG_LX_SYMLINK: 514 - fattr->cf_mode |= S_IFLNK; 515 - fattr->cf_dtype = DT_LNK; 516 - break; 517 451 case IO_REPARSE_TAG_LX_FIFO: 518 - fattr->cf_mode |= S_IFIFO; 519 - fattr->cf_dtype = DT_FIFO; 520 - break; 521 452 case IO_REPARSE_TAG_AF_UNIX: 522 - fattr->cf_mode |= S_IFSOCK; 523 - fattr->cf_dtype = DT_SOCK; 524 - break; 525 453 case IO_REPARSE_TAG_LX_CHR: 526 - fattr->cf_mode |= S_IFCHR; 527 - fattr->cf_dtype = DT_CHR; 528 - break; 529 454 case IO_REPARSE_TAG_LX_BLK: 530 - fattr->cf_mode |= S_IFBLK; 531 - fattr->cf_dtype = DT_BLK; 455 + wsl_to_fattr(data, cifs_sb, tag, fattr); 532 456 break; 533 457 case 0: /* SMB1 symlink */ 534 458 case IO_REPARSE_TAG_SYMLINK:
+29
fs/smb/client/reparse.h
··· 8 8 9 9 #include <linux/fs.h> 10 10 #include <linux/stat.h> 11 + #include <linux/uidgid.h> 12 + #include "fs_context.h" 11 13 #include "cifsglob.h" 12 14 13 15 static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf) ··· 17 15 u64 v = le64_to_cpu(*(__le64 *)buf->DataBuffer); 18 16 19 17 return MKDEV(v >> 32, v & 0xffffffff); 18 + } 19 + 20 + static inline dev_t wsl_mkdev(void *ptr) 21 + { 22 + u64 v = le64_to_cpu(*(__le64 *)ptr); 23 + 24 + return MKDEV(v & 0xffffffff, v >> 32); 25 + } 26 + 27 + static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb, 28 + void *ptr) 29 + { 30 + u32 uid = le32_to_cpu(*(__le32 *)ptr); 31 + 32 + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) 33 + return cifs_sb->ctx->linux_uid; 34 + return make_kuid(current_user_ns(), uid); 35 + } 36 + 37 + static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb, 38 + void *ptr) 39 + { 40 + u32 gid = le32_to_cpu(*(__le32 *)ptr); 41 + 42 + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) 43 + return cifs_sb->ctx->linux_gid; 44 + return make_kgid(current_user_ns(), gid); 20 45 } 21 46 22 47 static inline u64 reparse_mode_nfs_type(mode_t mode)