mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 12:34:02 +02:00
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:
commit
0a96d0d726
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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") \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user