2024-03-22 09:02:23

by Roman Smirnov

[permalink] [raw]
Subject: [PATCH] udf: udftime: prevent overflow in udf_disk_stamp_to_time()

An overflow can occur in a situation where src.centiseconds
takes the value of 255. This situation is unlikely, but there
is no validation check anywere in the code. It is necessary
to convert the type of expression to 64-bit.

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

Suggested-by: Sergey Shtylyov <[email protected]>
Signed-off-by: Roman Smirnov <[email protected]>
Reviewed-by: Sergey Shtylyov <[email protected]>
---
fs/udf/udftime.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c
index 758163af39c2..2824b90c8288 100644
--- a/fs/udf/udftime.c
+++ b/fs/udf/udftime.c
@@ -33,6 +33,7 @@ udf_disk_stamp_to_time(struct timespec64 *dest, struct timestamp src)
u16 year = le16_to_cpu(src.year);
uint8_t type = typeAndTimezone >> 12;
int16_t offset;
+ int64_t nsec;

if (type == 1) {
offset = typeAndTimezone << 4;
@@ -46,13 +47,13 @@ udf_disk_stamp_to_time(struct timespec64 *dest, struct timestamp src)
dest->tv_sec = mktime64(year, src.month, src.day, src.hour, src.minute,
src.second);
dest->tv_sec -= offset * 60;
- dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
+ nsec = 1000LL * (src.centiseconds * 10000 +
src.hundredsOfMicroseconds * 100 + src.microseconds);
/*
* Sanitize nanosecond field since reportedly some filesystems are
* recorded with bogus sub-second values.
*/
- dest->tv_nsec %= NSEC_PER_SEC;
+ dest->tv_nsec = do_div(nsec, NSEC_PER_SEC);
}

void
--
2.34.1



2024-03-22 13:49:07

by Jan Kara

[permalink] [raw]
Subject: Re: [PATCH] udf: udftime: prevent overflow in udf_disk_stamp_to_time()

On Fri 22-03-24 12:01:45, Roman Smirnov wrote:
> An overflow can occur in a situation where src.centiseconds
> takes the value of 255. This situation is unlikely, but there
> is no validation check anywere in the code. It is necessary
> to convert the type of expression to 64-bit.
>
> Found by Linux Verification Center (linuxtesting.org) with Svace.
>
> Suggested-by: Sergey Shtylyov <[email protected]>
> Signed-off-by: Roman Smirnov <[email protected]>
> Reviewed-by: Sergey Shtylyov <[email protected]>

Thanks for the fix but I think this is not the right way to solve the
problem. Mainly because the 64-bit division is unnecessarily costly. I'd
rather first make sure that src.centiseconds < 100,
src.hundredsOfMicroseconds < 100, src.microseconds < 100 (just ignore the
values if any is bogus) and then do the multiplication without worrying it
might overflow the int type...

Honza

> @@ -46,13 +47,13 @@ udf_disk_stamp_to_time(struct timespec64 *dest, struct timestamp src)
> dest->tv_sec = mktime64(year, src.month, src.day, src.hour, src.minute,
> src.second);
> dest->tv_sec -= offset * 60;
> - dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
> + nsec = 1000LL * (src.centiseconds * 10000 +
> src.hundredsOfMicroseconds * 100 + src.microseconds);
> /*
> * Sanitize nanosecond field since reportedly some filesystems are
> * recorded with bogus sub-second values.
> */
> - dest->tv_nsec %= NSEC_PER_SEC;
> + dest->tv_nsec = do_div(nsec, NSEC_PER_SEC);
> }
>
> void
> --
> 2.34.1
>
--
Jan Kara <[email protected]>
SUSE Labs, CR