Bug 14717 - Allow choice of clock source for calls to sem_timedwait() and pthread_mutex_timedwait().
Summary: Allow choice of clock source for calls to sem_timedwait() and pthread_mutex_t...
Status: WAITING
Alias: None
Product: glibc
Classification: Unclassified
Component: nptl (show other bugs)
Version: unspecified
: P2 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-10-14 11:58 UTC by Grotlek
Modified: 2019-05-27 14:42 UTC (History)
12 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Grotlek 2012-10-14 11:58:23 UTC
The OS maintains various clocks, such as CLOCK_REALTIME, CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW.

CLOCK_REALTIME is defined as being the "wall clock" time, and as such, is subject to being changed by NTP, calls to adjtime(), clock changes by the system administrator, and jumps to and from DST.

PThread conditionals allow you to choose which clock the calls are synchronised with; so pthread_cond_timedwait() can synchronise with CLOCK_MONOTONIC_RAW by calling pthread_cond_init() with an appropriate attribute set.

However, no such facility exists for pthread_mutex_timedwait() or sem_timedwait(). Looking at the source code to sem_timedwait(), it appears to just translate the time given into a relative offset against gettimeofday() and then call the underlying futex() system call.

Please add facility to semaphores and mutexes to allow a choice of clocks to prevent the following scenario:

1. Program wants to call wait on a semaphore, but also process 1 second 'ticks'.
2. Program determines what the CLOCK_REALTIME time will be in 1 second, and loads this value into a 'struct timespec'.
3. At this point in time, a clock change happens (DST/NTP/adjtime/admin changing clock) - let's say DST changes the clock time by minus one hour.
4. Program calls sem_timedwait() with its timespec set to what the program believes is 1 second.
5. sem_timedwait() calls gettimeofday() and prepares its relative offset, which is now 1 hour and 1 second. It could feasibly not wake up for another hour.

This scenario isn't good if the tick is, for example, to process updates to a UI. (It could even be to update a clock time :P).

So to repeat, please add functionality to allow a C program to choose the clock source for calls to sem_timedwait() and pthread_mutex_timedwait().
Comment 1 Rich Felker 2012-10-15 03:46:15 UTC
DST does not affect the clock whatsoever.
Comment 2 Grotlek 2012-10-16 13:30:59 UTC
Accepted - I was inferring from the Debian man page for clock_gettime() - as the "wall clock" time does change for DST. However, the issue does still apply because the clocks used for programmatic threads are subject to change with the race condition I described, even if DST isn't one of the factors that influence it (the other three do, and those are directly stated by the man pages).

I'll paste the descriptions of the clocks from the man page here, as it does add to the conversation.

---

Sufficiently recent versions of glibc and the Linux kernel support  the
 following clocks:

 CLOCK_REALTIME
        System-wide  clock  that  measures real (i.e., wall-clock) time.
        Setting this clock requires appropriate privileges.  This  clock
        is  affected by discontinuous jumps in the system time (e.g., if
        the system administrator manually changes the clock), and by the
        incremental adjustments performed by adjtime(3) and NTP.

 CLOCK_MONOTONIC
        Clock  that  cannot  be  set and represents monotonic time since
        some unspecified starting point.  This clock is not affected  by
        discontinuous  jumps  in  the  system  time (e.g., if the system
        administrator manually changes the clock), but  is  affected  by
        the incremental adjustments performed by adjtime(3) and NTP.

 CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific)
        Similar  to  CLOCK_MONOTONIC, but provides access to a raw hard‐
        ware-based time that is not subject to NTP  adjustments  or  the
        incremental adjustments performed by adjtime(3).
Comment 3 OndrejBilka 2013-05-09 19:29:21 UTC
We must pass a time to kernel. For specifing time in other formats you would need add appropriate choice in syscalls.
Comment 4 Dean Jenkins 2014-10-23 09:18:40 UTC
Is there any news on allowing CLOCK_MONOTONIC to be used with sem_timedwait() ?

The issue we are facing on an embedded ARM project is that sem_timedwait() can misbehave when the system clock aka CLOCK_REALTIME is modified such as by a GPS timebase. Typically the system does not have a real RTC and starts at the EPOCH of 1970 and then sometime after boot the system clock gets adjusted to the present day time. This causes a misbehaviour of sem_timedwait() because an absolute timespec is used such as a time in 1970.

I think a lack of a monotonic clock for functions such as sem_timedwait() is a serious limitation in embedded systems.

I read reports on the Internet about sem_timedwait() not having a monotonic clock but no solutions or workarounds appear to be written in the reports. Does anyone have a workaround because this seems to be a long-standing issue/limitation ?

Thanks.
Comment 5 Jay 2015-10-07 08:54:27 UTC
I'm using wait-calls and have problems if another process changes the time.
Would very much appreciate it if monotonic was supported somehow.
Comment 6 Florian Weimer 2016-02-04 14:57:34 UTC
It seems this would need kernel work, to add new futex wait operations which specify a clock type.  I don't think we can address this inside glibc.
Comment 7 Grotlek 2016-02-16 13:38:14 UTC
Hi,

I am going to assume it's not possible to use a similar method to the PThread conditionals then; shame.

As it stands (although I've not tested either - this paragraph at the moment is hypothetical) it's potentially possible for any process with the permission to set the clock to effectively hang other processes (DoS) by using a "while(1) adjtime(..);" call or by "abuse" of an upstream NTP server achieve the same thing. (Although admittedly, there would be two problems if this were to happen ;-). Doubly so if the processes use the timeout to actually do background work (which would no longer get done).

However, now three of us have seen this problem on a smaller scale in real use (myself and two other commenters), the bug is clearly not just hypothetical.

Is it worth someone who understands the underlying code better (hint, probably not me because I could not be sufficiently pedantic with the description :-), pushing this into the kernel bug tracker?
Comment 8 Jay 2016-02-16 14:10:50 UTC
I created ticket 112521


https://bugzilla.kernel.org/show_bug.cgi?id=112521
Comment 9 Niels 2016-04-25 07:51:24 UTC
Hmm, I'm into this problem as well. But futex(2) has supported CLOCK_MONOTONIC at least since linux kernel 3.0. It does not support CLOCK_MONOTONIC_RAW. Hint: just OR your futex command with FUTEX_CLOCK_REALTIME.
So maybe it falls back to the libc implementors after all. It should be more or less just a matter of cut'n'paste sem_timedwait() but just with OR'ing all FUTEX-commands with FUTEX_CLOCK_REALTIME.