mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-09-22 09:34:56 +02:00
can: bcm: validate frame length in bcm_rx_setup() for RTR replies
commit62ec41f364upstream. bcm_tx_setup() validates cf->len against the CAN/CAN FD DLC limits before installing frames for TX_SETUP, but bcm_rx_setup() never did the same for the RTR-reply frame configured via RX_SETUP with RX_RTR_FRAME. Fixes:ffd980f976("[CAN]: Add broadcast manager (bcm) protocol") Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://patch.msgid.link/20260714-bcm_fixes-v15-7-562f7e3e42da@hartkopp.net Cc: stable@kernel.org Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
52f06e7603
commit
7d966cdee0
+41
-18
@@ -1199,22 +1199,37 @@ free_op:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void bcm_rx_setup_rtr_check(struct bcm_msg_head *msg_head,
|
||||
struct bcm_op *op, void *new_frames)
|
||||
static int bcm_rx_setup_rtr_check(struct bcm_msg_head *msg_head,
|
||||
struct bcm_op *op, void *new_frames)
|
||||
{
|
||||
struct canfd_frame *frame0 = new_frames;
|
||||
|
||||
if (!(msg_head->flags & RX_RTR_FRAME))
|
||||
return 0;
|
||||
|
||||
/* this frame is sent out as-is by bcm_can_tx() whenever a matching
|
||||
* remote request is received, so validate its length the same way
|
||||
* bcm_tx_setup() validates TX_SETUP frames before installing it
|
||||
*/
|
||||
if (msg_head->flags & CAN_FD_FRAME) {
|
||||
if (frame0->len > 64)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
if (frame0->len > 8)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* funny feature in RX(!)_SETUP only for RTR-mode:
|
||||
* copy can_id into frame BUT without RTR-flag to
|
||||
* prevent a full-load-loopback-test ... ;-]
|
||||
* normalize this on the staged buffer, before it is
|
||||
* ever installed into op->frames.
|
||||
*/
|
||||
if (msg_head->flags & RX_RTR_FRAME) {
|
||||
struct canfd_frame *frame0 = new_frames;
|
||||
if ((msg_head->flags & TX_CP_CAN_ID) ||
|
||||
frame0->can_id == op->can_id)
|
||||
frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
|
||||
|
||||
if ((msg_head->flags & TX_CP_CAN_ID) ||
|
||||
frame0->can_id == op->can_id)
|
||||
frame0->can_id = op->can_id & ~CAN_RTR_FLAG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1277,7 +1292,11 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||
return err;
|
||||
}
|
||||
|
||||
bcm_rx_setup_rtr_check(msg_head, op, new_frames);
|
||||
err = bcm_rx_setup_rtr_check(msg_head, op, new_frames);
|
||||
if (err < 0) {
|
||||
kfree(new_frames);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_bh(&op->bcm_rx_update_lock);
|
||||
@@ -1350,16 +1369,12 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||
if (msg_head->nframes) {
|
||||
err = memcpy_from_msg(op->frames, msg,
|
||||
msg_head->nframes * op->cfsiz);
|
||||
if (err < 0) {
|
||||
if (op->frames != &op->sframe)
|
||||
kfree(op->frames);
|
||||
if (op->last_frames != &op->last_sframe)
|
||||
kfree(op->last_frames);
|
||||
kfree(op);
|
||||
return err;
|
||||
}
|
||||
if (err < 0)
|
||||
goto free_op;
|
||||
|
||||
bcm_rx_setup_rtr_check(msg_head, op, op->frames);
|
||||
err = bcm_rx_setup_rtr_check(msg_head, op, op->frames);
|
||||
if (err < 0)
|
||||
goto free_op;
|
||||
}
|
||||
|
||||
/* bcm_can_tx / bcm_tx_timeout_handler needs this */
|
||||
@@ -1461,6 +1476,14 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
||||
}
|
||||
|
||||
return msg_head->nframes * op->cfsiz + MHSIZ;
|
||||
|
||||
free_op:
|
||||
if (op->frames != &op->sframe)
|
||||
kfree(op->frames);
|
||||
if (op->last_frames != &op->last_sframe)
|
||||
kfree(op->last_frames);
|
||||
kfree(op);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user