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 * Bad argument tests for clock_gettime(2) on multiple clocks: 8 * 9 * 1) MAX_CLOCKS 10 * 2) MAX_CLOCKS + 1 11 * 3) CLOCK_REALTIME 12 * 4) CLOCK_MONOTONIC 13 * 5) CLOCK_PROCESS_CPUTIME_ID 14 * 6) CLOCK_THREAD_CPUTIME_ID 15 * 7) CLOCK_REALTIME_COARSE 16 * 8) CLOCK_MONOTONIC_COARSE 17 * 9) CLOCK_MONOTONIC_RAW 18 * 10) CLOCK_BOOTTIME 19 */ 20 21#include "config.h" 22#include "time64_variants.h" 23#include "tst_timer.h" 24#include "tst_safe_clocks.h" 25 26static void *bad_addr; 27 28struct test_case { 29 clockid_t clktype; 30 int exp_err; 31 int allow_inval; 32}; 33 34static struct test_case tc[] = { 35 { 36 .clktype = MAX_CLOCKS, 37 .exp_err = EINVAL, 38 }, 39 { 40 .clktype = MAX_CLOCKS + 1, 41 .exp_err = EINVAL, 42 }, 43 /* 44 * Different POSIX clocks have different (*clock_get)() handlers. 45 * It justifies testing EFAULT for all. 46 */ 47 { 48 .clktype = CLOCK_REALTIME, 49 .exp_err = EFAULT, 50 }, 51 { 52 .clktype = CLOCK_MONOTONIC, 53 .exp_err = EFAULT, 54 }, 55 { 56 .clktype = CLOCK_PROCESS_CPUTIME_ID, 57 .exp_err = EFAULT, 58 }, 59 { 60 .clktype = CLOCK_THREAD_CPUTIME_ID, 61 .exp_err = EFAULT, 62 }, 63 { 64 .clktype = CLOCK_REALTIME_COARSE, 65 .exp_err = EFAULT, 66 .allow_inval = 1, 67 }, 68 { 69 .clktype = CLOCK_MONOTONIC_COARSE, 70 .exp_err = EFAULT, 71 .allow_inval = 1, 72 }, 73 { 74 .clktype = CLOCK_MONOTONIC_RAW, 75 .exp_err = EFAULT, 76 .allow_inval = 1, 77 }, 78 { 79 .clktype = CLOCK_BOOTTIME, 80 .exp_err = EFAULT, 81 .allow_inval = 1, 82 }, 83}; 84 85static struct tst_ts spec; 86 87/* 88 * bad pointer w/ libc causes SIGSEGV signal, call syscall directly 89 */ 90static struct time64_variants variants[] = { 91#if (__NR_clock_gettime != __LTP__NR_INVALID_SYSCALL) 92 { .clock_gettime = sys_clock_gettime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 93#endif 94 95#if (__NR_clock_gettime64 != __LTP__NR_INVALID_SYSCALL) 96 { .clock_gettime = sys_clock_gettime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 97#endif 98}; 99 100static void setup(void) 101{ 102 tst_res(TINFO, "Testing variant: %d: %s", tst_variant, variants[tst_variant].desc); 103 104 bad_addr = tst_get_bad_addr(NULL); 105} 106 107static void verify_clock_gettime(unsigned int i) 108{ 109 struct time64_variants *tv = &variants[tst_variant]; 110 void *ts; 111 112 /* bad pointer cases */ 113 if (tc[i].exp_err == EFAULT) { 114 ts = bad_addr; 115 } else { 116 spec.type = tv->ts_type; 117 ts = tst_ts_get(&spec); 118 } 119 120 TEST(tv->clock_gettime(tc[i].clktype, ts)); 121 122 if (TST_RET != -1) { 123 tst_res(TFAIL, "clock_gettime(2): clock %s passed unexpectedly", 124 tst_clock_name(tc[i].clktype)); 125 return; 126 } 127 128 if ((tc[i].exp_err == TST_ERR) || 129 (tc[i].allow_inval && TST_ERR == EINVAL)) { 130 tst_res(TPASS | TTERRNO, "clock_gettime(2): clock %s failed as expected", 131 tst_clock_name(tc[i].clktype)); 132 } else { 133 tst_res(TFAIL | TTERRNO, "clock_gettime(2): clock %s failed unexpectedly", 134 tst_clock_name(tc[i].clktype)); 135 } 136} 137 138static struct tst_test test = { 139 .test = verify_clock_gettime, 140 .tcnt = ARRAY_SIZE(tc), 141 .test_variants = ARRAY_SIZE(variants), 142 .setup = setup, 143 .needs_root = 1, 144}; 145