1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) Wipro Technologies Ltd, 2003. All Rights Reserved. 4 * 5 * Author: Aniruddha Marathe <aniruddha.marathe@wipro.com> 6 * 7 * Ported to new library: 8 * 07/2019 Christian Amann <camann@suse.com> 9 */ 10/* 11 * This tests basic error handling of the timer_settime(2) syscall: 12 * 13 * 1) Setting pointer to new settings to NULL -> EINVAL 14 * 2) Setting tv_nsec of the itimerspec structure to a negative value 15 * -> EINVAL 16 * 3) Setting tv_nsec of the itimerspec structure to something larger 17 * than NSEC_PER_SEC -> EINVAL 18 * 4) Passing an invalid timer -> EINVAL 19 * 5) Passing an invalid address for new_value -> EFAULT 20 * 6) Passing an invalid address for old_value -> EFAULT 21 * 22 * This is also regression test for commit: 23 * f18ddc13af98 ("alarmtimer: Use EOPNOTSUPP instead of ENOTSUPP") 24 */ 25 26#include <errno.h> 27#include <time.h> 28#include "time64_variants.h" 29#include "tst_timer.h" 30 31static struct tst_its new_set, old_set; 32static struct tst_its *pnew_set = &new_set, *pold_set = &old_set, *null_set = NULL; 33static void *faulty_set; 34static kernel_timer_t timer; 35static kernel_timer_t timer_inval = (kernel_timer_t)-1; 36 37/* separate description-array to (hopefully) improve readability */ 38static const char * const descriptions[] = { 39 "setting new_set pointer to NULL", 40 "setting tv_nsec to a negative value", 41 "setting tv_nsec value too high", 42 "passing pointer to invalid timer_id", 43 "passing invalid address for new_value", 44 "passing invalid address for old_value", 45}; 46 47static struct testcase { 48 kernel_timer_t *timer_id; 49 struct tst_its **new_ptr; 50 struct tst_its **old_ptr; 51 int it_value_tv_nsec; 52 int error; 53} tcases[] = { 54 {&timer, &null_set, &pold_set, 0, EINVAL}, 55 {&timer, &pnew_set, &pold_set, -1, EINVAL}, 56 {&timer, &pnew_set, &pold_set, NSEC_PER_SEC + 1, EINVAL}, 57 {&timer_inval, &pnew_set, &pold_set, 0, EINVAL}, 58 {&timer, (struct tst_its **)&faulty_set, &pold_set, 0, EFAULT}, 59 {&timer, &pnew_set, (struct tst_its **)&faulty_set, 0, EFAULT}, 60}; 61 62static struct time64_variants variants[] = { 63#if (__NR_timer_settime != __LTP__NR_INVALID_SYSCALL) 64 { .timer_settime = sys_timer_settime, .ts_type = TST_KERN_OLD_TIMESPEC, .desc = "syscall with old kernel spec"}, 65#endif 66 67#if (__NR_timer_settime64 != __LTP__NR_INVALID_SYSCALL) 68 { .timer_settime = sys_timer_settime64, .ts_type = TST_KERN_TIMESPEC, .desc = "syscall time64 with kernel spec"}, 69#endif 70}; 71 72static void setup(void) 73{ 74 tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); 75 faulty_set = tst_get_bad_addr(NULL); 76} 77 78static void run(unsigned int n) 79{ 80 struct time64_variants *tv = &variants[tst_variant]; 81 struct testcase *tc = &tcases[n]; 82 void *new, *old; 83 unsigned int i; 84 85 tst_res(TINFO, "Testing for %s:", descriptions[n]); 86 87 for (i = 0; i < CLOCKS_DEFINED; ++i) { 88 clock_t clock = clock_list[i]; 89 90 /* Init temporary timer */ 91 TEST(tst_syscall(__NR_timer_create, clock, NULL, &timer)); 92 if (TST_RET != 0) { 93 if (possibly_unsupported(clock) && 94 (TST_ERR == EINVAL || TST_ERR == ENOTSUP)) { 95 tst_res(TCONF | TTERRNO, "%s unsupported", 96 get_clock_str(clock)); 97 } else { 98 tst_res(TFAIL | TTERRNO, 99 "timer_create(%s) failed", 100 get_clock_str(clock)); 101 } 102 continue; 103 } 104 105 memset(&new_set, 0, sizeof(new_set)); 106 memset(&old_set, 0, sizeof(old_set)); 107 108 new_set.type = old_set.type = tv->ts_type; 109 tst_its_set_interval_sec(&new_set, 0); 110 tst_its_set_interval_nsec(&new_set, 0); 111 tst_its_set_value_sec(&new_set, 5); 112 tst_its_set_value_nsec(&new_set, tc->it_value_tv_nsec); 113 114 new = (tc->new_ptr == (struct tst_its **)&faulty_set) ? faulty_set : tst_its_get(*tc->new_ptr); 115 old = (tc->old_ptr == (struct tst_its **)&faulty_set) ? faulty_set : tst_its_get(*tc->old_ptr); 116 117 TEST(tv->timer_settime(*tc->timer_id, 0, new, old)); 118 119 if (tc->error != TST_ERR) { 120 tst_res(TFAIL | TTERRNO, 121 "%s didn't fail as expected. Expected: %s - Got", 122 get_clock_str(clock), 123 tst_strerrno(tc->error)); 124 } else { 125 tst_res(TPASS | TTERRNO, 126 "%s failed as expected", 127 get_clock_str(clock)); 128 } 129 130 /* Delete temporary timer */ 131 TEST(tst_syscall(__NR_timer_delete, timer)); 132 if (TST_RET != 0) 133 tst_res(TFAIL | TTERRNO, "timer_delete() failed!"); 134 } 135} 136 137static struct tst_test test = { 138 .test = run, 139 .needs_root = 1, 140 .tcnt = ARRAY_SIZE(tcases), 141 .test_variants = ARRAY_SIZE(variants), 142 .setup = setup, 143 .tags = (const struct tst_tag[]) { 144 {"linux-git", "f18ddc13af98"}, 145 {} 146 } 147}; 148