1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 4 Copyright (c) 2020 Cyril Hrubis <chrubis@suse.cz> 5 6 */ 7/* 8 9 Basic test for timens_offsets error handling. 10 11 After a call to unshare(CLONE_NEWTIME) a new timer namespace is created, the 12 process that has called the unshare() can adjust offsets for CLOCK_MONOTONIC 13 and CLOCK_BOOTTIME for its children by writing to the '/proc/self/timens_offsets'. 14 15 */ 16 17#define _GNU_SOURCE 18#include "lapi/posix_clocks.h" 19#include "tst_test.h" 20#include "lapi/sched.h" 21 22static struct tcase { 23 const char *desc; 24 const char *offsets; 25 int exp_err; 26} tcases[] = { 27 {"Obvious garbage", "not an offset", EINVAL}, 28 {"Missing nanoseconds", "1 10", EINVAL}, 29 {"Negative nanoseconds", "1 10 -10", EINVAL}, 30 {"Nanoseconds > 1s", "1 10 1000000001", EINVAL}, 31 {"Unsupported CLOCK_REALTIME", "0 10 0", EINVAL}, 32 {"Mess on the second line", "1 10 0\na", EINVAL}, 33 {"Overflow kernel 64bit ns timer", "1 9223372036 0", ERANGE}, 34 {"Overflow kernel 64bit ns timer", "1 -9223372036 0", ERANGE}, 35}; 36 37static void verify_ns_clock(unsigned int n) 38{ 39 struct tcase *tc = &tcases[n]; 40 int fd, ret; 41 42 SAFE_UNSHARE(CLONE_NEWTIME); 43 44 fd = SAFE_OPEN("/proc/self/timens_offsets", O_WRONLY); 45 ret = write(fd, tc->offsets, strlen(tc->offsets)); 46 47 if (ret != -1) { 48 tst_res(TFAIL, "%s returned %i", tc->desc, ret); 49 return; 50 } 51 52 if (errno != tc->exp_err) { 53 tst_res(TFAIL | TERRNO, "%s should fail with %s, got:", 54 tc->desc, tst_strerrno(tc->exp_err)); 55 return; 56 } 57 58 tst_res(TPASS | TERRNO, "%s", tc->desc); 59} 60 61static struct tst_test test = { 62 .tcnt = ARRAY_SIZE(tcases), 63 .test = verify_ns_clock, 64 .needs_root = 1, 65 .needs_kconfigs = (const char *[]) { 66 "CONFIG_TIME_NS=y", 67 NULL 68 } 69}; 70