mirror of
https://github.com/torvalds/linux.git
synced 2026-10-09 20:09:02 +02:00
ksmbd: fix durable V2 persistent handle handling
Correct the durable-handle V2 response context layout and use the V2 context size when chaining a following CREATE response context. Validate the only defined DH2Q/DH2C flag, require the reconnect request type to match the saved open type, and process the application instance identifier before durable V2 state. Persistent opens are durable opens as required by MS-SMB2. Permit the durable reconnect path to rebind either type of disconnected open. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
bc2f3f3dd6
commit
d6bf101da7
|
|
@ -2068,12 +2068,12 @@ void create_durable_v2_rsp_buf(char *cc, struct ksmbd_file *fp)
|
|||
struct create_durable_rsp_v2 *buf;
|
||||
|
||||
buf = (struct create_durable_rsp_v2 *)cc;
|
||||
memset(buf, 0, sizeof(struct create_durable_rsp));
|
||||
memset(buf, 0, sizeof(*buf));
|
||||
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
||||
(struct create_durable_rsp, Data));
|
||||
(struct create_durable_rsp_v2, dcontext));
|
||||
buf->ccontext.DataLength = cpu_to_le32(8);
|
||||
buf->ccontext.NameOffset = cpu_to_le16(offsetof
|
||||
(struct create_durable_rsp, Name));
|
||||
(struct create_durable_rsp_v2, Name));
|
||||
buf->ccontext.NameLength = cpu_to_le16(4);
|
||||
/* SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 is "DH2Q" */
|
||||
buf->Name[0] = 'D';
|
||||
|
|
|
|||
|
|
@ -3430,6 +3430,7 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
|
|||
case DURABLE_RECONN_V2:
|
||||
{
|
||||
struct create_durable_handle_reconnect_v2 *recon_v2;
|
||||
u32 flags;
|
||||
|
||||
if (dh_info->type == DURABLE_RECONN ||
|
||||
dh_info->type == DURABLE_REQ_V2) {
|
||||
|
|
@ -3444,6 +3445,12 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
|
|||
}
|
||||
|
||||
recon_v2 = (struct create_durable_handle_reconnect_v2 *)context;
|
||||
flags = le32_to_cpu(recon_v2->dcontext.Flags);
|
||||
if (flags & ~SMB2_DHANDLE_FLAG_PERSISTENT) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
dh_info->persistent = flags & SMB2_DHANDLE_FLAG_PERSISTENT;
|
||||
persistent_id = recon_v2->dcontext.Fid.PersistentFileId;
|
||||
dh_info->fp = ksmbd_lookup_durable_fd(persistent_id);
|
||||
if (!dh_info->fp) {
|
||||
|
|
@ -3466,6 +3473,13 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* A persistent reconnect must match the original open type. */
|
||||
if (dh_info->fp->is_persistent != dh_info->persistent) {
|
||||
err = dh_info->persistent ? -EINVAL : -EBADF;
|
||||
ksmbd_put_durable_fd(dh_info->fp);
|
||||
goto out;
|
||||
}
|
||||
|
||||
dh_info->type = dh_idx;
|
||||
dh_info->reconnected = true;
|
||||
ksmbd_debug(SMB,
|
||||
|
|
@ -3529,6 +3543,11 @@ static int parse_durable_handle_context(struct ksmbd_work *work,
|
|||
|
||||
durable_v2_blob =
|
||||
(struct create_durable_req_v2 *)context;
|
||||
if (le32_to_cpu(durable_v2_blob->dcontext.Flags) &
|
||||
~SMB2_DHANDLE_FLAG_PERSISTENT) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ksmbd_debug(SMB, "Request for durable v2 open\n");
|
||||
dh_info->CreateGuid = durable_v2_blob->dcontext.CreateGuid;
|
||||
dh_info->persistent =
|
||||
|
|
@ -3812,14 +3831,14 @@ int smb2_open(struct ksmbd_work *work)
|
|||
if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
|
||||
req_op_level = SMB2_OPLOCK_LEVEL_NONE;
|
||||
}
|
||||
rc = parse_app_instance_id(req, &dh_info);
|
||||
if (rc)
|
||||
goto err_out2;
|
||||
rc = parse_durable_handle_context(work, req, lc, &dh_info);
|
||||
if (rc) {
|
||||
ksmbd_debug(SMB, "error parsing durable handle context\n");
|
||||
goto err_out2;
|
||||
}
|
||||
rc = parse_app_instance_id(req, &dh_info);
|
||||
if (rc)
|
||||
goto err_out2;
|
||||
|
||||
if (dh_info.replay == true) {
|
||||
fp = dh_info.fp;
|
||||
|
|
@ -4594,10 +4613,15 @@ int smb2_open(struct ksmbd_work *work)
|
|||
if (dh_info.type == DURABLE_REQ_V2 || dh_info.type == DURABLE_REQ) {
|
||||
if (dh_info.type == DURABLE_REQ_V2 && dh_info.persistent &&
|
||||
test_share_config_flag(work->tcon->share_conf,
|
||||
KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY))
|
||||
fp->is_persistent = true;
|
||||
else
|
||||
KSMBD_SHARE_FLAG_CONTINUOUS_AVAILABILITY) &&
|
||||
(conn->vals->req_capabilities &
|
||||
SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)) {
|
||||
/* MS-SMB2 3.3.5.9.10: a persistent open is durable too. */
|
||||
fp->is_durable = true;
|
||||
fp->is_persistent = true;
|
||||
} else {
|
||||
fp->is_durable = true;
|
||||
}
|
||||
if (dh_info.type == DURABLE_REQ_V2) {
|
||||
if (dh_info.app_instance_id)
|
||||
memcpy(fp->app_instance_id,
|
||||
|
|
@ -4760,7 +4784,9 @@ int smb2_open(struct ksmbd_work *work)
|
|||
if (next_ptr)
|
||||
*next_ptr = cpu_to_le32(next_off);
|
||||
next_ptr = &durable_ccontext->Next;
|
||||
next_off = conn->vals->create_durable_size;
|
||||
next_off = dh_info.type == DURABLE_REQ ?
|
||||
conn->vals->create_durable_size :
|
||||
conn->vals->create_durable_v2_size;
|
||||
}
|
||||
|
||||
if (posix_ctxt) {
|
||||
|
|
|
|||
|
|
@ -1845,7 +1845,7 @@ int ksmbd_reopen_durable_fd(struct ksmbd_work *work, struct ksmbd_file *fp)
|
|||
unsigned int old_f_state;
|
||||
|
||||
write_lock(&global_ft.lock);
|
||||
if (!fp->is_durable || fp->conn || fp->tcon) {
|
||||
if ((!fp->is_durable && !fp->is_persistent) || fp->conn || fp->tcon) {
|
||||
write_unlock(&global_ft.lock);
|
||||
pr_err("Invalid durable fd [%p:%p]\n", fp->conn, fp->tcon);
|
||||
return -EBADF;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user