smb client fixes for v7.3-rc3

A batch of bug fixes for the smb client:
 
  - File type corruption fixes in reparse point handling: setting S_IFMT
    bits without clearing the existing type first corrupted the file mode
    (e.g. S_IFREG | S_IFCHR == S_IFLNK). Fixed in the WSL, POSIX and
    native symlink reparse parsers. Also fixes an uninitialized SID
    structure in the POSIX readdir path when parsing fails.
 
  - Ownership mapping fixes: forceuid/forcegid mount options were
    ignored in several code paths (SID-to-id mapping, WSL extended
    attributes, POSIX extensions getattr), allowing an untrusted server
    to dictate local file ownership despite explicit mount overrides.
 
  - Heap overflow and overflow fixes in DACL rewriting: replacing short
    SIDs with long ones could overflow the DACL buffer, and the u16
    accumulator for DACL size could wrap around with enough ACEs.
 
  - Reference count leak fixes in oplock break and deferred close:
    duplicate oplock breaks on a queued work item leaked a
    cifsFileInfo reference, and deferred close had a similar leak when
    requeueing a running work item. Both cause busy-inode oopses on
    unmount.
 
  - DFS superblock use-after-free fix: the iterator callback stored a
    raw superblock pointer without pinning it, racing with automount
    expiry.
 
  - One-byte slab OOB read in the native symlink parser when handling
    share-root relative paths.
 
  - Hardening of legacy SMB1 input: reject userspace-crafted
    cifs.idmap key descriptions that bypass kernel origin checks, and
    validate DataOffset in CIFSSMBRead() to prevent heap info
    disclosure from a malicious server.
 
  - DFS cache fix: defer metadata updates until target copying
    succeeds to prevent partial-state cache entries on allocation
    failure.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTcqRusfSdYROJQwGkpVtNKoQNdYwUCaqLMxAAKCRApVtNKoQNd
 YwSyAQDUDSxCnDMmJbRr4e22oF/YrGSN/snp8cqrZlZh2pb5/gD/c2G3xMJA85YP
 yL/G8auRWkpwDl0/Parqptjhx1c9YwE=
 =PjPM
 -----END PGP SIGNATURE-----

Merge tag 'cifs-fixes-7.3-rc3' of https://git.manguebit.org/linux

Pull smb client fixes from Paulo Alcantara:

 - File type corruption fixes in reparse point handling: setting S_IFMT
   bits without clearing the existing type first corrupted the file mode
   (e.g. S_IFREG | S_IFCHR == S_IFLNK). Fixed in the WSL, POSIX and
   native symlink reparse parsers. Also fixes an uninitialized SID
   structure in the POSIX readdir path when parsing fails.

 - Ownership mapping fixes: forceuid/forcegid mount options were
   ignored in several code paths (SID-to-id mapping, WSL extended
   attributes, POSIX extensions getattr), allowing an untrusted server
   to dictate local file ownership despite explicit mount overrides.

 - Heap overflow and overflow fixes in DACL rewriting: replacing short
   SIDs with long ones could overflow the DACL buffer, and the u16
   accumulator for DACL size could wrap around with enough ACEs.

 - Reference count leak fixes in oplock break and deferred close:
   duplicate oplock breaks on a queued work item leaked a
   cifsFileInfo reference, and deferred close had a similar leak when
   requeueing a running work item. Both cause busy-inode oopses on
   unmount.

 - DFS superblock use-after-free fix: the iterator callback stored a
   raw superblock pointer without pinning it, racing with automount
   expiry.

 - One-byte slab OOB read in the native symlink parser when handling
   share-root relative paths.

 - Hardening of legacy SMB1 input: reject userspace-crafted
   cifs.idmap key descriptions that bypass kernel origin checks, and
   validate DataOffset in CIFSSMBRead() to prevent heap info
   disclosure from a malicious server.

 - DFS cache fix: defer metadata updates until target copying
   succeeds to prevent partial-state cache entries on allocation
   failure.

* tag 'cifs-fixes-7.3-rc3' of https://git.manguebit.org/linux:
  smb: client: fix one-byte OOB read in smb2_parse_native_symlink()
  smb: client: fail DACL rewrite when the new DACL exceeds 64K
  smb: client: fix heap overflow in DACL owner/group rewrite
  smb: client: fix file type corruption in cifs_reparse_point_to_fattr()
  smb: client: fix file type corruption in posix_reparse_to_fattr()
  smb: client: fix file type corruption in wsl_to_fattr()
  smb: client: avoid using uninitialized SIDs in cifs_posix_to_fattr()
  smb: client: fix WSL reparse point uid/gid override
  smb: client: honor forceuid/forcegid when mapping SIDs to uid/gid
  smb: client: fix uid/gid override in getattr with posix extensions
  smb: client: fix cifsFileInfo reference leak in deferred close
  smb: client: avoid leaking refcount when cifs_sb_tlink() fails
  smb: client: avoid leaking refcount in cifs_queue_oplock_break()
  smb: client: fill cache fields after populating cache in copy_ref_data()
  smb: client: pin DFS superblock in iterator callback
  smb: client: reject userspace cifs.idmap descriptions
  smb: client: reject out-of-bounds DataOffset in CIFSSMBRead()
  smb: client: reject short READ responses in CIFSSMBRead()
This commit is contained in:
Linus Torvalds 2026-09-10 14:03:48 -07:00
commit 0a96d0d726
9 changed files with 172 additions and 81 deletions

View File

@ -100,8 +100,23 @@ cifs_idmap_key_destroy(struct key *key)
kfree(key->payload.data[0]);
}
static int
cifs_idmap_key_vet_description(const char *description)
{
/*
* cifs.idmap descriptions are authority-bearing inputs to the
* cifs.idmap upcall helper. Only allow the kernel to create this
* type of key using the private root_cred installed in
* init_cifs_idmap; reject userspace request_key(2)/add_key(2).
*/
if (current_cred() != root_cred)
return -EPERM;
return 0;
}
static struct key_type cifs_idmap_key_type = {
.name = "cifs.idmap",
.vet_description = cifs_idmap_key_vet_description,
.instantiate = cifs_idmap_key_instantiate,
.destroy = cifs_idmap_key_destroy,
.describe = user_describe,
@ -1081,13 +1096,13 @@ unsigned int setup_special_user_owner_ACE(struct smb_ace *pntace)
static void populate_new_aces(char *nacl_base,
struct smb_sid *pownersid,
struct smb_sid *pgrpsid,
__u64 *pnmode, u16 *pnum_aces, u16 *pnsize,
__u64 *pnmode, u16 *pnum_aces, u32 *pnsize,
bool modefromsid,
bool posix)
{
__u64 nmode;
u16 num_aces = 0;
u16 nsize = 0;
u32 nsize = 0;
__u64 user_mode;
__u64 group_mode;
__u64 other_mode;
@ -1186,17 +1201,17 @@ static void populate_new_aces(char *nacl_base,
*pnsize = nsize;
}
static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *pndacl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
struct smb_sid *pnownersid, struct smb_sid *pngrpsid,
int *aclflag)
static int replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *pndacl,
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
struct smb_sid *pnownersid, struct smb_sid *pngrpsid,
int *aclflag, u16 *pnsize)
{
int i;
u16 size = 0;
struct smb_ace *pntace = NULL;
char *acl_base = NULL;
u16 src_num_aces = 0;
u16 nsize = 0;
u32 nsize = 0;
struct smb_ace *pnntace = NULL;
char *nacl_base = NULL;
u16 ace_size = 0;
@ -1225,9 +1240,12 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
size += le16_to_cpu(pntace->size);
nsize += ace_size;
if (nsize > U16_MAX)
return -EOVERFLOW;
}
return nsize;
*pnsize = nsize;
return 0;
}
static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
@ -1239,7 +1257,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
struct smb_ace *pntace = NULL;
char *acl_base = NULL;
u16 src_num_aces = 0;
u16 nsize = 0;
u32 nsize = 0;
struct smb_ace *pnntace = NULL;
char *nacl_base = NULL;
u16 num_aces = 0;
@ -1290,6 +1308,8 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
nsize += cifs_copy_ace(pnntace, pntace, NULL);
num_aces++;
if (nsize > U16_MAX)
return -EOVERFLOW;
next_ace:
size += le16_to_cpu(pntace->size);
@ -1306,6 +1326,10 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
}
finalize_dacl:
/* The DACL size field is 16-bit on the wire, see MS-DTYP 2.4.5 */
if (nsize > U16_MAX)
return -EOVERFLOW;
pndacl->num_aces = cpu_to_le16(num_aces);
pndacl->size = cpu_to_le16(nsize);
@ -1331,6 +1355,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
{
int rc = 0;
struct smb_sid *owner_sid_ptr, *group_sid_ptr;
unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct smb_acl *dacl_ptr; /* no need for SACL ptr */
char *end_of_acl;
__u32 dacloffset, osidoffset, gsidoffset;
@ -1349,17 +1374,21 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
cifs_dbg(NOISY, "revision %d type 0x%x ooffset 0x%x goffset 0x%x sacloffset 0x%x dacloffset 0x%x\n",
pntsd->revision, pntsd->type, osidoffset, gsidoffset,
le32_to_cpu(pntsd->sacloffset), dacloffset);
/* cifs_dump_mem("owner_sid: ", owner_sid_ptr, 64); */
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
rc = sid_from_sd(pntsd, acl_len, osidoffset, &owner_sid_ptr);
if (rc) {
cifs_dbg(FYI, "%s: Error %d parsing Owner SID\n", __func__, rc);
return rc;
}
rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
if (rc) {
cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
__func__, rc);
return rc;
if (!(sbflags & CIFS_MOUNT_OVERR_UID)) {
rc = sid_to_id(cifs_sb, owner_sid_ptr, fattr, SIDOWNER);
if (rc) {
cifs_dbg(FYI, "%s: Error %d mapping Owner SID to uid\n",
__func__, rc);
return rc;
}
}
rc = sid_from_sd(pntsd, acl_len, gsidoffset, &group_sid_ptr);
@ -1368,11 +1397,13 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
__func__, rc);
return rc;
}
rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
if (rc) {
cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
__func__, rc);
return rc;
if (!(sbflags & CIFS_MOUNT_OVERR_GID)) {
rc = sid_to_id(cifs_sb, group_sid_ptr, fattr, SIDGROUP);
if (rc) {
cifs_dbg(FYI, "%s: Error %d mapping Group SID to gid\n",
__func__, rc);
return rc;
}
}
if (dacloffset) {
@ -1451,6 +1482,8 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
pnmode, mode_from_sid, posix);
if (rc)
return rc;
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
/* copy the non-dacl portion of secdesc */
@ -1526,10 +1559,12 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
if (dacloffset) {
/* Replace ACEs for old owner with new one */
size = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
owner_sid_ptr, group_sid_ptr,
nowner_sid_ptr, ngroup_sid_ptr,
aclflag);
rc = replace_sids_and_copy_aces(dacl_ptr, ndacl_ptr,
owner_sid_ptr, group_sid_ptr,
nowner_sid_ptr, ngroup_sid_ptr,
aclflag, &size);
if (rc)
goto chown_chgrp_exit;
ndacl_ptr->size = cpu_to_le16(size);
}
@ -1815,11 +1850,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
cifs_put_tlink(tlink);
return rc;
}
if (mode_from_sid)
nsecdesclen +=
le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
else /* cifsacl */
nsecdesclen += le16_to_cpu(dacl_ptr->size);
/*
* Worst case: every ACE is rewritten with a new SID of
* SID_MAX_SUB_AUTHORITIES sub-auths -> sizeof(smb_ace) each,
* plus the smb_acl header replace_sids_and_copy_aces() emits.
*/
nsecdesclen += sizeof(struct smb_acl) +
le16_to_cpu(dacl_ptr->num_aces) * sizeof(struct smb_ace);
}
}

View File

@ -1719,8 +1719,17 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
pSMBr = (READ_RSP *)rsp_iov.iov_base;
if (rc) {
cifs_dbg(VFS, "Send error in read = %d\n", rc);
} else if (rsp_iov.iov_len < tcon->ses->server->vals->read_rsp_size) {
/* check that the received response can hold a whole READ_RSP */
cifs_dbg(FYI, "%s: server returned short header. got=%zu expected=%zu\n",
__func__, rsp_iov.iov_len,
tcon->ses->server->vals->read_rsp_size);
rc = smb_EIO2(smb_eio_trace_read_rsp_short,
rsp_iov.iov_len, tcon->ses->server->vals->read_rsp_size);
*nbytes = 0;
} else {
int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
unsigned int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
__u16 data_offset = le16_to_cpu(pSMBr->DataOffset);
data_length = data_length << 16;
data_length += le16_to_cpu(pSMBr->DataLength);
*nbytes = data_length;
@ -1728,14 +1737,21 @@ CIFSSMBRead(const unsigned int xid, struct cifs_io_parms *io_parms,
/*check that DataLength would not go beyond end of SMB */
if ((data_length > CIFSMaxBufSize)
|| (data_length > count)) {
cifs_dbg(FYI, "bad length %d for count %d\n",
data_length, count);
cifs_dbg(FYI, "%s: bad length %u for count %u\n",
__func__, data_length, count);
rc = smb_EIO2(smb_eio_trace_read_overlarge,
data_length, count);
*nbytes = 0;
} else if (data_offset < sizeof(*pSMBr) ||
(size_t)data_offset + data_length > rsp_iov.iov_len) {
/* check that the data lies within the received response */
cifs_dbg(FYI, "%s: bad data offset %u length %u for response of %zu\n",
__func__, data_offset, data_length, rsp_iov.iov_len);
rc = smb_EIO2(smb_eio_trace_read_bad_offset,
data_offset, data_length);
*nbytes = 0;
} else {
pReadData = (char *) (&pSMBr->hdr.Protocol) +
le16_to_cpu(pSMBr->DataOffset);
pReadData = (char *) (&pSMBr->hdr.Protocol) + data_offset;
/* if (rc = copy_to_user(buf, pReadData, data_length)) {
cifs_dbg(VFS, "Faulting on read rc = %d\n",rc);
rc = -EFAULT;

View File

@ -123,6 +123,7 @@ static inline void free_tgts(struct cache_entry *ce)
kfree(t);
}
ce->numtgts = 0;
WRITE_ONCE(ce->tgthint, NULL);
}
@ -388,13 +389,6 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
struct cache_dfs_tgt *target;
int i;
ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL);
ce->etime = get_expire_time(ce->ttl);
ce->srvtype = refs[0].server_type;
ce->hdr_flags = refs[0].flags;
ce->ref_flags = refs[0].ref_flag;
ce->path_consumed = refs[0].path_consumed;
for (i = 0; i < numrefs; i++) {
struct cache_dfs_tgt *t;
@ -409,12 +403,19 @@ static int copy_ref_data(const struct dfs_info3_param *refs, int numrefs,
} else {
list_add_tail(&t->list, &ce->tlist);
}
ce->numtgts++;
}
target = list_first_entry_or_null(&ce->tlist, struct cache_dfs_tgt,
list);
WRITE_ONCE(ce->tgthint, target);
ce->ttl = max_t(int, refs[0].ttl, CACHE_MIN_TTL);
ce->etime = get_expire_time(ce->ttl);
ce->srvtype = refs[0].server_type;
ce->hdr_flags = refs[0].flags;
ce->ref_flags = refs[0].ref_flag;
ce->path_consumed = refs[0].path_consumed;
ce->numtgts = numrefs;
return 0;
}
@ -634,7 +635,6 @@ static int update_cache_entry_locked(struct cache_entry *ce, const struct dfs_in
}
free_tgts(ce);
ce->numtgts = 0;
rc = copy_ref_data(refs, numrefs, ce, th);

View File

@ -1515,11 +1515,18 @@ int cifs_close(struct inode *inode, struct file *file)
trace_smb3_close_cached(tcon->tid, tcon->ses->Suid,
cfile->fid.persistent_fid,
cifs_sb->ctx->closetimeo);
queue_delayed_work(deferredclose_wq,
&cfile->deferred, cifs_sb->ctx->closetimeo);
cfile->deferred_close_scheduled = true;
spin_unlock(&cinode->deferred_lock);
return 0;
/*
* Each queued execution owns one reference.
* If nothing was queued, the reference of
* the closing file is dropped below.
*/
if (queue_delayed_work(deferredclose_wq,
&cfile->deferred,
cifs_sb->ctx->closetimeo)) {
cfile->deferred_close_scheduled = true;
spin_unlock(&cinode->deferred_lock);
return 0;
}
}
spin_unlock(&cinode->deferred_lock);
_cifsFileInfo_put(cfile, true, false);
@ -3348,8 +3355,11 @@ void cifs_oplock_break(struct work_struct *work)
TASK_UNINTERRUPTIBLE);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
if (IS_ERR(tlink)) {
/* drop the reference taken when the break was queued */
_cifsFileInfo_put(cfile, false /* do not wait for ourself */, false);
goto out;
}
tcon = tlink_tcon(tlink);
server = tcon->ses->server;

View File

@ -851,6 +851,7 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
struct smb311_posix_qinfo *info = &data->posix_fi;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
unsigned int sbflags = cifs_sb_flags(cifs_sb);
memset(fattr, 0, sizeof(*fattr));
@ -895,8 +896,12 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr,
fattr->cf_symlink_target = data->symlink_target;
data->symlink_target = NULL;
}
sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER);
sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP);
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
if (!(sbflags & CIFS_MOUNT_OVERR_UID))
sid_to_id(cifs_sb, &data->posix_owner, fattr, SIDOWNER);
if (!(sbflags & CIFS_MOUNT_OVERR_GID))
sid_to_id(cifs_sb, &data->posix_group, fattr, SIDGROUP);
cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
@ -2992,14 +2997,14 @@ int cifs_getattr(struct mnt_idmap *idmap, const struct path *path,
stat->attributes |= STATX_ATTR_ENCRYPTED;
/*
* If on a multiuser mount without unix extensions or cifsacl being
* enabled, and the admin hasn't overridden them, set the ownership
* to the fsuid/fsgid of the current process.
* If on a multiuser mount without unix extensions, posix extensions
* or cifsacl being enabled, and the admin hasn't overridden them,
* set the ownership to the fsuid/fsgid of the current process.
*/
sbflags = cifs_sb_flags(cifs_sb);
if ((sbflags & CIFS_MOUNT_MULTIUSER) &&
!(sbflags & CIFS_MOUNT_CIFS_ACL) &&
!tcon->unix_ext) {
!tcon->unix_ext && !tcon->posix_extensions) {
if (!(sbflags & CIFS_MOUNT_OVERR_UID))
stat->uid = current_fsuid();
if (!(sbflags & CIFS_MOUNT_OVERR_GID))

View File

@ -378,10 +378,11 @@ void cifs_queue_oplock_break(struct cifsFileInfo *cfile)
* open_file_lock to enforce the validity of it for the oplock
* break handler. The matching put is done at the end of the
* handler.
*
* Only take a reference if the work is actually queued.
*/
cifsFileInfo_get(cfile);
queue_work(cifsoplockd_wq, &cfile->oplock_break);
if (queue_work(cifsoplockd_wq, &cfile->oplock_break))
cifsFileInfo_get(cfile);
}
void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
@ -891,8 +892,14 @@ static void tcon_super_cb(struct super_block *sb, void *arg)
t1->ses->dfs_root_ses == t2->ses->dfs_root_ses) &&
t1->ses->server == t2->ses->server &&
t2->origin_fullpath &&
dfs_src_pathname_equal(t2->origin_fullpath, t1->origin_fullpath))
dfs_src_pathname_equal(t2->origin_fullpath, t1->origin_fullpath)) {
/*
* Take the active reference while iterate_supers_type() still
* holds s_umount shared.
*/
cifs_sb_active(sb);
sd->sb = sb;
}
spin_unlock(&t2->tc_lock);
}
@ -909,15 +916,8 @@ static struct super_block *__cifs_get_super(void (*f)(struct super_block *, void
for (; *fs_type; fs_type++) {
iterate_supers_type(*fs_type, f, &sd);
if (sd.sb) {
/*
* Grab an active reference in order to prevent automounts (DFS links)
* of expiring and then freeing up our cifs superblock pointer while
* we're doing failover.
*/
cifs_sb_active(sd.sb);
if (sd.sb)
return sd.sb;
}
}
pr_warn_once("%s: could not find dfs superblock\n", __func__);
return ERR_PTR(-EINVAL);

View File

@ -242,9 +242,11 @@ static void
cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
struct cifs_sb_info *cifs_sb)
{
unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct smb2_posix_info_parsed parsed;
int rc;
posix_info_parse(info, NULL, &parsed);
rc = posix_info_parse(info, NULL, &parsed);
memset(fattr, 0, sizeof(*fattr));
fattr->cf_uniqueid = le64_to_cpu(info->Inode);
@ -281,8 +283,17 @@ cifs_posix_to_fattr(struct cifs_fattr *fattr, struct smb2_posix_info *info,
le32_to_cpu(info->ReparseTag),
le32_to_cpu(info->Mode));
sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
if (rc < 0) {
cifs_dbg(VFS, "%s: failed to parse SIDs: %d\n",
__func__, rc);
} else {
if (!(sbflags & CIFS_MOUNT_OVERR_UID))
sid_to_id(cifs_sb, &parsed.owner, fattr, SIDOWNER);
if (!(sbflags & CIFS_MOUNT_OVERR_GID))
sid_to_id(cifs_sb, &parsed.group, fattr, SIDGROUP);
}
}
static void __dir_info_to_fattr(struct cifs_fattr *fattr, const void *info)

View File

@ -971,7 +971,8 @@ int smb2_parse_native_symlink(char **target, const char *buf, unsigned int len,
linux_target[i*3 + 1] = '.';
linux_target[i*3 + 2] = sep;
}
memcpy(linux_target + levels*3, smb_target+1, smb_target_len); /* +1 to skip leading sep */
/* +1 to skip leading sep */
memcpy(linux_target + levels*3, smb_target+1, smb_target_len-1);
} else {
/*
* This is either an absolute symlink in POSIX-style format
@ -1137,10 +1138,15 @@ static bool wsl_to_fattr(struct cifs_open_info_data *data,
struct cifs_sb_info *cifs_sb,
u32 tag, struct cifs_fattr *fattr)
{
unsigned int sbflags = cifs_sb_flags(cifs_sb);
struct smb2_file_full_ea_info *ea;
bool have_xattr_dev = false;
u32 next = 0;
fattr->cf_uid = cifs_sb->ctx->linux_uid;
fattr->cf_gid = cifs_sb->ctx->linux_gid;
fattr->cf_mode &= ~S_IFMT;
switch (tag) {
case IO_REPARSE_TAG_LX_SYMLINK:
fattr->cf_mode |= S_IFLNK;
@ -1177,11 +1183,13 @@ static bool wsl_to_fattr(struct cifs_open_info_data *data,
nlen = ea->ea_name_length;
v = (void *)((u8 *)ea->ea_data + ea->ea_name_length + 1);
if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen))
fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen))
fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) {
if (!strncmp(name, SMB2_WSL_XATTR_UID, nlen)) {
if (!(sbflags & CIFS_MOUNT_OVERR_UID))
fattr->cf_uid = wsl_make_kuid(cifs_sb, v);
} else if (!strncmp(name, SMB2_WSL_XATTR_GID, nlen)) {
if (!(sbflags & CIFS_MOUNT_OVERR_GID))
fattr->cf_gid = wsl_make_kgid(cifs_sb, v);
} else if (!strncmp(name, SMB2_WSL_XATTR_MODE, nlen)) {
/* File type in reparse point tag and in xattr mode must match. */
if (S_DT(fattr->cf_mode) != S_DT(le32_to_cpu(*(__le32 *)v)))
return false;
@ -1205,6 +1213,7 @@ static bool posix_reparse_to_fattr(struct cifs_sb_info *cifs_sb,
struct cifs_open_info_data *data)
{
struct reparse_nfs_data_buffer *buf = (struct reparse_nfs_data_buffer *)data->reparse.buf;
umode_t ftype;
if (buf == NULL)
return true;
@ -1220,7 +1229,7 @@ static bool posix_reparse_to_fattr(struct cifs_sb_info *cifs_sb,
WARN_ON_ONCE(1);
return false;
}
fattr->cf_mode |= S_IFCHR;
ftype = S_IFCHR;
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
break;
case NFS_SPECFILE_BLK:
@ -1228,22 +1237,23 @@ static bool posix_reparse_to_fattr(struct cifs_sb_info *cifs_sb,
WARN_ON_ONCE(1);
return false;
}
fattr->cf_mode |= S_IFBLK;
ftype = S_IFBLK;
fattr->cf_rdev = reparse_mkdev(buf->DataBuffer);
break;
case NFS_SPECFILE_FIFO:
fattr->cf_mode |= S_IFIFO;
ftype = S_IFIFO;
break;
case NFS_SPECFILE_SOCK:
fattr->cf_mode |= S_IFSOCK;
ftype = S_IFSOCK;
break;
case NFS_SPECFILE_LNK:
fattr->cf_mode |= S_IFLNK;
ftype = S_IFLNK;
break;
default:
WARN_ON_ONCE(1);
return false;
}
fattr->cf_mode = (fattr->cf_mode & ~S_IFMT) | ftype;
return true;
}
@ -1271,6 +1281,7 @@ bool cifs_reparse_point_to_fattr(struct cifs_sb_info *cifs_sb,
break;
case 0: /* SMB1 symlink */
case IO_REPARSE_TAG_SYMLINK:
fattr->cf_mode &= ~S_IFMT;
fattr->cf_mode |= S_IFLNK;
break;
default:

View File

@ -79,6 +79,7 @@
EM(smb_eio_trace_qreparse_setup_count, "qreparse_setup_count") \
EM(smb_eio_trace_qreparse_sizes_wrong, "qreparse_sizes_wrong") \
EM(smb_eio_trace_qsym_bcc_too_small, "qsym_bcc_too_small") \
EM(smb_eio_trace_read_bad_offset, "read_bad_offset") \
EM(smb_eio_trace_read_mid_state_unknown, "read_mid_state_unknown") \
EM(smb_eio_trace_read_overlarge, "read_overlarge") \
EM(smb_eio_trace_read_rsp_malformed, "read_rsp_malformed") \