• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 = &param[0]
45 	},
46 	{
47 		.pid = &zero_pid,
48 		.policy = SCHED_BATCH,
49 		.sched_param = &param[0]
50 	},
51 #ifdef SCHED_IDLE
52 	{
53 		.pid = &zero_pid,
54 		.policy = SCHED_IDLE,
55 		.sched_param = &param[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 	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 
setup(void)104 static 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, &param[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 
do_test(unsigned int i)144 static 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 
158 static 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