mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 22:14:03 +02:00
RDMA/srp: fix heap information leak on a truncated SRP_CRED_REQ
srp_recv_done() passes wc->byte_len to srp_process_rsp(). It passes
nothing to srp_process_cred_req() and srp_process_aer_req(), which read
fixed-size fields from the receive buffer without checking that those
fields were received.
The buffer size is max_ti_iu_len, which comes from the login response
and is not validated. A target that advertises 8 and then sends an
8-byte SRP_CRED_REQ makes the initiator read req->tag from beyond the
end of the buffer. req->tag is copied into the SRP_CRED_RSP and sent
back, so those bytes reach the target. SRP_AER_REQ behaves the same way
and also reads req->lun.
The leak is 8 bytes per response. max_ti_iu_len also decides which slab
cache the buffer comes from. With 8 the buffer is a kmalloc-8 object and
the read is entirely outside it:
BUG: KASAN: slab-out-of-bounds in srp_recv_done+0x172b/0x1aa0
Read of size 8 at addr ffff888104714da8 by task kworker/u8:3/50
which belongs to the cache kmalloc-8 of size 8
The buggy address is located 0 bytes to the right of
allocated 8-byte region [ffff888104714da0, ffff888104714da8)
Without KASAN the returned bytes are whatever is next in the slab. One
run returned ".strtab".
rsp->data[3] in srp_process_rsp() has the same problem: only
resp_data_len is checked before it is read.
Drop a request that is shorter than the structure being parsed, and
check byte_len before the tsk_mgmt read.
Fixes: bb12588a38 ("IB/srp: Implement SRP_CRED_REQ and SRP_AER_REQ")
Signed-off-by: Yehyeong Lee <yhlee@isslab.korea.ac.kr>
Link: https://patch.msgid.link/20260729093203.1503201-1-yhlee@isslab.korea.ac.kr
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Leon Romanovsky <leon@kernel.org>
This commit is contained in:
parent
a52eeff320
commit
961ac0f0c5
|
|
@ -1945,7 +1945,8 @@ static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp,
|
|||
ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
|
||||
if (rsp->tag == ch->tsk_mgmt_tag) {
|
||||
ch->tsk_mgmt_status = -1;
|
||||
if (be32_to_cpu(rsp->resp_data_len) >= 4)
|
||||
if (be32_to_cpu(rsp->resp_data_len) >= 4 &&
|
||||
byte_len >= sizeof(*rsp) + 4)
|
||||
ch->tsk_mgmt_status = rsp->data[3];
|
||||
complete(&ch->tsk_mgmt_done);
|
||||
} else {
|
||||
|
|
@ -2045,13 +2046,20 @@ static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta,
|
|||
}
|
||||
|
||||
static void srp_process_cred_req(struct srp_rdma_ch *ch,
|
||||
struct srp_cred_req *req)
|
||||
struct srp_cred_req *req, u32 byte_len)
|
||||
{
|
||||
struct srp_cred_rsp rsp = {
|
||||
.opcode = SRP_CRED_RSP,
|
||||
.tag = req->tag,
|
||||
};
|
||||
s32 delta = be32_to_cpu(req->req_lim_delta);
|
||||
struct srp_cred_rsp rsp = { .opcode = SRP_CRED_RSP };
|
||||
s32 delta;
|
||||
|
||||
if (byte_len < sizeof(*req)) {
|
||||
shost_printk(KERN_ERR, ch->target->scsi_host, PFX
|
||||
"dropping truncated SRP_CRED_REQ (%u bytes received, %zu expected)\n",
|
||||
byte_len, sizeof(*req));
|
||||
return;
|
||||
}
|
||||
|
||||
rsp.tag = req->tag;
|
||||
delta = be32_to_cpu(req->req_lim_delta);
|
||||
|
||||
if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
|
||||
shost_printk(KERN_ERR, ch->target->scsi_host, PFX
|
||||
|
|
@ -2059,14 +2067,21 @@ static void srp_process_cred_req(struct srp_rdma_ch *ch,
|
|||
}
|
||||
|
||||
static void srp_process_aer_req(struct srp_rdma_ch *ch,
|
||||
struct srp_aer_req *req)
|
||||
struct srp_aer_req *req, u32 byte_len)
|
||||
{
|
||||
struct srp_target_port *target = ch->target;
|
||||
struct srp_aer_rsp rsp = {
|
||||
.opcode = SRP_AER_RSP,
|
||||
.tag = req->tag,
|
||||
};
|
||||
s32 delta = be32_to_cpu(req->req_lim_delta);
|
||||
struct srp_aer_rsp rsp = { .opcode = SRP_AER_RSP };
|
||||
s32 delta;
|
||||
|
||||
if (byte_len < sizeof(*req)) {
|
||||
shost_printk(KERN_ERR, target->scsi_host, PFX
|
||||
"dropping truncated SRP_AER_REQ (%u bytes received, %zu expected)\n",
|
||||
byte_len, sizeof(*req));
|
||||
return;
|
||||
}
|
||||
|
||||
rsp.tag = req->tag;
|
||||
delta = be32_to_cpu(req->req_lim_delta);
|
||||
|
||||
shost_printk(KERN_ERR, target->scsi_host, PFX
|
||||
"ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun));
|
||||
|
|
@ -2108,11 +2123,11 @@ static void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)
|
|||
break;
|
||||
|
||||
case SRP_CRED_REQ:
|
||||
srp_process_cred_req(ch, iu->buf);
|
||||
srp_process_cred_req(ch, iu->buf, wc->byte_len);
|
||||
break;
|
||||
|
||||
case SRP_AER_REQ:
|
||||
srp_process_aer_req(ch, iu->buf);
|
||||
srp_process_aer_req(ch, iu->buf, wc->byte_len);
|
||||
break;
|
||||
|
||||
case SRP_T_LOGOUT:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user