Message ID | 70417fdc55c750e8b13d7124e66a7e8a59182e75.1590494889.git.viresh.kumar@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | syscalls: clock_settime: Add test around y2038 vulnerability | expand |
On Tue, May 26, 2020 at 2:10 PM Viresh Kumar <viresh.kumar@linaro.org> wrote: > > This adds a test around the y2038 vulnerability, it sets the system time > to just before y2038 time (i.e. max value that can be stored in s32), > and adds a timer to expire just after crossing it. > > Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Nice! > +static struct test_variants { > + int (*clock_settime)(clockid_t clk_id, void *ts); > + int (*timer_settime)(timer_t timerid, int flags, void *its, > + void *old_its); > + enum tst_ts_type type; > + char *desc; > +} variants[] = { > +#if (__NR_clock_settime != __LTP__NR_INVALID_SYSCALL) > + { .clock_settime = sys_clock_settime, .timer_settime = sys_timer_settime, .type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, > +#endif > + > +#if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL) > + { .clock_settime = sys_clock_settime64, .timer_settime = sys_timer_settime64, .type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, > +#endif I think the first one has to be guarded so we do not try to set the time to just before the end with sys_clock_settime() on 32-bit machines, as kernels that don't fully support 64-bit time_t behave in unpredictable ways when you do that and are likely to crash. However, we probably do want to test this on 64-bit kernels with sys_clock_settime() anyway. > + tst_ts_set_sec(&ts, time); > + tst_ts_set_nsec(&ts, 0); > + > + ret = tv->clock_settime(CLOCK_REALTIME, tst_ts_get(&ts)); > + if (ret == -1) > + tst_brk(TBROK | TERRNO, "clock_settime() failed"); > + > + tst_its_set_time(&its, time + EXPIREDELTA, 0, 0, 0); I suspect this is where it fails for the 32-bit time_t case, as the expiration date for timer_settime wraps to year 1902. Arnd
On 27-05-20, 13:18, Arnd Bergmann wrote: > On Tue, May 26, 2020 at 2:10 PM Viresh Kumar <viresh.kumar@linaro.org> wrote: > > > > This adds a test around the y2038 vulnerability, it sets the system time > > to just before y2038 time (i.e. max value that can be stored in s32), > > and adds a timer to expire just after crossing it. > > > > Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> > > Nice! > > +static struct test_variants { > > + int (*clock_settime)(clockid_t clk_id, void *ts); > > + int (*timer_settime)(timer_t timerid, int flags, void *its, > > + void *old_its); > > + enum tst_ts_type type; > > + char *desc; > > +} variants[] = { > > +#if (__NR_clock_settime != __LTP__NR_INVALID_SYSCALL) > > + { .clock_settime = sys_clock_settime, .timer_settime = sys_timer_settime, .type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, > > +#endif > > + > > +#if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL) > > + { .clock_settime = sys_clock_settime64, .timer_settime = sys_timer_settime64, .type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, > > +#endif > > I think the first one has to be guarded so we do not try to set > the time to just before the end with sys_clock_settime() on > 32-bit machines, as kernels that don't fully support 64-bit > time_t behave in unpredictable ways when you do that and > are likely to crash. > > However, we probably do want to test this on 64-bit kernels > with sys_clock_settime() anyway. I have done this differently, please see V2.
diff --git a/runtest/syscalls b/runtest/syscalls index 8457db34e999..d7c3cbed611a 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -101,6 +101,7 @@ leapsec01 leapsec01 clock_settime01 clock_settime01 clock_settime02 clock_settime02 +clock_settime03 clock_settime03 clone01 clone01 clone02 clone02 diff --git a/testcases/kernel/syscalls/clock_settime/.gitignore b/testcases/kernel/syscalls/clock_settime/.gitignore index 28121755006b..b66169b3eb7b 100644 --- a/testcases/kernel/syscalls/clock_settime/.gitignore +++ b/testcases/kernel/syscalls/clock_settime/.gitignore @@ -1,2 +1,3 @@ clock_settime01 clock_settime02 +clock_settime03 diff --git a/testcases/kernel/syscalls/clock_settime/clock_settime03.c b/testcases/kernel/syscalls/clock_settime/clock_settime03.c new file mode 100644 index 000000000000..94e2d4ce4b9e --- /dev/null +++ b/testcases/kernel/syscalls/clock_settime/clock_settime03.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar<viresh.kumar@linaro.org> + * + * Check Year 2038 related vulnerabilities. + */ + +#include <signal.h> +#include "config.h" +#include "tst_timer.h" +#include "tst_safe_clocks.h" + +#define EXPIREDELTA 4 + +static struct tst_ts ts; +static struct tst_its its; + +static struct test_variants { + int (*clock_settime)(clockid_t clk_id, void *ts); + int (*timer_settime)(timer_t timerid, int flags, void *its, + void *old_its); + enum tst_ts_type type; + char *desc; +} variants[] = { +#if (__NR_clock_settime != __LTP__NR_INVALID_SYSCALL) + { .clock_settime = sys_clock_settime, .timer_settime = sys_timer_settime, .type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, +#endif + +#if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL) + { .clock_settime = sys_clock_settime64, .timer_settime = sys_timer_settime64, .type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, +#endif +}; + +static void setup(void) +{ + tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); + ts.type = its.type = variants[tst_variant].type; +} + +static void run(void) +{ + struct test_variants *tv = &variants[tst_variant]; + unsigned long long time = 0x7FFFFFFE; /* Time just before y2038 */ + struct sigevent ev = { + .sigev_notify = SIGEV_SIGNAL, + .sigev_signo = SIGABRT, + }; + timer_t timer; + sigset_t set; + int sig, ret; + + if (sigemptyset(&set) == -1) + tst_brk(TBROK, "sigemptyset() failed"); + + if (sigaddset(&set, SIGABRT) == -1) + tst_brk(TBROK, "sigaddset() failed"); + + if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) + tst_brk(TBROK, "sigprocmask() failed"); + + TEST(tst_syscall(__NR_timer_create, CLOCK_REALTIME_ALARM, &ev, &timer)); + if (TST_RET != 0) + tst_brk(TBROK | TERRNO, "timer_create() failed"); + + tst_ts_set_sec(&ts, time); + tst_ts_set_nsec(&ts, 0); + + ret = tv->clock_settime(CLOCK_REALTIME, tst_ts_get(&ts)); + if (ret == -1) + tst_brk(TBROK | TERRNO, "clock_settime() failed"); + + tst_its_set_time(&its, time + EXPIREDELTA, 0, 0, 0); + + TEST(tv->timer_settime(timer, TIMER_ABSTIME, tst_its_get(&its), NULL)); + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "timer_settime() failed"); + + if (sigwait(&set, &sig) == -1) + tst_brk(TBROK, "sigwait() failed"); + + if (sig == SIGABRT) { + tst_res(TPASS, "clock_settime(): Y2038 test passed"); + return; + } + + tst_res(TFAIL, "clock_settime(): Y2038 test failed"); +} + +static struct tst_test test = { + .test_all = run, + .test_variants = ARRAY_SIZE(variants), + .setup = setup, + .needs_root = 1, + .restore_wallclock = 1, +};
This adds a test around the y2038 vulnerability, it sets the system time to just before y2038 time (i.e. max value that can be stored in s32), and adds a timer to expire just after crossing it. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> --- Arnd/Cyril, There is some problem with this test, I am trying to fire the timer after 4 seconds, but it fires in no time. I am not sure on what's incorrect here. runtest/syscalls | 1 + .../kernel/syscalls/clock_settime/.gitignore | 1 + .../syscalls/clock_settime/clock_settime03.c | 96 +++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 testcases/kernel/syscalls/clock_settime/clock_settime03.c