five small SMB3 fixes, all also for stable - an important fix for an oplock (lease) bug, a handle leak, and 3 bugs spotted by KASAN
-----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAly2PPMACgkQiiy9cAdy T1EbQQwArLGfousJE2mkQZIdAlefjeyCLJdFxOLktA3dd3EbmgOtxg8FSBt5W04X UqQ6i2cGL46Uecp+EaOTy2o0o3lc7eRGA83+0CYY+JLNLSS9g+RNgK2kIkcnj3h8 N/fovUg3yhdLO0tmh13FcwBDAYPqjSd4iija1icBXSkkZdp592ims3zJaGunHMGn s237jaLPzx7xxqNaGDD/MtQtpPDzZzPlVCszTnO3anGaSHB1R7HNhR9twWTF/mmz bfhLiOyquzzt53XyaTmtpnzMua5X+Rhii2Pq315Pb+71JQ5TBYWRIOx/8QKwdGS+ 9EiiiEgqYfwmcDl1KPnm1ppTF2++mYkFBFq43cgosagDaL8YXdqtCIrsVkTxXnmv +bKhiXpriPzsy5INuRgfWmODrbl2QLRY1qbS4I/lA0+uZxFu7palwmSBkMOgcorn 0TnejxsajTtYBpkzYKOuiRN7z4ukvR4FJd6xaxqSkyX+Jlda4wnwPTRVyBxOcL06 EaAxdi7X =vsJs -----END PGP SIGNATURE----- Merge tag '5.1-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6 Pull smb3 fixes from Steve French: "Five small SMB3 fixes, all also for stable - an important fix for an oplock (lease) bug, a handle leak, and three bugs spotted by KASAN" * tag '5.1-rc5-smb3-fixes' of git://git.samba.org/sfrench/cifs-2.6: CIFS: keep FileInfo handle live during oplock break cifs: fix handle leak in smb2_query_symlink() cifs: Fix lease buffer length error cifs: Fix use-after-free in SMB2_read cifs: Fix use-after-free in SMB2_write
This commit is contained in:
Коммит
e53f31bffe
|
@ -1333,6 +1333,7 @@ cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
|
|||
}
|
||||
|
||||
struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file);
|
||||
void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_hdlr);
|
||||
void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
|
||||
|
||||
#define CIFS_CACHE_READ_FLG 1
|
||||
|
@ -1855,6 +1856,7 @@ GLOBAL_EXTERN spinlock_t gidsidlock;
|
|||
#endif /* CONFIG_CIFS_ACL */
|
||||
|
||||
void cifs_oplock_break(struct work_struct *work);
|
||||
void cifs_queue_oplock_break(struct cifsFileInfo *cfile);
|
||||
|
||||
extern const struct slow_work_ops cifs_oplock_break_ops;
|
||||
extern struct workqueue_struct *cifsiod_wq;
|
||||
|
|
|
@ -360,12 +360,30 @@ cifsFileInfo_get(struct cifsFileInfo *cifs_file)
|
|||
return cifs_file;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a reference on the file private data. This may involve closing
|
||||
* the filehandle out on the server. Must be called without holding
|
||||
* tcon->open_file_lock and cifs_file->file_info_lock.
|
||||
/**
|
||||
* cifsFileInfo_put - release a reference of file priv data
|
||||
*
|
||||
* Always potentially wait for oplock handler. See _cifsFileInfo_put().
|
||||
*/
|
||||
void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
||||
{
|
||||
_cifsFileInfo_put(cifs_file, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* _cifsFileInfo_put - release a reference of file priv data
|
||||
*
|
||||
* This may involve closing the filehandle @cifs_file out on the
|
||||
* server. Must be called without holding tcon->open_file_lock and
|
||||
* cifs_file->file_info_lock.
|
||||
*
|
||||
* If @wait_for_oplock_handler is true and we are releasing the last
|
||||
* reference, wait for any running oplock break handler of the file
|
||||
* and cancel any pending one. If calling this function from the
|
||||
* oplock break handler, you need to pass false.
|
||||
*
|
||||
*/
|
||||
void _cifsFileInfo_put(struct cifsFileInfo *cifs_file, bool wait_oplock_handler)
|
||||
{
|
||||
struct inode *inode = d_inode(cifs_file->dentry);
|
||||
struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink);
|
||||
|
@ -414,7 +432,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
|
|||
|
||||
spin_unlock(&tcon->open_file_lock);
|
||||
|
||||
oplock_break_cancelled = cancel_work_sync(&cifs_file->oplock_break);
|
||||
oplock_break_cancelled = wait_oplock_handler ?
|
||||
cancel_work_sync(&cifs_file->oplock_break) : false;
|
||||
|
||||
if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
|
||||
struct TCP_Server_Info *server = tcon->ses->server;
|
||||
|
@ -4603,6 +4622,7 @@ void cifs_oplock_break(struct work_struct *work)
|
|||
cinode);
|
||||
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
|
||||
}
|
||||
_cifsFileInfo_put(cfile, false /* do not wait for ourself */);
|
||||
cifs_done_oplock_break(cinode);
|
||||
}
|
||||
|
||||
|
|
|
@ -501,8 +501,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
|
|||
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
|
||||
&pCifsInode->flags);
|
||||
|
||||
queue_work(cifsoplockd_wq,
|
||||
&netfile->oplock_break);
|
||||
cifs_queue_oplock_break(netfile);
|
||||
netfile->oplock_break_cancelled = false;
|
||||
|
||||
spin_unlock(&tcon->open_file_lock);
|
||||
|
@ -607,6 +606,28 @@ void cifs_put_writer(struct cifsInodeInfo *cinode)
|
|||
spin_unlock(&cinode->writers_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* cifs_queue_oplock_break - queue the oplock break handler for cfile
|
||||
*
|
||||
* This function is called from the demultiplex thread when it
|
||||
* receives an oplock break for @cfile.
|
||||
*
|
||||
* Assumes the tcon->open_file_lock is held.
|
||||
* Assumes cfile->file_info_lock is NOT held.
|
||||
*/
|
||||
void cifs_queue_oplock_break(struct cifsFileInfo *cfile)
|
||||
{
|
||||
/*
|
||||
* Bump the handle refcount now while we hold the
|
||||
* 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.
|
||||
*/
|
||||
cifsFileInfo_get(cfile);
|
||||
|
||||
queue_work(cifsoplockd_wq, &cfile->oplock_break);
|
||||
}
|
||||
|
||||
void cifs_done_oplock_break(struct cifsInodeInfo *cinode)
|
||||
{
|
||||
clear_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags);
|
||||
|
|
|
@ -555,7 +555,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
|
|||
clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
|
||||
&cinode->flags);
|
||||
|
||||
queue_work(cifsoplockd_wq, &cfile->oplock_break);
|
||||
cifs_queue_oplock_break(cfile);
|
||||
kfree(lw);
|
||||
return true;
|
||||
}
|
||||
|
@ -712,8 +712,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
|
|||
CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2,
|
||||
&cinode->flags);
|
||||
spin_unlock(&cfile->file_info_lock);
|
||||
queue_work(cifsoplockd_wq,
|
||||
&cfile->oplock_break);
|
||||
|
||||
cifs_queue_oplock_break(cfile);
|
||||
|
||||
spin_unlock(&tcon->open_file_lock);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
|
|
|
@ -2389,6 +2389,8 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_iov,
|
||||
&resp_buftype);
|
||||
if (!rc)
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
if (!rc || !err_iov.iov_base) {
|
||||
rc = -ENOENT;
|
||||
goto free_path;
|
||||
|
|
|
@ -832,8 +832,11 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
|
|||
} else if (rsp->DialectRevision == cpu_to_le16(SMB21_PROT_ID)) {
|
||||
/* ops set to 3.0 by default for default so update */
|
||||
ses->server->ops = &smb21_operations;
|
||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID))
|
||||
ses->server->vals = &smb21_values;
|
||||
} else if (rsp->DialectRevision == cpu_to_le16(SMB311_PROT_ID)) {
|
||||
ses->server->ops = &smb311_operations;
|
||||
ses->server->vals = &smb311_values;
|
||||
}
|
||||
} else if (le16_to_cpu(rsp->DialectRevision) !=
|
||||
ses->server->vals->protocol_id) {
|
||||
/* if requested single dialect ensure returned dialect matched */
|
||||
|
@ -3448,8 +3451,6 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
rqst.rq_nvec = 1;
|
||||
|
||||
rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
|
||||
rsp = (struct smb2_read_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc) {
|
||||
|
@ -3471,6 +3472,8 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
io_parms->tcon->tid, ses->Suid,
|
||||
io_parms->offset, io_parms->length);
|
||||
|
||||
cifs_small_buf_release(req);
|
||||
|
||||
*nbytes = le32_to_cpu(rsp->DataLength);
|
||||
if ((*nbytes > CIFS_MAX_MSGSIZE) ||
|
||||
(*nbytes > io_parms->length)) {
|
||||
|
@ -3769,7 +3772,6 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
|
||||
rc = cifs_send_recv(xid, io_parms->tcon->ses, &rqst,
|
||||
&resp_buftype, flags, &rsp_iov);
|
||||
cifs_small_buf_release(req);
|
||||
rsp = (struct smb2_write_rsp *)rsp_iov.iov_base;
|
||||
|
||||
if (rc) {
|
||||
|
@ -3787,6 +3789,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
|
|||
io_parms->offset, *nbytes);
|
||||
}
|
||||
|
||||
cifs_small_buf_release(req);
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче