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 "sched_setaffinity.h" 44 #include "linux_syscall_numbers.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 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 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 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