1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2016 Linux Test Project. 4 */ 5 6/* 7 * A regression test for can_nice call usage in sched_setscheduler, 8 * introduced by kernel commit: 9 * d50dde5a (sched: Add new scheduler syscalls to support 10 * 11 * This was fixed by below commit: 12 * eaad4513 (sched: Fix __sched_setscheduler() nice test 13 * 14 */ 15 16#define _GNU_SOURCE 17#include <stdio.h> 18#include <errno.h> 19#include <pwd.h> 20#include <sys/time.h> 21#include <sys/resource.h> 22#include <sys/wait.h> 23#include <stdlib.h> 24 25#include "tst_test.h" 26#include "tst_sched.h" 27 28#define RLIMIT_NICE_NORMAL 20 29 30static pid_t zero_pid; 31static struct sched_param param[1] = { {0} }; 32 33struct test_case_t { 34 pid_t *pid; 35 int policy; 36 struct sched_param *sched_param; 37 int error; 38}; 39 40struct test_case_t cases[] = { 41 { 42 .pid = &zero_pid, 43 .policy = SCHED_OTHER, 44 .sched_param = ¶m[0] 45 }, 46 { 47 .pid = &zero_pid, 48 .policy = SCHED_BATCH, 49 .sched_param = ¶m[0] 50 }, 51#ifdef SCHED_IDLE 52 { 53 .pid = &zero_pid, 54 .policy = SCHED_IDLE, 55 .sched_param = ¶m[0] 56 } 57#endif 58}; 59 60static void l_rlimit_show(const int type, struct rlimit *limit) 61{ 62 SAFE_GETRLIMIT(type, limit); 63 tst_res(TINFO, 64 "rlimit rlim_cur=%lu", (unsigned long)(limit->rlim_cur)); 65 tst_res(TINFO, 66 "rlimit rlim_max=%lu", (unsigned long)(limit->rlim_max)); 67} 68 69static void l_rlimit_setup(const int type, struct rlimit *limit) 70{ 71 struct rlimit tmp_rlimit; 72 73 tst_res(TINFO, 74 "Setting rlim_cur to %lu", (unsigned long)(limit->rlim_cur)); 75 tst_res(TINFO, 76 "Setting rlim_max to %lu", (unsigned long)(limit->rlim_max)); 77 78 SAFE_SETRLIMIT(type, limit); 79 80 l_rlimit_show(RLIMIT_NICE, &tmp_rlimit); 81 82 if (tmp_rlimit.rlim_cur != limit->rlim_cur) 83 tst_brk(TBROK | TERRNO, "Expect rlim_cur = %lu, get %lu", 84 (unsigned long)(limit->rlim_cur), 85 (unsigned long)tmp_rlimit.rlim_cur); 86 87 if (tmp_rlimit.rlim_max != limit->rlim_max) 88 tst_brk(TBROK | TERRNO, "Expect rlim_max = %lu, get %lu", 89 (unsigned long)(limit->rlim_max), 90 (unsigned long)(tmp_rlimit.rlim_max)); 91} 92 93static void verify_fn(unsigned int i) 94{ 95 struct sched_variant *tv = &sched_variants[tst_variant]; 96 97 tst_res(TINFO, "Verifying case[%d]: policy = %d, priority = %d", 98 i + 1, cases[i].policy, cases[i].sched_param->sched_priority); 99 100 TST_EXP_PASS(tv->sched_setscheduler(*cases[i].pid, cases[i].policy, 101 cases[i].sched_param)); 102} 103 104static void setup(void) 105{ 106 struct sched_variant *tv = &sched_variants[tst_variant]; 107 uid_t ruid, euid, suid; 108 struct rlimit limit; 109 struct passwd *pw; 110 uid_t nobody_uid; 111 112 tst_res(TINFO, "Testing %s variant", tv->desc); 113 114 pw = SAFE_GETPWNAM("nobody"); 115 nobody_uid = pw->pw_uid; 116 l_rlimit_show(RLIMIT_NICE, &limit); 117 118 /* 119 * nice rlimit ranges from 1 to 40, mapping to real nice 120 * value from 19 to -20. We set it to 19, as the default priority 121 * of process with fair policy is 120, which will be translated 122 * into nice 20, we make this RLIMIT_NICE smaller than that, to 123 * verify the can_nice usage issue. 124 */ 125 limit.rlim_cur = (RLIMIT_NICE_NORMAL - 1); 126 limit.rlim_max = (RLIMIT_NICE_NORMAL - 1); 127 128 l_rlimit_setup(RLIMIT_NICE, &limit); 129 130 tst_res(TINFO, "Setting init sched policy to SCHED_OTHER"); 131 if (tv->sched_setscheduler(0, SCHED_OTHER, ¶m[0])) 132 tst_brk(TBROK | TERRNO, "sched_setscheduler(0, SCHED_OTHER, 0)"); 133 if (tv->sched_getscheduler(0) != SCHED_OTHER) 134 tst_brk(TBROK | TERRNO, "sched_getscheduler(0) != SCHED_OTHER"); 135 136 tst_res(TINFO, "Setting euid to nobody to drop privilege"); 137 138 SAFE_SETEUID(nobody_uid); 139 SAFE_GETRESUID(&ruid, &euid, &suid); 140 if (euid != nobody_uid) 141 tst_brk(TBROK | TERRNO, "ERROR seteuid(nobody_uid)"); 142} 143 144static void do_test(unsigned int i) 145{ 146 int status = 0; 147 pid_t f_pid = SAFE_FORK(); 148 149 if (f_pid == 0) { 150 tst_res(TINFO, "forked pid is %d", getpid()); 151 verify_fn(i); 152 exit(0); 153 } 154 155 SAFE_WAIT(&status); 156} 157 158static struct tst_test test = { 159 .test_variants = ARRAY_SIZE(sched_variants), 160 .tcnt = ARRAY_SIZE(cases), 161 .test = do_test, 162 .setup = setup, 163 .needs_root = 1, 164 .forks_child = 1 165}; 166 167