diff options
Diffstat (limited to 'fs/smb/server/smb2pdu.c')
-rw-r--r-- | fs/smb/server/smb2pdu.c | 131 |
1 files changed, 82 insertions, 49 deletions
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 599118aed205..803b35b89513 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -67,8 +67,10 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id) return false; sess = ksmbd_session_lookup_all(conn, id); - if (sess) + if (sess) { + ksmbd_user_session_put(sess); return true; + } pr_err("Invalid user session id: %llu\n", id); return false; } @@ -551,7 +553,7 @@ int smb2_allocate_rsp_buf(struct ksmbd_work *work) if (le32_to_cpu(hdr->NextCommand) > 0) sz = large_sz; - work->response_buf = kvzalloc(sz, GFP_KERNEL); + work->response_buf = kvzalloc(sz, KSMBD_DEFAULT_GFP); if (!work->response_buf) return -ENOMEM; @@ -605,10 +607,8 @@ int smb2_check_user_session(struct ksmbd_work *work) /* Check for validity of user session */ work->sess = ksmbd_session_lookup_all(conn, sess_id); - if (work->sess) { - ksmbd_user_session_get(work->sess); + if (work->sess) return 1; - } ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id); return -ENOENT; } @@ -1147,7 +1147,7 @@ int smb2_handle_negotiate(struct ksmbd_work *work) case SMB311_PROT_ID: conn->preauth_info = kzalloc(sizeof(struct preauth_integrity_info), - GFP_KERNEL); + KSMBD_DEFAULT_GFP); if (!conn->preauth_info) { rc = -ENOMEM; rsp->hdr.Status = STATUS_INVALID_PARAMETER; @@ -1266,7 +1266,7 @@ static int alloc_preauth_hash(struct ksmbd_session *sess, return 0; sess->Preauth_HashValue = kmemdup(conn->preauth_info->Preauth_HashValue, - PREAUTH_HASHVALUE_SIZE, GFP_KERNEL); + PREAUTH_HASHVALUE_SIZE, KSMBD_DEFAULT_GFP); if (!sess->Preauth_HashValue) return -ENOMEM; @@ -1352,7 +1352,7 @@ static int ntlm_negotiate(struct ksmbd_work *work, sz = sizeof(struct challenge_message); sz += (strlen(ksmbd_netbios_name()) * 2 + 1 + 4) * 6; - neg_blob = kzalloc(sz, GFP_KERNEL); + neg_blob = kzalloc(sz, KSMBD_DEFAULT_GFP); if (!neg_blob) return -ENOMEM; @@ -1543,12 +1543,12 @@ binding_session: if (conn->dialect >= SMB30_PROT_ID) { chann = lookup_chann_list(sess, conn); if (!chann) { - chann = kmalloc(sizeof(struct channel), GFP_KERNEL); + chann = kmalloc(sizeof(struct channel), KSMBD_DEFAULT_GFP); if (!chann) return -ENOMEM; chann->conn = conn; - xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL); + xa_store(&sess->ksmbd_chann_list, (long)conn, chann, KSMBD_DEFAULT_GFP); } } @@ -1624,12 +1624,12 @@ static int krb5_authenticate(struct ksmbd_work *work, if (conn->dialect >= SMB30_PROT_ID) { chann = lookup_chann_list(sess, conn); if (!chann) { - chann = kmalloc(sizeof(struct channel), GFP_KERNEL); + chann = kmalloc(sizeof(struct channel), KSMBD_DEFAULT_GFP); if (!chann) return -ENOMEM; chann->conn = conn; - xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL); + xa_store(&sess->ksmbd_chann_list, (long)conn, chann, KSMBD_DEFAULT_GFP); } } @@ -1666,7 +1666,7 @@ int smb2_sess_setup(struct ksmbd_work *work) unsigned int negblob_len, negblob_off; int rc = 0; - ksmbd_debug(SMB, "Received request for session setup\n"); + ksmbd_debug(SMB, "Received smb2 session setup request\n"); WORK_BUFFERS(work, req, rsp); @@ -1701,29 +1701,35 @@ int smb2_sess_setup(struct ksmbd_work *work) if (conn->dialect != sess->dialect) { rc = -EINVAL; + ksmbd_user_session_put(sess); goto out_err; } if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) { rc = -EINVAL; + ksmbd_user_session_put(sess); goto out_err; } if (strncmp(conn->ClientGUID, sess->ClientGUID, SMB2_CLIENT_GUID_SIZE)) { rc = -ENOENT; + ksmbd_user_session_put(sess); goto out_err; } if (sess->state == SMB2_SESSION_IN_PROGRESS) { rc = -EACCES; + ksmbd_user_session_put(sess); goto out_err; } if (sess->state == SMB2_SESSION_EXPIRED) { rc = -EFAULT; + ksmbd_user_session_put(sess); goto out_err; } + ksmbd_user_session_put(sess); if (ksmbd_conn_need_reconnect(conn)) { rc = -EFAULT; @@ -1731,7 +1737,8 @@ int smb2_sess_setup(struct ksmbd_work *work) goto out_err; } - if (ksmbd_session_lookup(conn, sess_id)) { + sess = ksmbd_session_lookup(conn, sess_id); + if (!sess) { rc = -EACCES; goto out_err; } @@ -1742,7 +1749,6 @@ int smb2_sess_setup(struct ksmbd_work *work) } conn->binding = true; - ksmbd_user_session_get(sess); } else if ((conn->dialect < SMB30_PROT_ID || server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) && (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) { @@ -1769,7 +1775,6 @@ int smb2_sess_setup(struct ksmbd_work *work) } conn->binding = false; - ksmbd_user_session_get(sess); } work->sess = sess; @@ -1940,6 +1945,8 @@ int smb2_tree_connect(struct ksmbd_work *work) struct ksmbd_share_config *share = NULL; int rc = -EINVAL; + ksmbd_debug(SMB, "Received smb2 tree connect request\n"); + WORK_BUFFERS(work, req, rsp); treename = smb_strndup_from_utf16((char *)req + le16_to_cpu(req->PathOffset), @@ -2136,9 +2143,9 @@ int smb2_tree_disconnect(struct ksmbd_work *work) struct ksmbd_tree_connect *tcon = work->tcon; int err; - WORK_BUFFERS(work, req, rsp); + ksmbd_debug(SMB, "Received smb2 tree disconnect request\n"); - ksmbd_debug(SMB, "request\n"); + WORK_BUFFERS(work, req, rsp); if (!tcon) { ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); @@ -2195,15 +2202,15 @@ err_out: int smb2_session_logoff(struct ksmbd_work *work) { struct ksmbd_conn *conn = work->conn; + struct ksmbd_session *sess = work->sess; struct smb2_logoff_req *req; struct smb2_logoff_rsp *rsp; - struct ksmbd_session *sess; u64 sess_id; int err; WORK_BUFFERS(work, req, rsp); - ksmbd_debug(SMB, "request\n"); + ksmbd_debug(SMB, "Received smb2 session logoff request\n"); ksmbd_conn_lock(conn); if (!ksmbd_conn_good(conn)) { @@ -2219,11 +2226,6 @@ int smb2_session_logoff(struct ksmbd_work *work) ksmbd_close_session_fds(work); ksmbd_conn_wait_idle(conn); - /* - * Re-lookup session to validate if session is deleted - * while waiting request complete - */ - sess = ksmbd_session_lookup_all(conn, sess_id); if (ksmbd_tree_conn_session_logoff(sess)) { ksmbd_debug(SMB, "Invalid tid %d\n", req->hdr.Id.SyncId.TreeId); rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED; @@ -2346,7 +2348,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len, le16_to_cpu(eabuf->EaValueLength)) return -EINVAL; - attr_name = kmalloc(XATTR_NAME_MAX + 1, GFP_KERNEL); + attr_name = kmalloc(XATTR_NAME_MAX + 1, KSMBD_DEFAULT_GFP); if (!attr_name) return -ENOMEM; @@ -2849,6 +2851,8 @@ int smb2_open(struct ksmbd_work *work) __le32 daccess, maximal_access = 0; int iov_len = 0; + ksmbd_debug(SMB, "Received smb2 create request\n"); + WORK_BUFFERS(work, req, rsp); if (req->hdr.NextCommand && !work->next_smb2_rcv_hdr_off && @@ -2897,7 +2901,7 @@ int smb2_open(struct ksmbd_work *work) goto err_out2; } } else { - name = kstrdup("", GFP_KERNEL); + name = kstrdup("", KSMBD_DEFAULT_GFP); if (!name) { rc = -ENOMEM; goto err_out2; @@ -3338,7 +3342,7 @@ int smb2_open(struct ksmbd_work *work) sizeof(struct smb_sid) * 3 + sizeof(struct smb_acl) + sizeof(struct smb_ace) * ace_num * 2, - GFP_KERNEL); + KSMBD_DEFAULT_GFP); if (!pntsd) { posix_acl_release(fattr.cf_acls); posix_acl_release(fattr.cf_dacls); @@ -4224,6 +4228,7 @@ static bool __query_dir(struct dir_context *ctx, const char *name, int namlen, /* dot and dotdot entries are already reserved */ if (!strcmp(".", name) || !strcmp("..", name)) return true; + d_info->num_scan++; if (ksmbd_share_veto_filename(priv->work->tcon->share_conf, name)) return true; if (!match_pattern(name, namlen, priv->search_pattern)) @@ -4296,6 +4301,8 @@ int smb2_query_dir(struct ksmbd_work *work) int buffer_sz; struct smb2_query_dir_private query_dir_private = {NULL, }; + ksmbd_debug(SMB, "Received smb2 query directory request\n"); + WORK_BUFFERS(work, req, rsp); if (ksmbd_override_fsids(work)) { @@ -4384,9 +4391,18 @@ int smb2_query_dir(struct ksmbd_work *work) query_dir_private.info_level = req->FileInformationClass; dir_fp->readdir_data.private = &query_dir_private; set_ctx_actor(&dir_fp->readdir_data.ctx, __query_dir); - +again: + d_info.num_scan = 0; rc = iterate_dir(dir_fp->filp, &dir_fp->readdir_data.ctx); /* + * num_entry can be 0 if the directory iteration stops before reaching + * the end of the directory and no file is matched with the search + * pattern. + */ + if (rc >= 0 && !d_info.num_entry && d_info.num_scan && + d_info.out_buf_len > 0) + goto again; + /* * req->OutputBufferLength is too small to contain even one entry. * In this case, it immediately returns OutputBufferLength 0 to client. */ @@ -4946,7 +4962,7 @@ static int get_file_stream_info(struct ksmbd_work *work, /* plus : size */ streamlen += 1; - stream_buf = kmalloc(streamlen + 1, GFP_KERNEL); + stream_buf = kmalloc(streamlen + 1, KSMBD_DEFAULT_GFP); if (!stream_buf) break; @@ -5602,9 +5618,9 @@ int smb2_query_info(struct ksmbd_work *work) struct smb2_query_info_rsp *rsp; int rc = 0; - WORK_BUFFERS(work, req, rsp); + ksmbd_debug(SMB, "Received request smb2 query info request\n"); - ksmbd_debug(SMB, "GOT query info request\n"); + WORK_BUFFERS(work, req, rsp); if (ksmbd_override_fsids(work)) { rc = -ENOMEM; @@ -5709,6 +5725,8 @@ int smb2_close(struct ksmbd_work *work) u64 time; int err = 0; + ksmbd_debug(SMB, "Received smb2 close request\n"); + WORK_BUFFERS(work, req, rsp); if (test_share_config_flag(work->tcon->share_conf, @@ -5825,6 +5843,8 @@ int smb2_echo(struct ksmbd_work *work) { struct smb2_echo_rsp *rsp = smb2_get_msg(work->response_buf); + ksmbd_debug(SMB, "Received smb2 echo request\n"); + if (work->next_smb2_rcv_hdr_off) rsp = ksmbd_resp_buf_next(work); @@ -5921,7 +5941,7 @@ static int smb2_create_link(struct ksmbd_work *work, return -EINVAL; ksmbd_debug(SMB, "setting FILE_LINK_INFORMATION\n"); - pathname = kmalloc(PATH_MAX, GFP_KERNEL); + pathname = kmalloc(PATH_MAX, KSMBD_DEFAULT_GFP); if (!pathname) return -ENOMEM; @@ -6006,15 +6026,13 @@ static int set_file_basic_info(struct ksmbd_file *fp, attrs.ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); } - attrs.ia_valid |= ATTR_CTIME; if (file_info->ChangeTime) - attrs.ia_ctime = ksmbd_NTtimeToUnix(file_info->ChangeTime); - else - attrs.ia_ctime = inode_get_ctime(inode); + inode_set_ctime_to_ts(inode, + ksmbd_NTtimeToUnix(file_info->ChangeTime)); if (file_info->LastWriteTime) { attrs.ia_mtime = ksmbd_NTtimeToUnix(file_info->LastWriteTime); - attrs.ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); + attrs.ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET | ATTR_CTIME); } if (file_info->Attributes) { @@ -6056,8 +6074,6 @@ static int set_file_basic_info(struct ksmbd_file *fp, return -EACCES; inode_lock(inode); - inode_set_ctime_to_ts(inode, attrs.ia_ctime); - attrs.ia_valid &= ~ATTR_CTIME; rc = notify_change(idmap, dentry, &attrs, NULL); inode_unlock(inode); } @@ -6365,7 +6381,7 @@ int smb2_set_info(struct ksmbd_work *work) int rc = 0; unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; - ksmbd_debug(SMB, "Received set info request\n"); + ksmbd_debug(SMB, "Received smb2 set info request\n"); if (work->next_smb2_rcv_hdr_off) { req = ksmbd_req_buf_next(work); @@ -6485,7 +6501,7 @@ static noinline int smb2_read_pipe(struct ksmbd_work *work) } aux_payload_buf = - kvmalloc(rpc_resp->payload_sz, GFP_KERNEL); + kvmalloc(rpc_resp->payload_sz, KSMBD_DEFAULT_GFP); if (!aux_payload_buf) { err = -ENOMEM; goto out; @@ -6591,6 +6607,8 @@ int smb2_read(struct ksmbd_work *work) unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID; void *aux_payload_buf; + ksmbd_debug(SMB, "Received smb2 read request\n"); + if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) { ksmbd_debug(SMB, "IPC pipe read request\n"); @@ -6651,6 +6669,10 @@ int smb2_read(struct ksmbd_work *work) } offset = le64_to_cpu(req->Offset); + if (offset < 0) { + err = -EINVAL; + goto out; + } length = le32_to_cpu(req->Length); mincount = le32_to_cpu(req->MinimumCount); @@ -6664,7 +6686,7 @@ int smb2_read(struct ksmbd_work *work) ksmbd_debug(SMB, "filename %pD, offset %lld, len %zu\n", fp->filp, offset, length); - aux_payload_buf = kvzalloc(length, GFP_KERNEL); + aux_payload_buf = kvzalloc(ALIGN(length, 8), KSMBD_DEFAULT_GFP); if (!aux_payload_buf) { err = -ENOMEM; goto out; @@ -6816,7 +6838,7 @@ static ssize_t smb2_write_rdma_channel(struct ksmbd_work *work, int ret; ssize_t nbytes; - data_buf = kvzalloc(length, GFP_KERNEL); + data_buf = kvzalloc(length, KSMBD_DEFAULT_GFP); if (!data_buf) return -ENOMEM; @@ -6856,6 +6878,8 @@ int smb2_write(struct ksmbd_work *work) int err = 0; unsigned int max_write_size = work->conn->vals->max_write_size; + ksmbd_debug(SMB, "Received smb2 write request\n"); + WORK_BUFFERS(work, req, rsp); if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) { @@ -6864,6 +6888,8 @@ int smb2_write(struct ksmbd_work *work) } offset = le64_to_cpu(req->Offset); + if (offset < 0) + return -EINVAL; length = le32_to_cpu(req->Length); if (req->Channel == SMB2_CHANNEL_RDMA_V1 || @@ -6994,7 +7020,7 @@ int smb2_flush(struct ksmbd_work *work) WORK_BUFFERS(work, req, rsp); - ksmbd_debug(SMB, "SMB2_FLUSH called for fid %llu\n", req->VolatileFileId); + ksmbd_debug(SMB, "Received smb2 flush request(fid : %llu)\n", req->VolatileFileId); err = ksmbd_vfs_fsync(work, req->VolatileFileId, req->PersistentFileId); if (err) @@ -7145,7 +7171,7 @@ static struct ksmbd_lock *smb2_lock_init(struct file_lock *flock, { struct ksmbd_lock *lock; - lock = kzalloc(sizeof(struct ksmbd_lock), GFP_KERNEL); + lock = kzalloc(sizeof(struct ksmbd_lock), KSMBD_DEFAULT_GFP); if (!lock) return NULL; @@ -7206,7 +7232,7 @@ int smb2_lock(struct ksmbd_work *work) WORK_BUFFERS(work, req, rsp); - ksmbd_debug(SMB, "Received lock request\n"); + ksmbd_debug(SMB, "Received smb2 lock request\n"); fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId); if (!fp) { ksmbd_debug(SMB, "Invalid file id for lock : %llu\n", req->VolatileFileId); @@ -7413,7 +7439,7 @@ skip: "would have to wait for getting lock\n"); list_add(&smb_lock->llist, &rollback_list); - argv = kmalloc(sizeof(void *), GFP_KERNEL); + argv = kmalloc(sizeof(void *), KSMBD_DEFAULT_GFP); if (!argv) { err = -ENOMEM; goto out; @@ -7973,6 +7999,8 @@ int smb2_ioctl(struct ksmbd_work *work) int ret = 0; char *buffer; + ksmbd_debug(SMB, "Received smb2 ioctl request\n"); + if (work->next_smb2_rcv_hdr_off) { req = ksmbd_req_buf_next(work); rsp = ksmbd_resp_buf_next(work); @@ -8599,6 +8627,8 @@ int smb2_oplock_break(struct ksmbd_work *work) struct smb2_oplock_break *req; struct smb2_oplock_break *rsp; + ksmbd_debug(SMB, "Received smb2 oplock break acknowledgment request\n"); + WORK_BUFFERS(work, req, rsp); switch (le16_to_cpu(req->StructureSize)) { @@ -8629,6 +8659,8 @@ int smb2_notify(struct ksmbd_work *work) struct smb2_change_notify_req *req; struct smb2_change_notify_rsp *rsp; + ksmbd_debug(SMB, "Received smb2 notify\n"); + WORK_BUFFERS(work, req, rsp); if (work->next_smb2_rcv_hdr_off && req->hdr.NextCommand) { @@ -8907,7 +8939,7 @@ int smb3_encrypt_resp(struct ksmbd_work *work) int rc = -ENOMEM; void *tr_buf; - tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, GFP_KERNEL); + tr_buf = kzalloc(sizeof(struct smb2_transform_hdr) + 4, KSMBD_DEFAULT_GFP); if (!tr_buf) return rc; @@ -8956,6 +8988,7 @@ int smb3_decrypt_req(struct ksmbd_work *work) le64_to_cpu(tr_hdr->SessionId)); return -ECONNABORTED; } + ksmbd_user_session_put(sess); iov[0].iov_base = buf; iov[0].iov_len = sizeof(struct smb2_transform_hdr) + 4; |