1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd 4 * Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>, 5 * Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, 6 * Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp> 7 * Copyright (c) 2016 Linux Test Project 8 */ 9/* 10 * test status of errors on man page 11 * EINTR v (function was interrupted by a signal) 12 * EINVAL v (invalid tv_nsec, etc.) 13 * ENOTSUP v (sleep not supported against the specified clock_id) 14 * EFAULT v (Invalid request pointer) 15 * EFAULT V (Invalid remain pointer when interrupted by a signal) 16 */ 17 18#include <limits.h> 19 20#include "time64_variants.h" 21#include "tst_safe_clocks.h" 22#include "tst_sig_proc.h" 23#include "tst_timer.h" 24 25static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) 26{ 27} 28 29enum test_type { 30 NORMAL = 1, 31 SEND_SIGINT = 2, 32 BAD_TS_ADDR_REQ = 4, 33 BAD_TS_ADDR_REM = 8, 34}; 35 36#define TYPE_NAME(x) .ttype = x, .desc = #x 37 38static void *bad_addr; 39 40struct test_case { 41 clockid_t clk_id; /* clock_* clock type parameter */ 42 int ttype; /* test type (enum) */ 43 const char *desc; /* test description (name) */ 44 int flags; /* clock_nanosleep flags parameter */ 45 long tv_sec; 46 long tv_nsec; 47 int exp_ret; 48 int exp_err; 49}; 50 51static struct test_case tcase[] = { 52 { 53 TYPE_NAME(NORMAL), 54 .clk_id = CLOCK_REALTIME, 55 .flags = 0, 56 .tv_sec = 0, 57 .tv_nsec = -1, 58 .exp_ret = -1, 59 .exp_err = EINVAL, 60 }, 61 { 62 TYPE_NAME(NORMAL), 63 .clk_id = CLOCK_REALTIME, 64 .flags = 0, 65 .tv_sec = 0, 66 .tv_nsec = 1000000000, 67 .exp_ret = -1, 68 .exp_err = EINVAL, 69 }, 70 { 71 TYPE_NAME(NORMAL), 72 .clk_id = CLOCK_THREAD_CPUTIME_ID, 73 .flags = 0, 74 .tv_sec = 0, 75 .tv_nsec = 500000000, 76 .exp_ret = -1, 77 .exp_err = ENOTSUP, 78 }, 79 { 80 TYPE_NAME(SEND_SIGINT), 81 .clk_id = CLOCK_REALTIME, 82 .flags = 0, 83 .tv_sec = 10, 84 .tv_nsec = 0, 85 .exp_ret = -1, 86 .exp_err = EINTR, 87 }, 88 { 89 TYPE_NAME(BAD_TS_ADDR_REQ), 90 .clk_id = CLOCK_REALTIME, 91 .flags = 0, 92 .exp_ret = -1, 93 .exp_err = EFAULT, 94 }, 95 { 96 TYPE_NAME(BAD_TS_ADDR_REM), 97 .clk_id = CLOCK_REALTIME, 98 .flags = 0, 99 .tv_sec = 10, 100 .tv_nsec = 0, 101 .exp_ret = -1, 102 .exp_err = EFAULT, 103 }, 104}; 105 106static struct tst_ts *rq; 107static struct tst_ts *rm; 108 109static struct time64_variants variants[] = { 110 { .clock_nanosleep = libc_clock_nanosleep, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"}, 111 112#if (__NR_clock_nanosleep != __LTP__NR_INVALID_SYSCALL) 113 { .clock_nanosleep = sys_clock_nanosleep, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 114#endif 115 116#if (__NR_clock_nanosleep_time64 != __LTP__NR_INVALID_SYSCALL) 117 { .clock_nanosleep = sys_clock_nanosleep64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 118#endif 119}; 120 121void setup(void) 122{ 123 rq->type = variants[tst_variant].ts_type; 124 tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); 125 SAFE_SIGNAL(SIGINT, sighandler); 126 bad_addr = tst_get_bad_addr(NULL); 127} 128 129static void do_test(unsigned int i) 130{ 131 struct time64_variants *tv = &variants[tst_variant]; 132 struct test_case *tc = &tcase[i]; 133 pid_t pid = 0; 134 void *request, *remain; 135 136 memset(rm, 0, sizeof(*rm)); 137 rm->type = rq->type; 138 139 tst_res(TINFO, "case %s", tc->desc); 140 141 if (tc->ttype & (BAD_TS_ADDR_REQ | BAD_TS_ADDR_REM) && 142 tv->clock_nanosleep == libc_clock_nanosleep) { 143 tst_res(TCONF, 144 "The libc wrapper may dereference req or rem"); 145 return; 146 } 147 148 if (tc->ttype & (SEND_SIGINT | BAD_TS_ADDR_REM)) 149 pid = create_sig_proc(SIGINT, 40, 500000); 150 151 tst_ts_set_sec(rq, tc->tv_sec); 152 tst_ts_set_nsec(rq, tc->tv_nsec); 153 154 if (tc->ttype == BAD_TS_ADDR_REQ) 155 request = bad_addr; 156 else 157 request = tst_ts_get(rq); 158 159 if (tc->ttype == BAD_TS_ADDR_REM) 160 remain = bad_addr; 161 else 162 remain = tst_ts_get(rm); 163 164 TEST(tv->clock_nanosleep(tc->clk_id, tc->flags, request, remain)); 165 166 if (tv->clock_nanosleep == libc_clock_nanosleep) { 167 /* 168 * The return value and error number are differently set for 169 * libc syscall as compared to kernel syscall. 170 */ 171 if (TST_RET) { 172 TST_ERR = TST_RET; 173 TST_RET = -1; 174 } 175 176 /* 177 * nsleep isn't implemented by kernelf or 178 * CLOCK_THREAD_CPUTIME_ID and it returns ENOTSUP, but libc 179 * changes that error value to EINVAL. 180 */ 181 if (tc->clk_id == CLOCK_THREAD_CPUTIME_ID) 182 tc->exp_err = EINVAL; 183 } 184 185 if (pid) { 186 SAFE_KILL(pid, SIGTERM); 187 SAFE_WAIT(NULL); 188 } 189 190 if (tc->ttype == SEND_SIGINT) { 191 long long expect_ms = tst_ts_to_ms(*rq); 192 long long remain_ms = tst_ts_to_ms(*rm); 193 194 if (tst_ts_valid(rm)) { 195 tst_res(TFAIL | TTERRNO, 196 "The clock_nanosleep() haven't updated" 197 " timespec or it's not valid"); 198 return; 199 } 200 201 if (remain_ms > expect_ms) { 202 tst_res(TFAIL | TTERRNO, 203 "remaining time > requested time (%lld > %lld)", 204 remain_ms, expect_ms); 205 return; 206 } 207 208 tst_res(TPASS, "Timespec updated correctly"); 209 } 210 211 if ((TST_RET != tc->exp_ret) || (TST_ERR != tc->exp_err)) { 212 tst_res(TFAIL | TTERRNO, "returned %ld, expected %d," 213 " expected errno: %s (%d)", TST_RET, 214 tc->exp_ret, tst_strerrno(tc->exp_err), tc->exp_err); 215 return; 216 } 217 218 tst_res(TPASS | TTERRNO, "clock_nanosleep() failed with"); 219} 220 221static struct tst_test test = { 222 .tcnt = ARRAY_SIZE(tcase), 223 .test = do_test, 224 .test_variants = ARRAY_SIZE(variants), 225 .setup = setup, 226 .forks_child = 1, 227 .bufs = (struct tst_buffers []) { 228 {&rq, .size = sizeof(*rq)}, 229 {&rm, .size = sizeof(*rm)}, 230 {}, 231 } 232}; 233