• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Linux Test Project.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * A regression test for can_nice call usage in sched_setscheduler,
20  * introduced by kernel commit:
21  *    d50dde5a (sched: Add new scheduler syscalls to support
22  *
23  * This was fixed by below commit:
24  *    eaad4513 (sched: Fix __sched_setscheduler() nice test
25  *
26  */
27 
28 #define _GNU_SOURCE
29 #include <stdio.h>
30 #include <errno.h>
31 #include <pwd.h>
32 #include <sched.h>
33 #include <sys/time.h>
34 #include <sys/resource.h>
35 #include <sys/wait.h>
36 #include <stdlib.h>
37 
38 #include "tst_test.h"
39 
40 #define RLIMIT_NICE_NORMAL 20
41 
42 static pid_t zero_pid;
43 static struct sched_param param[1] = { {0} };
44 
45 struct test_case_t {
46 	pid_t *pid;
47 	int policy;
48 	struct sched_param *sched_param;
49 	int error;
50 };
51 
52 struct test_case_t cases[] = {
53 	{
54 		.pid = &zero_pid,
55 		.policy = SCHED_OTHER,
56 		.sched_param = &param[0]
57 	},
58 	{
59 		.pid = &zero_pid,
60 		.policy = SCHED_BATCH,
61 		.sched_param = &param[0]
62 	},
63 #ifdef SCHED_IDLE
64 	{
65 		.pid = &zero_pid,
66 		.policy = SCHED_IDLE,
67 		.sched_param = &param[0]
68 	}
69 #endif
70 };
71 
l_rlimit_show(const int type,struct rlimit * limit)72 static void l_rlimit_show(const int type, struct rlimit *limit)
73 {
74 	SAFE_GETRLIMIT(type, limit);
75 	tst_res(TINFO,
76 		"rlimit rlim_cur=%lu", (unsigned long)(limit->rlim_cur));
77 	tst_res(TINFO,
78 		"rlimit rlim_max=%lu", (unsigned long)(limit->rlim_max));
79 }
80 
l_rlimit_setup(const int type,struct rlimit * limit)81 static void l_rlimit_setup(const int type, struct rlimit *limit)
82 {
83 	struct rlimit tmp_rlimit;
84 
85 	tst_res(TINFO,
86 		"Setting rlim_cur to %lu", (unsigned long)(limit->rlim_cur));
87 	tst_res(TINFO,
88 		"Setting rlim_max to %lu", (unsigned long)(limit->rlim_max));
89 
90 	SAFE_SETRLIMIT(type, limit);
91 
92 	l_rlimit_show(RLIMIT_NICE, &tmp_rlimit);
93 
94 	if (tmp_rlimit.rlim_cur != limit->rlim_cur)
95 		tst_brk(TBROK | TERRNO, "Expect rlim_cur = %lu, get %lu",
96 				(unsigned long)(limit->rlim_cur),
97 				(unsigned long)tmp_rlimit.rlim_cur);
98 
99 	if (tmp_rlimit.rlim_max != limit->rlim_max)
100 		tst_brk(TBROK | TERRNO, "Expect rlim_max = %lu, get %lu",
101 				(unsigned long)(limit->rlim_max),
102 				(unsigned long)(tmp_rlimit.rlim_max));
103 }
104 
verify_fn(unsigned int i)105 static void verify_fn(unsigned int i)
106 {
107 	tst_res(TINFO,
108 		"Verifying case[%d]: policy = %d, priority = %d",
109 		i + 1, cases[i].policy, cases[i].sched_param->sched_priority);
110 
111 	TEST(sched_setscheduler(*cases[i].pid, cases[i].policy,
112 					cases[i].sched_param));
113 	if (TEST_RETURN)
114 		tst_res(TFAIL | TTERRNO, "case[%d] expected: %d, got: ",
115 			i + 1, cases[i].error);
116 	else
117 		tst_res(TPASS, "case[%d] succeeded", i + 1);
118 }
119 
setup(void)120 static void setup(void)
121 {
122 	uid_t ruid, euid, suid;
123 	struct rlimit limit;
124 	struct passwd *pw;
125 	uid_t nobody_uid;
126 
127 	pw = SAFE_GETPWNAM("nobody");
128 	nobody_uid = pw->pw_uid;
129 	l_rlimit_show(RLIMIT_NICE, &limit);
130 
131 	/*
132 	* nice rlimit ranges from 1 to 40, mapping to real nice
133 	* value from 19 to -20. We set it to 19, as the default priority
134 	* of process with fair policy is 120, which will be translated
135 	* into nice 20, we make this RLIMIT_NICE smaller than that, to
136 	* verify the can_nice usage issue.
137 	*/
138 	limit.rlim_cur = (RLIMIT_NICE_NORMAL - 1);
139 	limit.rlim_max = (RLIMIT_NICE_NORMAL - 1);
140 
141 	l_rlimit_setup(RLIMIT_NICE, &limit);
142 
143 	tst_res(TINFO, "Setting init sched policy to SCHED_OTHER");
144 	if (sched_setscheduler(0, SCHED_OTHER, &param[0]) != 0)
145 		tst_res(TBROK | TERRNO,
146 			 "ERROR sched_setscheduler: (0, SCHED_OTHER, param)");
147 
148 	if (sched_getscheduler(0) != SCHED_OTHER)
149 		tst_res(TBROK | TERRNO, "ERROR sched_setscheduler");
150 
151 	tst_res(TINFO, "Setting euid to nobody to drop privilege");
152 
153 	SAFE_SETEUID(nobody_uid);
154 	SAFE_GETRESUID(&ruid, &euid, &suid);
155 	if (euid != nobody_uid)
156 		tst_brk(TBROK | TERRNO, "ERROR seteuid(nobody_uid)");
157 }
158 
do_test(unsigned int i)159 static void do_test(unsigned int i)
160 {
161 	int status = 0;
162 	pid_t f_pid = SAFE_FORK();
163 
164 	if (f_pid == 0) {
165 		tst_res(TINFO, "forked pid is %d", getpid());
166 		verify_fn(i);
167 		exit(0);
168 	}
169 
170 	SAFE_WAIT(&status);
171 }
172 
173 static struct tst_test test = {
174 	.tid = "sched_setscheduler03",
175 	.tcnt = ARRAY_SIZE(cases),
176 	.test = do_test,
177 	.setup = setup,
178 	.needs_root = 1,
179 	.forks_child = 1
180 };
181 
182