Home | History | Annotate | Download | only in sched_setaffinity
      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