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