mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
Merge tag 'v6.18-rc3-smb-server-fixes' of git://git.samba.org/ksmbd
Pull smb server fixes from Steve French: - Improve check for malformed payload - Fix free transport smbdirect potential race - Fix potential race in credit allocation during smbdirect negotiation * tag 'v6.18-rc3-smb-server-fixes' of git://git.samba.org/ksmbd: smb: server: let smb_direct_cm_handler() call ib_drain_qp() after smb_direct_disconnect_rdma_work() smb: server: call smb_direct_post_recv_credits() when the negotiation is done ksmbd: transport_ipc: validate payload size before reading handle
This commit is contained in:
@@ -263,10 +263,16 @@ static void ipc_msg_handle_free(int handle)
|
|||||||
|
|
||||||
static int handle_response(int type, void *payload, size_t sz)
|
static int handle_response(int type, void *payload, size_t sz)
|
||||||
{
|
{
|
||||||
unsigned int handle = *(unsigned int *)payload;
|
unsigned int handle;
|
||||||
struct ipc_msg_table_entry *entry;
|
struct ipc_msg_table_entry *entry;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
/* Prevent 4-byte read beyond declared payload size */
|
||||||
|
if (sz < sizeof(unsigned int))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
handle = *(unsigned int *)payload;
|
||||||
|
|
||||||
ipc_update_last_active();
|
ipc_update_last_active();
|
||||||
down_read(&ipc_msg_table_lock);
|
down_read(&ipc_msg_table_lock);
|
||||||
hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) {
|
hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) {
|
||||||
|
|||||||
@@ -418,9 +418,6 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id)
|
|||||||
|
|
||||||
sc->ib.dev = sc->rdma.cm_id->device;
|
sc->ib.dev = sc->rdma.cm_id->device;
|
||||||
|
|
||||||
INIT_WORK(&sc->recv_io.posted.refill_work,
|
|
||||||
smb_direct_post_recv_credits);
|
|
||||||
INIT_WORK(&sc->idle.immediate_work, smb_direct_send_immediate_work);
|
|
||||||
INIT_DELAYED_WORK(&sc->idle.timer_work, smb_direct_idle_connection_timer);
|
INIT_DELAYED_WORK(&sc->idle.timer_work, smb_direct_idle_connection_timer);
|
||||||
|
|
||||||
conn = ksmbd_conn_alloc();
|
conn = ksmbd_conn_alloc();
|
||||||
@@ -469,6 +466,9 @@ static void free_transport(struct smb_direct_transport *t)
|
|||||||
disable_delayed_work_sync(&sc->idle.timer_work);
|
disable_delayed_work_sync(&sc->idle.timer_work);
|
||||||
disable_work_sync(&sc->idle.immediate_work);
|
disable_work_sync(&sc->idle.immediate_work);
|
||||||
|
|
||||||
|
if (sc->rdma.cm_id)
|
||||||
|
rdma_lock_handler(sc->rdma.cm_id);
|
||||||
|
|
||||||
if (sc->ib.qp) {
|
if (sc->ib.qp) {
|
||||||
ib_drain_qp(sc->ib.qp);
|
ib_drain_qp(sc->ib.qp);
|
||||||
sc->ib.qp = NULL;
|
sc->ib.qp = NULL;
|
||||||
@@ -497,8 +497,10 @@ static void free_transport(struct smb_direct_transport *t)
|
|||||||
ib_free_cq(sc->ib.recv_cq);
|
ib_free_cq(sc->ib.recv_cq);
|
||||||
if (sc->ib.pd)
|
if (sc->ib.pd)
|
||||||
ib_dealloc_pd(sc->ib.pd);
|
ib_dealloc_pd(sc->ib.pd);
|
||||||
if (sc->rdma.cm_id)
|
if (sc->rdma.cm_id) {
|
||||||
|
rdma_unlock_handler(sc->rdma.cm_id);
|
||||||
rdma_destroy_id(sc->rdma.cm_id);
|
rdma_destroy_id(sc->rdma.cm_id);
|
||||||
|
}
|
||||||
|
|
||||||
smb_direct_destroy_pools(sc);
|
smb_direct_destroy_pools(sc);
|
||||||
ksmbd_conn_free(KSMBD_TRANS(t)->conn);
|
ksmbd_conn_free(KSMBD_TRANS(t)->conn);
|
||||||
@@ -1727,10 +1729,10 @@ static int smb_direct_cm_handler(struct rdma_cm_id *cm_id,
|
|||||||
}
|
}
|
||||||
case RDMA_CM_EVENT_DEVICE_REMOVAL:
|
case RDMA_CM_EVENT_DEVICE_REMOVAL:
|
||||||
case RDMA_CM_EVENT_DISCONNECTED: {
|
case RDMA_CM_EVENT_DISCONNECTED: {
|
||||||
ib_drain_qp(sc->ib.qp);
|
|
||||||
|
|
||||||
sc->status = SMBDIRECT_SOCKET_DISCONNECTED;
|
sc->status = SMBDIRECT_SOCKET_DISCONNECTED;
|
||||||
smb_direct_disconnect_rdma_work(&sc->disconnect_work);
|
smb_direct_disconnect_rdma_work(&sc->disconnect_work);
|
||||||
|
if (sc->ib.qp)
|
||||||
|
ib_drain_qp(sc->ib.qp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RDMA_CM_EVENT_CONNECT_ERROR: {
|
case RDMA_CM_EVENT_CONNECT_ERROR: {
|
||||||
@@ -1904,7 +1906,6 @@ static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc)
|
|||||||
goto out_err;
|
goto out_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
smb_direct_post_recv_credits(&sc->recv_io.posted.refill_work);
|
|
||||||
return 0;
|
return 0;
|
||||||
out_err:
|
out_err:
|
||||||
put_recvmsg(sc, recvmsg);
|
put_recvmsg(sc, recvmsg);
|
||||||
@@ -2249,8 +2250,8 @@ static int smb_direct_prepare(struct ksmbd_transport *t)
|
|||||||
return -ECONNABORTED;
|
return -ECONNABORTED;
|
||||||
|
|
||||||
ret = smb_direct_check_recvmsg(recvmsg);
|
ret = smb_direct_check_recvmsg(recvmsg);
|
||||||
if (ret == -ECONNABORTED)
|
if (ret)
|
||||||
goto out;
|
goto put;
|
||||||
|
|
||||||
req = (struct smbdirect_negotiate_req *)recvmsg->packet;
|
req = (struct smbdirect_negotiate_req *)recvmsg->packet;
|
||||||
sp->max_recv_size = min_t(int, sp->max_recv_size,
|
sp->max_recv_size = min_t(int, sp->max_recv_size,
|
||||||
@@ -2265,14 +2266,38 @@ static int smb_direct_prepare(struct ksmbd_transport *t)
|
|||||||
sc->recv_io.credits.target = min_t(u16, sc->recv_io.credits.target, sp->recv_credit_max);
|
sc->recv_io.credits.target = min_t(u16, sc->recv_io.credits.target, sp->recv_credit_max);
|
||||||
sc->recv_io.credits.target = max_t(u16, sc->recv_io.credits.target, 1);
|
sc->recv_io.credits.target = max_t(u16, sc->recv_io.credits.target, 1);
|
||||||
|
|
||||||
ret = smb_direct_send_negotiate_response(sc, ret);
|
put:
|
||||||
out:
|
|
||||||
spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags);
|
spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags);
|
||||||
sc->recv_io.reassembly.queue_length--;
|
sc->recv_io.reassembly.queue_length--;
|
||||||
list_del(&recvmsg->list);
|
list_del(&recvmsg->list);
|
||||||
spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags);
|
spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags);
|
||||||
put_recvmsg(sc, recvmsg);
|
put_recvmsg(sc, recvmsg);
|
||||||
|
|
||||||
|
if (ret == -ECONNABORTED)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
goto respond;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We negotiated with success, so we need to refill the recv queue.
|
||||||
|
* We do that with sc->idle.immediate_work still being disabled
|
||||||
|
* via smbdirect_socket_init(), so that queue_work(sc->workqueue,
|
||||||
|
* &sc->idle.immediate_work) in smb_direct_post_recv_credits()
|
||||||
|
* is a no-op.
|
||||||
|
*
|
||||||
|
* The message that grants the credits to the client is
|
||||||
|
* the negotiate response.
|
||||||
|
*/
|
||||||
|
INIT_WORK(&sc->recv_io.posted.refill_work, smb_direct_post_recv_credits);
|
||||||
|
smb_direct_post_recv_credits(&sc->recv_io.posted.refill_work);
|
||||||
|
if (unlikely(sc->first_error))
|
||||||
|
return sc->first_error;
|
||||||
|
INIT_WORK(&sc->idle.immediate_work, smb_direct_send_immediate_work);
|
||||||
|
|
||||||
|
respond:
|
||||||
|
ret = smb_direct_send_negotiate_response(sc, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user