mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
can: bcm: validate frame length in bcm_rx_setup() for RTR replies
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>
This commit is contained in:
parent
12ce799f7a
commit
62ec41f364
|
|
@ -1246,22 +1246,37 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
|
|||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1324,7 +1339,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);
|
||||
|
|
@ -1397,16 +1416,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 */
|
||||
|
|
@ -1505,6 +1520,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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user