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 <sched.h>
21 #include <sys/time.h>
22 #include <sys/resource.h>
23 #include <sys/wait.h>
24 #include <stdlib.h>
25
26 #include "tst_test.h"
27
28 #define RLIMIT_NICE_NORMAL 20
29
30 static pid_t zero_pid;
31 static struct sched_param param[1] = { {0} };
32
33 struct test_case_t {
34 pid_t *pid;
35 int policy;
36 struct sched_param *sched_param;
37 int error;
38 };
39
40 struct 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
l_rlimit_show(const int type,struct rlimit * limit)60 static 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
l_rlimit_setup(const int type,struct rlimit * limit)69 static 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
verify_fn(unsigned int i)93 static void verify_fn(unsigned int i)
94 {
95 tst_res(TINFO,
96 "Verifying case[%d]: policy = %d, priority = %d",
97 i + 1, cases[i].policy, cases[i].sched_param->sched_priority);
98
99 TEST(sched_setscheduler(*cases[i].pid, cases[i].policy,
100 cases[i].sched_param));
101 if (TST_RET)
102 tst_res(TFAIL | TTERRNO, "case[%d] expected: %d, got: ",
103 i + 1, cases[i].error);
104 else
105 tst_res(TPASS, "case[%d] succeeded", i + 1);
106 }
107
setup(void)108 static void setup(void)
109 {
110 uid_t ruid, euid, suid;
111 struct rlimit limit;
112 struct passwd *pw;
113 uid_t nobody_uid;
114
115 pw = SAFE_GETPWNAM("nobody");
116 nobody_uid = pw->pw_uid;
117 l_rlimit_show(RLIMIT_NICE, &limit);
118
119 /*
120 * nice rlimit ranges from 1 to 40, mapping to real nice
121 * value from 19 to -20. We set it to 19, as the default priority
122 * of process with fair policy is 120, which will be translated
123 * into nice 20, we make this RLIMIT_NICE smaller than that, to
124 * verify the can_nice usage issue.
125 */
126 limit.rlim_cur = (RLIMIT_NICE_NORMAL - 1);
127 limit.rlim_max = (RLIMIT_NICE_NORMAL - 1);
128
129 l_rlimit_setup(RLIMIT_NICE, &limit);
130
131 tst_res(TINFO, "Setting init sched policy to SCHED_OTHER");
132 if (sched_setscheduler(0, SCHED_OTHER, ¶m[0]) != 0)
133 tst_res(TBROK | TERRNO,
134 "ERROR sched_setscheduler: (0, SCHED_OTHER, param)");
135
136 if (sched_getscheduler(0) != SCHED_OTHER)
137 tst_res(TBROK | TERRNO, "ERROR sched_setscheduler");
138
139 tst_res(TINFO, "Setting euid to nobody to drop privilege");
140
141 SAFE_SETEUID(nobody_uid);
142 SAFE_GETRESUID(&ruid, &euid, &suid);
143 if (euid != nobody_uid)
144 tst_brk(TBROK | TERRNO, "ERROR seteuid(nobody_uid)");
145 }
146
do_test(unsigned int i)147 static void do_test(unsigned int i)
148 {
149 int status = 0;
150 pid_t f_pid = SAFE_FORK();
151
152 if (f_pid == 0) {
153 tst_res(TINFO, "forked pid is %d", getpid());
154 verify_fn(i);
155 exit(0);
156 }
157
158 SAFE_WAIT(&status);
159 }
160
161 static struct tst_test test = {
162 .tcnt = ARRAY_SIZE(cases),
163 .test = do_test,
164 .setup = setup,
165 .needs_root = 1,
166 .forks_child = 1
167 };
168
169