Commit 05de41f3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.18-rc1-smb-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix RPC hang due to locking bug

 - Fix for memory leak in read and refcount leak (in session setup)

 - Minor cleanup

* tag 'v6.18-rc1-smb-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: fix recursive locking in RPC handle list access
  smb/server: fix possible refcount leak in smb2_sess_setup()
  smb/server: fix possible memory leak in smb2_read()
  smb: server: Use common error handling code in smb_direct_rdma_xmit()
parents 634ec1fc 88f17081
Loading
Loading
Loading
Loading
+2 −5
Original line number Diff line number Diff line
@@ -147,14 +147,11 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
{
	struct ksmbd_session_rpc *entry;
	int method;

	down_read(&sess->rpc_lock);
	lockdep_assert_held(&sess->rpc_lock);
	entry = xa_load(&sess->rpc_handle_list, id);
	method = entry ? entry->method : 0;
	up_read(&sess->rpc_lock);

	return method;
	return entry ? entry->method : 0;
}

void ksmbd_session_destroy(struct ksmbd_session *sess)
+10 −1
Original line number Diff line number Diff line
@@ -1806,6 +1806,7 @@ int smb2_sess_setup(struct ksmbd_work *work)

		if (ksmbd_conn_need_reconnect(conn)) {
			rc = -EFAULT;
			ksmbd_user_session_put(sess);
			sess = NULL;
			goto out_err;
		}
@@ -4625,8 +4626,15 @@ static int smb2_get_info_file_pipe(struct ksmbd_session *sess,
	 * pipe without opening it, checking error condition here
	 */
	id = req->VolatileFileId;
	if (!ksmbd_session_rpc_method(sess, id))

	lockdep_assert_not_held(&sess->rpc_lock);

	down_read(&sess->rpc_lock);
	if (!ksmbd_session_rpc_method(sess, id)) {
		up_read(&sess->rpc_lock);
		return -ENOENT;
	}
	up_read(&sess->rpc_lock);

	ksmbd_debug(SMB, "FileInfoClass %u, FileId 0x%llx\n",
		    req->FileInfoClass, req->VolatileFileId);
@@ -6824,6 +6832,7 @@ int smb2_read(struct ksmbd_work *work)

	nbytes = ksmbd_vfs_read(work, fp, length, &offset, aux_payload_buf);
	if (nbytes < 0) {
		kvfree(aux_payload_buf);
		err = nbytes;
		goto out;
	}
+12 −0
Original line number Diff line number Diff line
@@ -825,6 +825,9 @@ struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle
	if (!msg)
		return NULL;

	lockdep_assert_not_held(&sess->rpc_lock);

	down_read(&sess->rpc_lock);
	msg->type = KSMBD_EVENT_RPC_REQUEST;
	req = (struct ksmbd_rpc_command *)msg->payload;
	req->handle = handle;
@@ -833,6 +836,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_write(struct ksmbd_session *sess, int handle
	req->flags |= KSMBD_RPC_WRITE_METHOD;
	req->payload_sz = payload_sz;
	memcpy(req->payload, payload, payload_sz);
	up_read(&sess->rpc_lock);

	resp = ipc_msg_send_request(msg, req->handle);
	ipc_msg_free(msg);
@@ -849,6 +853,9 @@ struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle)
	if (!msg)
		return NULL;

	lockdep_assert_not_held(&sess->rpc_lock);

	down_read(&sess->rpc_lock);
	msg->type = KSMBD_EVENT_RPC_REQUEST;
	req = (struct ksmbd_rpc_command *)msg->payload;
	req->handle = handle;
@@ -856,6 +863,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_read(struct ksmbd_session *sess, int handle)
	req->flags |= rpc_context_flags(sess);
	req->flags |= KSMBD_RPC_READ_METHOD;
	req->payload_sz = 0;
	up_read(&sess->rpc_lock);

	resp = ipc_msg_send_request(msg, req->handle);
	ipc_msg_free(msg);
@@ -876,6 +884,9 @@ struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle
	if (!msg)
		return NULL;

	lockdep_assert_not_held(&sess->rpc_lock);

	down_read(&sess->rpc_lock);
	msg->type = KSMBD_EVENT_RPC_REQUEST;
	req = (struct ksmbd_rpc_command *)msg->payload;
	req->handle = handle;
@@ -884,6 +895,7 @@ struct ksmbd_rpc_command *ksmbd_rpc_ioctl(struct ksmbd_session *sess, int handle
	req->flags |= KSMBD_RPC_IOCTL_METHOD;
	req->payload_sz = payload_sz;
	memcpy(req->payload, payload, payload_sz);
	up_read(&sess->rpc_lock);

	resp = ipc_msg_send_request(msg, req->handle);
	ipc_msg_free(msg);
+10 −10
Original line number Diff line number Diff line
@@ -1574,18 +1574,14 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,
					     get_buf_page_count(desc_buf, desc_buf_len),
					     msg->sg_list, SG_CHUNK_SIZE);
		if (ret) {
			kfree(msg);
			ret = -ENOMEM;
			goto out;
			goto free_msg;
		}

		ret = get_sg_list(desc_buf, desc_buf_len,
				  msg->sgt.sgl, msg->sgt.orig_nents);
		if (ret < 0) {
			sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE);
			kfree(msg);
			goto out;
		}
		if (ret < 0)
			goto free_table;

		ret = rdma_rw_ctx_init(&msg->rdma_ctx, sc->ib.qp, sc->ib.qp->port,
				       msg->sgt.sgl,
@@ -1596,9 +1592,7 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,
				       is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
		if (ret < 0) {
			pr_err("failed to init rdma_rw_ctx: %d\n", ret);
			sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE);
			kfree(msg);
			goto out;
			goto free_table;
		}

		list_add_tail(&msg->list, &msg_list);
@@ -1630,6 +1624,12 @@ static int smb_direct_rdma_xmit(struct smb_direct_transport *t,
	atomic_add(credits_needed, &sc->rw_io.credits.count);
	wake_up(&sc->rw_io.credits.wait_queue);
	return ret;

free_table:
	sg_free_table_chained(&msg->sgt, SG_CHUNK_SIZE);
free_msg:
	kfree(msg);
	goto out;
}

static int smb_direct_rdma_write(struct ksmbd_transport *t,