• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it would 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  * This test verifies sched_setaffinity(2) for all error conditions
20  * to occur correctly.
21  *
22  * sched_setaffinity() returns -1 and sets the error code to:
23  *
24  * 1) EFAULT, if the supplied memory address is invalid
25  * 2) EINVAL, if the mask doesn't contain at least one
26  *    permitted cpu
27  * 3) ESRCH, if the process whose id is pid could not
28  *    be found
29  * 4) EPERM, if the calling process doesn't have appropriate
30  *    privileges
31  */
32 
33 #define _GNU_SOURCE
34 #include <errno.h>
35 #include <pwd.h>
36 #include <sched.h>
37 #include <signal.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include "test.h"
42 #include "safe_macros.h"
43 #include "lapi/cpuset.h"
44 #include "lapi/syscalls.h"
45 
46 char *TCID = "sched_setaffinity01";
47 
48 #define PID_MAX_PATH "/proc/sys/kernel/pid_max"
49 
50 static cpu_set_t *mask, *emask;
51 static cpu_set_t *fmask = (void *)-1;
52 static size_t mask_size, emask_size;
53 static pid_t self_pid, privileged_pid, free_pid;
54 static uid_t uid;
55 static const char nobody_uid[] = "nobody";
56 static struct passwd *ltpuser;
57 static long ncpus;
58 
59 static struct test_case_t {
60 	pid_t *pid;
61 	size_t *mask_size;
62 	cpu_set_t **mask;
63 	int exp_errno;
64 } test_cases[] = {
65 	{&self_pid, &mask_size, &fmask, EFAULT},
66 	{&self_pid, &emask_size, &emask, EINVAL},
67 	{&free_pid, &mask_size, &mask, ESRCH},
68 	{&privileged_pid, &mask_size, &mask, EPERM},
69 };
70 
71 int TST_TOTAL = ARRAY_SIZE(test_cases);
72 
cleanup(void)73 static void cleanup(void)
74 {
75 	if (mask != NULL) {
76 		CPU_FREE(mask);
77 		mask = NULL;
78 	}
79 
80 	if (emask != NULL) {
81 		CPU_FREE(emask);
82 		emask = NULL;
83 	}
84 
85 	SAFE_SETEUID(NULL, uid);
86 
87 	if (privileged_pid > 0) {
88 		kill(privileged_pid, SIGKILL);
89 		waitpid(privileged_pid, NULL, 0);
90 		privileged_pid = 0;
91 	}
92 }
93 
setup(void)94 static void setup(void)
95 {
96 	tst_require_root();
97 	uid = geteuid();
98 	ncpus = tst_ncpus_max();
99 
100 	/* Current mask */
101 	mask = CPU_ALLOC(ncpus);
102 	if (mask == NULL)
103 		tst_brkm(TBROK | TERRNO, cleanup, "CPU_ALLOC(%ld) failed",
104 			ncpus);
105 	mask_size = CPU_ALLOC_SIZE(ncpus);
106 	if (sched_getaffinity(0, mask_size, mask) < 0)
107 		tst_brkm(TBROK | TERRNO, cleanup, "sched_getaffinity() failed");
108 
109 	/* Mask with one more cpu than available on the system */
110 	emask = CPU_ALLOC(ncpus + 1);
111 	if (emask == NULL)
112 		tst_brkm(TBROK | TERRNO, cleanup, "CPU_ALLOC(%ld) failed",
113 			ncpus + 1);
114 	emask_size = CPU_ALLOC_SIZE(ncpus + 1);
115 	CPU_ZERO_S(emask_size, emask);
116 	CPU_SET_S(ncpus, emask_size, emask);
117 
118 	privileged_pid = tst_fork();
119 	if (privileged_pid == 0) {
120 		pause();
121 
122 		exit(0);
123 	} else if (privileged_pid < 0) {
124 		tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
125 	}
126 
127 	/* Dropping the root privileges */
128 	ltpuser = getpwnam(nobody_uid);
129 	if (ltpuser == NULL)
130 		tst_brkm(TBROK | TERRNO, cleanup,
131 			"getpwnam failed for user id %s", nobody_uid);
132 
133 	SAFE_SETEUID(cleanup, ltpuser->pw_uid);
134 
135 	/* this pid is not used by the OS */
136 	free_pid = tst_get_unused_pid(cleanup);
137 }
138 
main(int argc,char * argv[])139 int main(int argc, char *argv[])
140 {
141 	int lc;
142 	int i;
143 
144 	tst_parse_opts(argc, argv, NULL, NULL);
145 
146 	setup();
147 
148 	for (lc = 0; TEST_LOOPING(lc); lc++) {
149 		tst_count = 0;
150 		for (i = 0; i < TST_TOTAL; i++) {
151 			/* Avoid calling glibc wrapper function, as it may
152 			 * try to read/validate data in cpu mask. This test
153 			 * is passing invalid pointer on purpose. */
154 			TEST(ltp_syscall(__NR_sched_setaffinity,
155 				*(test_cases[i].pid),
156 				*(test_cases[i].mask_size),
157 				*(test_cases[i].mask)));
158 
159 			if (TEST_RETURN != -1)
160 				tst_resm(TFAIL,
161 					"sched_setaffinity() unexpectedly succeded");
162 
163 			if (TEST_ERRNO == test_cases[i].exp_errno) {
164 				tst_resm(TPASS, "expected failure with '%s'",
165 					strerror(test_cases[i].exp_errno));
166 			} else {
167 				tst_resm(TFAIL,
168 					"call returned '%s', expected - '%s'",
169 					strerror(TEST_ERRNO),
170 					strerror(test_cases[i].exp_errno));
171 			}
172 		}
173 	}
174 
175 	cleanup();
176 	tst_exit();
177 }
178