1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2019 Linaro Limited. All rights reserved. 4 * Author: Rafael David Tinoco <rafael.tinoco@linaro.org> 5 */ 6 7/* 8 * Basic tests for errors of clock_settime(2) on different clock types. 9 */ 10 11#include "config.h" 12#include "time64_variants.h" 13#include "tst_timer.h" 14#include "tst_safe_clocks.h" 15 16#define DELTA_SEC 10 17 18static void *bad_addr; 19 20struct test_case { 21 clockid_t type; 22 int exp_err; 23 int replace; 24 long tv_sec; 25 long tv_nsec; 26}; 27 28struct test_case tc[] = { 29 { /* case 01: REALTIME: timespec NULL */ 30 .type = CLOCK_REALTIME, 31 .exp_err = EFAULT, 32 .replace = 1, 33 .tv_sec = 0, 34 .tv_nsec = 0, 35 }, 36 { /* case 02: REALTIME: tv_sec = -1 */ 37 .type = CLOCK_REALTIME, 38 .exp_err = EINVAL, 39 .replace = 1, 40 .tv_sec = -1, 41 .tv_nsec = 0, 42 }, 43 { /* case 03: REALTIME: tv_nsec = -1 */ 44 .type = CLOCK_REALTIME, 45 .exp_err = EINVAL, 46 .replace = 1, 47 .tv_sec = 0, 48 .tv_nsec = -1, 49 }, 50 { /* case 04: REALTIME: tv_nsec = 1s+1 */ 51 .type = CLOCK_REALTIME, 52 .exp_err = EINVAL, 53 .replace = 1, 54 .tv_sec = 0, 55 .tv_nsec = NSEC_PER_SEC + 1, 56 }, 57 { /* case 05: MONOTONIC */ 58 .type = CLOCK_MONOTONIC, 59 .exp_err = EINVAL, 60 }, 61 { /* case 06: MAXCLOCK */ 62 .type = MAX_CLOCKS, 63 .exp_err = EINVAL, 64 }, 65 { /* case 07: MAXCLOCK+1 */ 66 .type = MAX_CLOCKS + 1, 67 .exp_err = EINVAL, 68 }, 69 /* Linux specific */ 70 { /* case 08: CLOCK_MONOTONIC_COARSE */ 71 .type = CLOCK_MONOTONIC_COARSE, 72 .exp_err = EINVAL, 73 }, 74 { /* case 09: CLOCK_MONOTONIC_RAW */ 75 .type = CLOCK_MONOTONIC_RAW, 76 .exp_err = EINVAL, 77 }, 78 { /* case 10: CLOCK_BOOTTIME */ 79 .type = CLOCK_BOOTTIME, 80 .exp_err = EINVAL, 81 }, 82 { /* case 11: CLOCK_PROCESS_CPUTIME_ID */ 83 .type = CLOCK_PROCESS_CPUTIME_ID, 84 .exp_err = EINVAL, 85 }, 86 { /* case 12: CLOCK_THREAD_CPUTIME_ID */ 87 .type = CLOCK_THREAD_CPUTIME_ID, 88 .exp_err = EINVAL, 89 }, 90}; 91 92static struct tst_ts spec; 93 94static struct time64_variants variants[] = { 95#if (__NR_clock_settime != __LTP__NR_INVALID_SYSCALL) 96 { .clock_gettime = sys_clock_gettime, .clock_settime = sys_clock_settime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 97#endif 98 99#if (__NR_clock_settime64 != __LTP__NR_INVALID_SYSCALL) 100 { .clock_gettime = sys_clock_gettime64, .clock_settime = sys_clock_settime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 101#endif 102}; 103 104static void setup(void) 105{ 106 tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); 107 108 bad_addr = tst_get_bad_addr(NULL); 109} 110 111static void verify_clock_settime(unsigned int i) 112{ 113 struct time64_variants *tv = &variants[tst_variant]; 114 void *ts; 115 116 spec.type = tv->ts_type; 117 118 if (tc[i].replace == 0) { 119 TEST(tv->clock_gettime(CLOCK_REALTIME, tst_ts_get(&spec))); 120 if (TST_RET == -1) { 121 tst_res(TFAIL | TTERRNO, "clock_gettime(2) failed for clock %s", 122 tst_clock_name(CLOCK_REALTIME)); 123 return; 124 } 125 126 /* add 1 sec to wall clock */ 127 spec = tst_ts_add_us(spec, 1000000); 128 } else { 129 /* use given time spec */ 130 tst_ts_set_sec(&spec, tc[i].tv_sec); 131 tst_ts_set_nsec(&spec, tc[i].tv_nsec); 132 } 133 134 /* bad pointer case */ 135 if (tc[i].exp_err == EFAULT) 136 ts = bad_addr; 137 else 138 ts = tst_ts_get(&spec); 139 140 TEST(tv->clock_settime(tc[i].type, ts)); 141 142 if (TST_RET != -1) { 143 tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s passed unexpectedly, expected %s", 144 tst_clock_name(tc[i].type), 145 tst_strerrno(tc[i].exp_err)); 146 return; 147 } 148 149 if (tc[i].exp_err == TST_ERR) { 150 tst_res(TPASS | TTERRNO, "clock_settime(%s): failed as expected", 151 tst_clock_name(tc[i].type)); 152 return; 153 } 154 155 tst_res(TFAIL | TTERRNO, "clock_settime(2): clock %s " "expected to fail with %s", 156 tst_clock_name(tc[i].type), tst_strerrno(tc[i].exp_err)); 157} 158 159static struct tst_test test = { 160 .test = verify_clock_settime, 161 .test_variants = ARRAY_SIZE(variants), 162 .setup = setup, 163 .tcnt = ARRAY_SIZE(tc), 164 .needs_root = 1, 165 .restore_wallclock = 1, 166}; 167