Skip to content

Commit 12e0933

Browse files
committed
time: Prevent 32 bit overflow with set_normalized_timespec()
set_normalized_timespec() nsec argument is of type long. The recent timekeeping changes of ktime_get_ts() feed ts->tv_nsec + tomono.tv_nsec + nsecs to set_normalized_timespec(). On 32 bit machines that sum can be larger than (1 << 31) and therefor result in a negative value which screws up the result completely. Make the nsec argument of set_normalized_timespec() s64 to fix the problem at hand. This also prevents similar problems for future users of set_normalized_timespec(). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Carsten Emde <carsten.emde@osadl.org> LKML-Reference: <new-submission> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: John Stultz <johnstul@us.ibm.com>
1 parent 54a6bc0 commit 12e0933

File tree

2 files changed

+9
-2
lines changed

2 files changed

+9
-2
lines changed

include/linux/time.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ extern unsigned long mktime(const unsigned int year, const unsigned int mon,
7575
const unsigned int day, const unsigned int hour,
7676
const unsigned int min, const unsigned int sec);
7777

78-
extern void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec);
78+
extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec);
7979
extern struct timespec timespec_add_safe(const struct timespec lhs,
8080
const struct timespec rhs);
8181

kernel/time.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,20 @@ EXPORT_SYMBOL(mktime);
370370
* 0 <= tv_nsec < NSEC_PER_SEC
371371
* For negative values only the tv_sec field is negative !
372372
*/
373-
void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec)
373+
void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec)
374374
{
375375
while (nsec >= NSEC_PER_SEC) {
376+
/*
377+
* The following asm() prevents the compiler from
378+
* optimising this loop into a modulo operation. See
379+
* also __iter_div_u64_rem() in include/linux/time.h
380+
*/
381+
asm("" : "+rm"(nsec));
376382
nsec -= NSEC_PER_SEC;
377383
++sec;
378384
}
379385
while (nsec < 0) {
386+
asm("" : "+rm"(nsec));
380387
nsec += NSEC_PER_SEC;
381388
--sec;
382389
}

0 commit comments

Comments
 (0)