diff mbox series

hw/timer/nrf51_timer: prevent integer overflow

Message ID 20241203162525.75156-1-abelova@astralinux.ru (mailing list archive)
State New
Headers show
Series hw/timer/nrf51_timer: prevent integer overflow | expand

Commit Message

Anastasia Belova Dec. 3, 2024, 4:25 p.m. UTC
Both counter and tick are uint32_t and the result
of their addition may not fit this type. Add
explicit casting to uint64_t.

Found by Linux Verification Center (linuxtesting.org) with SVACE.

Fixes: c5a4829c08 ("hw/timer/nrf51_timer: Add nRF51 Timer peripheral")
Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
---
 hw/timer/nrf51_timer.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Peter Maydell Dec. 3, 2024, 4:46 p.m. UTC | #1
On Tue, 3 Dec 2024 at 16:25, Anastasia Belova <abelova@astralinux.ru> wrote:
>
> Both counter and tick are uint32_t and the result
> of their addition may not fit this type. Add
> explicit casting to uint64_t.
>
> Found by Linux Verification Center (linuxtesting.org) with SVACE.
>
> Fixes: c5a4829c08 ("hw/timer/nrf51_timer: Add nRF51 Timer peripheral")
> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
> ---
>  hw/timer/nrf51_timer.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
> index 35b0e62d5b..b5ff235eb8 100644
> --- a/hw/timer/nrf51_timer.c
> +++ b/hw/timer/nrf51_timer.c
> @@ -44,7 +44,7 @@ static uint32_t update_counter(NRF51TimerState *s, int64_t now)
>  {
>      uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
>
> -    s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
> +    s->counter = ((uint64_t)s->counter + ticks) % BIT(bitwidths[s->bitmode]);

Can you explain when adding the cast makes a difference?
Since s->counter is 32 bits and ticks is 32 bits and
the RHS of the % is a power of 2, it's not clear to
me that keeping the top 32 bits in the addition and then
discarding it after the % is any different from only
taking the bottom 32 bits of the addition.

thanks
-- PMM
Anastasia Belova Dec. 4, 2024, 12:26 p.m. UTC | #2
On 12/3/24 7:46 PM, Peter Maydell wrote:
> On Tue, 3 Dec 2024 at 16:25, Anastasia Belova <abelova@astralinux.ru> wrote:
>> Both counter and tick are uint32_t and the result
>> of their addition may not fit this type. Add
>> explicit casting to uint64_t.
>>
>> Found by Linux Verification Center (linuxtesting.org) with SVACE.
>>
>> Fixes: c5a4829c08 ("hw/timer/nrf51_timer: Add nRF51 Timer peripheral")
>> Signed-off-by: Anastasia Belova <abelova@astralinux.ru>
>> ---
>>   hw/timer/nrf51_timer.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
>> index 35b0e62d5b..b5ff235eb8 100644
>> --- a/hw/timer/nrf51_timer.c
>> +++ b/hw/timer/nrf51_timer.c
>> @@ -44,7 +44,7 @@ static uint32_t update_counter(NRF51TimerState *s, int64_t now)
>>   {
>>       uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
>>
>> -    s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
>> +    s->counter = ((uint64_t)s->counter + ticks) % BIT(bitwidths[s->bitmode]);
> Can you explain when adding the cast makes a difference?
> Since s->counter is 32 bits and ticks is 32 bits and
> the RHS of the % is a power of 2, it's not clear to
> me that keeping the top 32 bits in the addition and then
> discarding it after the % is any different from only
> taking the bottom 32 bits of the addition.
>
You're right. I was sure this situation invokes UB.

Thanks for your patience,
Anastasia Belova
diff mbox series

Patch

diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c
index 35b0e62d5b..b5ff235eb8 100644
--- a/hw/timer/nrf51_timer.c
+++ b/hw/timer/nrf51_timer.c
@@ -44,7 +44,7 @@  static uint32_t update_counter(NRF51TimerState *s, int64_t now)
 {
     uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
 
-    s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
+    s->counter = ((uint64_t)s->counter + ticks) % BIT(bitwidths[s->bitmode]);
     /*
      * Only advance the sync time to the timestamp of the last tick,
      * not all the way to 'now', so we don't lose time if we do