Project

General

Profile

Actions

Feature #7510

closed

enable highres clock usage for non-privileged users

Added by Robert Mustacchi over 5 years ago. Updated almost 2 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
kernel
Start date:
2016-10-25
Due date:
% Done:

100%

Estimated time:
Difficulty:
Medium
Tags:
Gerrit CR:

Description

Many applications on other systems allow non-privileged users to leverage the high resolution clock for timers. This has traditionally been behind a privilege as we worry about it being a potential way a user can create a denial of service.

We seem to have converged on the idea that without the priv we'll clamp the minimum monotonic value at something like 5000 hz (200 usecs) and if you have the priv you can do any interval. Once we're above a certain resolution (e.g., 1000 hz), we can also clamp you to evenly divide the interval.

Actions #1

Updated by Robert Mustacchi almost 2 years ago

To test this, I wrote a small program with a high-resolution timer that created a 23 nanosecond timer and then used DTrace to see if we had rewritten the timer interval. Here's the C program:

#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <err.h>
#include <unistd.h>
#include <strings.h>

int
main(void)
{
        timer_t t;
        struct itimerspec it;

        if (timer_create(CLOCK_HIGHRES, NULL, &t) != 0) {
                err(1, "failed to create high res clock");
        }

        bzero(&it, sizeof (it));
        it.it_value.tv_nsec = 23;
        if (timer_settime(t, 0, &it, NULL) != 0) {
                err(1, "failed to create the timer");
        }

        (void) pause();

        return (0);
}

Then, I used the following DTrace (long) one liner: dtrace -n 'fbt::clock_highres_timer_settime:entry/execname == "timer"/{ self->t = 1; print(*args[2]); }' -n 'fbt::ts2hrt:entry/self->t/{ print(*args[0]); }' -n 'fbt::clock_highres_timer_settime:return{ self->t = 0; }' -n 'fbt::cyclic_add:entry/self->t/{ print(*args[1]); }'

Running this, with the program as a normal user, you see:

root@beowulf:~# dtrace -n 'fbt::clock_highres_timer_settime:entry/execname == "timer"/{ self->t = 1; print(*args[2]); }' -n 'fbt::ts2hrt:entry/self->t/{ print(*args[0]); }' -n 'fbt::clock_highres_timer_settime:return{ self->t = 0; }' -n 'fbt::cyclic_add:entry/self->t/{ print(*args[1]); }'
dtrace: description 'fbt::clock_highres_timer_settime:entry' matched 1 probe
dtrace: description 'fbt::ts2hrt:entry' matched 1 probe
dtrace: description 'fbt::clock_highres_timer_settime:return' matched 1 probe
dtrace: description 'fbt::cyclic_add:entry' matched 1 probe
CPU     ID                    FUNCTION:NAME
 30  10513 clock_highres_timer_settime:entry struct itimerspec {
    struct timespec it_interval = {
        time_t tv_sec = 0
        long tv_nsec = 0
    }
    struct timespec it_value = {
        time_t tv_sec = 0
        long tv_nsec = 0x17
    }
}
 30  20263                     ts2hrt:entry timestruc_t {
    time_t tv_sec = 0
    long tv_nsec = 0x30d40
}
 30  20263                     ts2hrt:entry timestruc_t {
    time_t tv_sec = 0
    long tv_nsec = 0
}
 30  17297                 cyclic_add:entry cyc_time_t {
    hrtime_t cyt_when = 0x10230619721
    hrtime_t cyt_interval = 0x7fffffffffffffff
}

The second print statement is when we go through and have adjusted things. See how the 0x17 (23) was changed to 0x30d40 (200 us). If we now look at the output while running with root privileges:

^[[Aroot@beowulf:~# dtrace -n 'fbt::clock_highres_timer_settime:entry/execname == "timer"/{ self->t = 1; print(*args[2]); }' -n 'fbt::ts2hrt:entry/self->t/{ print(*args[0]); }' -n 'fbt::clock_highres_timer_settime:return{ self->t = 0; }' -n 'fbt::cyclic_add:entry/self->t/{ print(*args[1]); }'
dtrace: description 'fbt::clock_highres_timer_settime:entry' matched 1 probe
dtrace: description 'fbt::ts2hrt:entry' matched 1 probe
dtrace: description 'fbt::clock_highres_timer_settime:return' matched 1 probe
dtrace: description 'fbt::cyclic_add:entry' matched 1 probe
CPU     ID                    FUNCTION:NAME
 23  10513 clock_highres_timer_settime:entry struct itimerspec {
    struct timespec it_interval = {
        time_t tv_sec = 0
        long tv_nsec = 0
    }
    struct timespec it_value = {
        time_t tv_sec = 0
        long tv_nsec = 0x17
    }
}
 23  20263                     ts2hrt:entry timestruc_t {
    time_t tv_sec = 0
    long tv_nsec = 0x17
}
 23  20263                     ts2hrt:entry timestruc_t {
    time_t tv_sec = 0
    long tv_nsec = 0
}
 23  17297                 cyclic_add:entry cyc_time_t {
    hrtime_t cyt_when = 0x1294d5b1670
    hrtime_t cyt_interval = 0x7fffffffffffffff
}

In this case we've no longer adjusted this. So this proves that clamping does work correctly, doesn't interfere with root privileges, and provides a non-privileged user access to this with a reasonable granularity.

Actions #2

Updated by Robert Mustacchi almost 2 years ago

  • Subject changed from enable highres clock usage for non-priviliged users to enable highres clock usage for non-privileged users
Actions #3

Updated by Electric Monk almost 2 years ago

  • Status changed from New to Closed

git commit 605d010da59abaf92279a7caed83515cbb3218dc

commit  605d010da59abaf92279a7caed83515cbb3218dc
Author: Jerry Jelinek <jerry.jelinek@joyent.com>
Date:   2020-06-02T14:02:29.000Z

    7510 enable highres clock usage for non-privileged users
    Reviewed by: Bryan Cantrill <bryan@joyent.com>
    Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
    Reviewed by: Robert Mustacchi <rm@joyent.com>
    Reviewed by: Yuri Pankov <ypankov@tintri.com>
    Approved by: Richard Lowe <richlowe@richlowe.net>

Actions

Also available in: Atom PDF