Skip to content

Commit 97db416

Browse files
Paulo Alcantaragregkh
authored andcommitted
smb: client: parse uid, gid, mode and dev from WSL reparse points
[ Upstream commit 78e26be ] 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 <[email protected]> Signed-off-by: Steve French <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 7449d73 commit 97db416

File tree

4 files changed

+97
-17
lines changed

4 files changed

+97
-17
lines changed

fs/smb/client/inode.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,8 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
759759
fattr->cf_bytes = le64_to_cpu(info->AllocationSize);
760760
fattr->cf_createtime = le64_to_cpu(info->CreationTime);
761761
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;
762764

763765
fattr->cf_mode = cifs_sb->ctx->file_mode;
764766
if (cifs_open_data_reparse(data) &&
@@ -801,9 +803,6 @@ static void cifs_open_info_to_fattr(struct cifs_fattr *fattr,
801803
fattr->cf_symlink_target = data->symlink_target;
802804
data->symlink_target = NULL;
803805
}
804-
805-
fattr->cf_uid = cifs_sb->ctx->linux_uid;
806-
fattr->cf_gid = cifs_sb->ctx->linux_gid;
807806
}
808807

809808
static int

fs/smb/client/readdir.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
125125
if (likely(reparse_inode_match(inode, fattr))) {
126126
fattr->cf_mode = inode->i_mode;
127127
fattr->cf_rdev = inode->i_rdev;
128+
fattr->cf_uid = inode->i_uid;
129+
fattr->cf_gid = inode->i_gid;
128130
fattr->cf_eof = CIFS_I(inode)->server_eof;
129131
fattr->cf_symlink_target = NULL;
130132
} else {

fs/smb/client/reparse.c

Lines changed: 64 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,9 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
258258
{
259259
struct cifs_open_info_data data;
260260
struct reparse_data_buffer buf;
261+
struct smb2_create_ea_ctx *cc;
261262
struct inode *new;
263+
unsigned int len;
262264
struct kvec reparse_iov, xattr_iov;
263265
int rc;
264266

@@ -275,6 +277,11 @@ static int mknod_wsl(unsigned int xid, struct inode *inode,
275277
.reparse = { .tag = le32_to_cpu(buf.ReparseTag), .buf = &buf, },
276278
};
277279

280+
cc = xattr_iov.iov_base;
281+
len = le32_to_cpu(cc->ctx.DataLength);
282+
memcpy(data.wsl.eas, &cc->ea, len);
283+
data.wsl.eas_len = len;
284+
278285
new = smb2_get_reparse_inode(&data, inode->i_sb,
279286
xid, tcon, full_path,
280287
&reparse_iov, &xattr_iov);
@@ -408,6 +415,62 @@ int smb2_parse_reparse_point(struct cifs_sb_info *cifs_sb,
408415
return parse_reparse_point(buf, plen, cifs_sb, true, data);
409416
}
410417

418+
static void wsl_to_fattr(struct cifs_open_info_data *data,
419+
struct cifs_sb_info *cifs_sb,
420+
u32 tag, struct cifs_fattr *fattr)
421+
{
422+
struct smb2_file_full_ea_info *ea;
423+
u32 next = 0;
424+
425+
switch (tag) {
426+
case IO_REPARSE_TAG_LX_SYMLINK:
427+
fattr->cf_mode |= S_IFLNK;
428+
break;
429+
case IO_REPARSE_TAG_LX_FIFO:
430+
fattr->cf_mode |= S_IFIFO;
431+
break;
432+
case IO_REPARSE_TAG_AF_UNIX:
433+
fattr->cf_mode |= S_IFSOCK;
434+
break;
435+
case IO_REPARSE_TAG_LX_CHR:
436+
fattr->cf_mode |= S_IFCHR;
437+
break;
438+
case IO_REPARSE_TAG_LX_BLK:
439+
fattr->cf_mode |= S_IFBLK;
440+
break;
441+
}
442+
443+
if (!data->wsl.eas_len)
444+
goto out;
445+
446+
ea = (struct smb2_file_full_ea_info *)data->wsl.eas;
447+
do {
448+
const char *name;
449+
void *v;
450+
u8 nlen;
451+
452+
ea = (void *)((u8 *)ea + next);
453+
next = le32_to_cpu(ea->next_entry_offset);
454+
if (!le16_to_cpu(ea->ea_value_length))
455+
continue;
456+
457+
name = ea->ea_data;
458+
nlen = ea->ea_name_length;
459+
v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1);
460+
461+
if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen))
462+
fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
463+
else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen))
464+
fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
465+
else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen))
466+
fattr->cf_mode = (umode_t)le32_to_cpu(*(__le32 *)v);
467+
else if (!strncmp(name, SMB2_WSL_XATTR_DEV, nlen))
468+
fattr->cf_rdev = wsl_mkdev(v);
469+
} while (next);
470+
out:
471+
fattr->cf_dtype = S_DT(fattr->cf_mode);
472+
}
473+
411474
bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
412475
struct cifs_fattr *fattr,
413476
struct cifs_open_info_data *data)
@@ -448,24 +511,11 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
448511

449512
switch (tag) {
450513
case IO_REPARSE_TAG_LX_SYMLINK:
451-
fattr->cf_mode |= S_IFLNK;
452-
fattr->cf_dtype = DT_LNK;
453-
break;
454514
case IO_REPARSE_TAG_LX_FIFO:
455-
fattr->cf_mode |= S_IFIFO;
456-
fattr->cf_dtype = DT_FIFO;
457-
break;
458515
case IO_REPARSE_TAG_AF_UNIX:
459-
fattr->cf_mode |= S_IFSOCK;
460-
fattr->cf_dtype = DT_SOCK;
461-
break;
462516
case IO_REPARSE_TAG_LX_CHR:
463-
fattr->cf_mode |= S_IFCHR;
464-
fattr->cf_dtype = DT_CHR;
465-
break;
466517
case IO_REPARSE_TAG_LX_BLK:
467-
fattr->cf_mode |= S_IFBLK;
468-
fattr->cf_dtype = DT_BLK;
518+
wsl_to_fattr(data, cifs_sb, tag, fattr);
469519
break;
470520
case 0: /* SMB1 symlink */
471521
case IO_REPARSE_TAG_SYMLINK:

fs/smb/client/reparse.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include <linux/fs.h>
1010
#include <linux/stat.h>
11+
#include <linux/uidgid.h>
12+
#include "fs_context.h"
1113
#include "cifsglob.h"
1214

1315
static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf)
@@ -17,6 +19,33 @@ static inline dev_t reparse_nfs_mkdev(struct reparse_posix_data *buf)
1719
return MKDEV(v >> 32, v & 0xffffffff);
1820
}
1921

22+
static inline dev_t wsl_mkdev(void *ptr)
23+
{
24+
u64 v = le64_to_cpu(*(__le64 *)ptr);
25+
26+
return MKDEV(v & 0xffffffff, v >> 32);
27+
}
28+
29+
static inline kuid_t wsl_make_kuid(struct cifs_sb_info *cifs_sb,
30+
void *ptr)
31+
{
32+
u32 uid = le32_to_cpu(*(__le32 *)ptr);
33+
34+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
35+
return cifs_sb->ctx->linux_uid;
36+
return make_kuid(current_user_ns(), uid);
37+
}
38+
39+
static inline kgid_t wsl_make_kgid(struct cifs_sb_info *cifs_sb,
40+
void *ptr)
41+
{
42+
u32 gid = le32_to_cpu(*(__le32 *)ptr);
43+
44+
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)
45+
return cifs_sb->ctx->linux_gid;
46+
return make_kgid(current_user_ns(), gid);
47+
}
48+
2049
static inline u64 reparse_mode_nfs_type(mode_t mode)
2150
{
2251
switch (mode & S_IFMT) {

0 commit comments

Comments
 (0)