Three ksmbd server fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmkBPXkACgkQiiy9cAdy
 T1G/0QwAsO9KD52S8NFvrkZe6kdDy5uE+U74FMwPzVRSP4nHvf2jit5THokwGC01
 BEByI+XfVi8+2ckxcijdA2gZQUv63sTFBdh1doC1Qn5txO8VxS/+eD1pdrCDKDvg
 p0zmDUqyMvxqIg2GPjErA8zEUYXOkBtmJLM9FAyvoAt/iqJp2PBtoWidmCB6VTQZ
 E+B6tpIJmcVM8pZmktoNm6Y5wT+FZVdT6lbQGOW81DXKCkibfvh4m/yuZj87zB1Z
 L/Fyo0z3XlErwnjAn9ghFkTQAfswjQXo7CnJCXFIzf44kQCZ8iL8NcW02MPpXDyK
 UbyEVZM9eB93SbAHGqo2H6CjrYdjdnJCcaCFjopEmpjX+R9yWJTpS6dTKLslZlBe
 xEFl1mX4cDEvWdvMZNxV0+hGGefWzyTA40SSMFjdPdLBJUZ+Gv9qwVHmd6dU0RSv
 /tzSkiEBqKVHcvIoU6pOiSyxgEYExuTlkrkJk6Oax+vJ7V+PkUgx3nbGre2tXllJ
 e9Gf2/VW
 =w5Wf
 -----END PGP SIGNATURE-----

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:
Linus Torvalds 2025-10-28 18:00:40 -07:00
commit e53642b87a
2 changed files with 43 additions and 12 deletions

View File

@ -263,10 +263,16 @@ static void ipc_msg_handle_free(int handle)
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;
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();
down_read(&ipc_msg_table_lock);
hash_for_each_possible(ipc_msg_table, entry, ipc_table_hlist, handle) {

View File

@ -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;
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);
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_work_sync(&sc->idle.immediate_work);
if (sc->rdma.cm_id)
rdma_lock_handler(sc->rdma.cm_id);
if (sc->ib.qp) {
ib_drain_qp(sc->ib.qp);
sc->ib.qp = NULL;
@ -497,8 +497,10 @@ static void free_transport(struct smb_direct_transport *t)
ib_free_cq(sc->ib.recv_cq);
if (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);
}
smb_direct_destroy_pools(sc);
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_DISCONNECTED: {
ib_drain_qp(sc->ib.qp);
sc->status = SMBDIRECT_SOCKET_DISCONNECTED;
smb_direct_disconnect_rdma_work(&sc->disconnect_work);
if (sc->ib.qp)
ib_drain_qp(sc->ib.qp);
break;
}
case RDMA_CM_EVENT_CONNECT_ERROR: {
@ -1904,7 +1906,6 @@ static int smb_direct_prepare_negotiation(struct smbdirect_socket *sc)
goto out_err;
}
smb_direct_post_recv_credits(&sc->recv_io.posted.refill_work);
return 0;
out_err:
put_recvmsg(sc, recvmsg);
@ -2249,8 +2250,8 @@ static int smb_direct_prepare(struct ksmbd_transport *t)
return -ECONNABORTED;
ret = smb_direct_check_recvmsg(recvmsg);
if (ret == -ECONNABORTED)
goto out;
if (ret)
goto put;
req = (struct smbdirect_negotiate_req *)recvmsg->packet;
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 = max_t(u16, sc->recv_io.credits.target, 1);
ret = smb_direct_send_negotiate_response(sc, ret);
out:
put:
spin_lock_irqsave(&sc->recv_io.reassembly.lock, flags);
sc->recv_io.reassembly.queue_length--;
list_del(&recvmsg->list);
spin_unlock_irqrestore(&sc->recv_io.reassembly.lock, flags);
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;
}