| From 93171ba6f1deffd82f381d36cb13177872d023f6 Mon Sep 17 00:00:00 2001 |
| From: Oliver Hartkopp <socketcan@hartkopp.net> |
| Date: Sun, 13 Jan 2019 19:31:43 +0100 |
| Subject: can: bcm: check timer values before ktime conversion |
| |
| From: Oliver Hartkopp <socketcan@hartkopp.net> |
| |
| commit 93171ba6f1deffd82f381d36cb13177872d023f6 upstream. |
| |
| Kyungtae Kim detected a potential integer overflow in bcm_[rx|tx]_setup() |
| when the conversion into ktime multiplies the given value with NSEC_PER_USEC |
| (1000). |
| |
| Reference: https://marc.info/?l=linux-can&m=154732118819828&w=2 |
| |
| Add a check for the given tv_usec, so that the value stays below one second. |
| Additionally limit the tv_sec value to a reasonable value for CAN related |
| use-cases of 400 days and ensure all values to be positive. |
| |
| Reported-by: Kyungtae Kim <kt0755@gmail.com> |
| Tested-by: Oliver Hartkopp <socketcan@hartkopp.net> |
| Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> |
| Cc: linux-stable <stable@vger.kernel.org> # >= 2.6.26 |
| Tested-by: Kyungtae Kim <kt0755@gmail.com> |
| Acked-by: Andre Naujoks <nautsch2@gmail.com> |
| Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| net/can/bcm.c | 27 +++++++++++++++++++++++++++ |
| 1 file changed, 27 insertions(+) |
| |
| --- a/net/can/bcm.c |
| +++ b/net/can/bcm.c |
| @@ -67,6 +67,9 @@ |
| */ |
| #define MAX_NFRAMES 256 |
| |
| +/* limit timers to 400 days for sending/timeouts */ |
| +#define BCM_TIMER_SEC_MAX (400 * 24 * 60 * 60) |
| + |
| /* use of last_frames[index].flags */ |
| #define RX_RECV 0x40 /* received data for this element */ |
| #define RX_THR 0x80 /* element not been sent due to throttle feature */ |
| @@ -140,6 +143,22 @@ static inline ktime_t bcm_timeval_to_kti |
| return ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC); |
| } |
| |
| +/* check limitations for timeval provided by user */ |
| +static bool bcm_is_invalid_tv(struct bcm_msg_head *msg_head) |
| +{ |
| + if ((msg_head->ival1.tv_sec < 0) || |
| + (msg_head->ival1.tv_sec > BCM_TIMER_SEC_MAX) || |
| + (msg_head->ival1.tv_usec < 0) || |
| + (msg_head->ival1.tv_usec >= USEC_PER_SEC) || |
| + (msg_head->ival2.tv_sec < 0) || |
| + (msg_head->ival2.tv_sec > BCM_TIMER_SEC_MAX) || |
| + (msg_head->ival2.tv_usec < 0) || |
| + (msg_head->ival2.tv_usec >= USEC_PER_SEC)) |
| + return true; |
| + |
| + return false; |
| +} |
| + |
| #define CFSIZ(flags) ((flags & CAN_FD_FRAME) ? CANFD_MTU : CAN_MTU) |
| #define OPSIZ sizeof(struct bcm_op) |
| #define MHSIZ sizeof(struct bcm_msg_head) |
| @@ -873,6 +892,10 @@ static int bcm_tx_setup(struct bcm_msg_h |
| if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES) |
| return -EINVAL; |
| |
| + /* check timeval limitations */ |
| + if ((msg_head->flags & SETTIMER) && bcm_is_invalid_tv(msg_head)) |
| + return -EINVAL; |
| + |
| /* check the given can_id */ |
| op = bcm_find_op(&bo->tx_ops, msg_head, ifindex); |
| if (op) { |
| @@ -1053,6 +1076,10 @@ static int bcm_rx_setup(struct bcm_msg_h |
| (!(msg_head->can_id & CAN_RTR_FLAG)))) |
| return -EINVAL; |
| |
| + /* check timeval limitations */ |
| + if ((msg_head->flags & SETTIMER) && bcm_is_invalid_tv(msg_head)) |
| + return -EINVAL; |
| + |
| /* check the given can_id */ |
| op = bcm_find_op(&bo->rx_ops, msg_head, ifindex); |
| if (op) { |