blob: 435d6265f56711affc0fb38af15e7362793a2185 [file] [log] [blame]
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it would be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This test verifies sched_setaffinity(2) for all error conditions
* to occur correctly.
*
* sched_setaffinity() returns -1 and sets the error code to:
*
* 1) EFAULT, if the supplied memory address is invalid
* 2) EINVAL, if the mask doesn't contain at least one
* permitted cpu
* 3) ESRCH, if the process whose id is pid could not
* be found
* 4) EPERM, if the calling process doesn't have appropriate
* privileges
*/
#define _GNU_SOURCE
#include <errno.h>
#include <pwd.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "test.h"
#include "safe_macros.h"
#include "sched_setaffinity.h"
#include "linux_syscall_numbers.h"
char *TCID = "sched_setaffinity01";
#define PID_MAX_PATH "/proc/sys/kernel/pid_max"
static cpu_set_t *mask, *emask;
static cpu_set_t *fmask = (void *)-1;
static size_t mask_size, emask_size;
static pid_t self_pid, privileged_pid, free_pid;
static uid_t uid;
static const char nobody_uid[] = "nobody";
static struct passwd *ltpuser;
static long ncpus;
static struct test_case_t {
pid_t *pid;
size_t *mask_size;
cpu_set_t **mask;
int exp_errno;
} test_cases[] = {
{&self_pid, &mask_size, &fmask, EFAULT},
{&self_pid, &emask_size, &emask, EINVAL},
{&free_pid, &mask_size, &mask, ESRCH},
{&privileged_pid, &mask_size, &mask, EPERM},
};
int TST_TOTAL = ARRAY_SIZE(test_cases);
static void cleanup(void)
{
if (mask != NULL) {
CPU_FREE(mask);
mask = NULL;
}
if (emask != NULL) {
CPU_FREE(emask);
emask = NULL;
}
SAFE_SETEUID(NULL, uid);
if (privileged_pid != 0) {
kill(privileged_pid, SIGKILL);
waitpid(privileged_pid, NULL, 0);
privileged_pid = 0;
}
}
static void setup(void)
{
tst_require_root(NULL);
uid = geteuid();
ncpus = tst_ncpus_max();
/* Current mask */
mask = CPU_ALLOC(ncpus);
if (mask == NULL)
tst_brkm(TBROK | TERRNO, cleanup, "CPU_ALLOC(%ld) failed",
ncpus);
mask_size = CPU_ALLOC_SIZE(ncpus);
if (sched_getaffinity(0, mask_size, mask) < 0)
tst_brkm(TBROK | TERRNO, cleanup, "sched_getaffinity() failed");
/* Mask with one more cpu than available on the system */
emask = CPU_ALLOC(ncpus + 1);
if (emask == NULL)
tst_brkm(TBROK | TERRNO, cleanup, "CPU_ALLOC(%ld) failed",
ncpus + 1);
emask_size = CPU_ALLOC_SIZE(ncpus + 1);
CPU_ZERO_S(emask_size, emask);
CPU_SET_S(ncpus, emask_size, emask);
privileged_pid = tst_fork();
if (privileged_pid == 0) {
pause();
exit(0);
} else if (privileged_pid < 0) {
tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
}
/* Dropping the root privileges */
ltpuser = getpwnam(nobody_uid);
if (ltpuser == NULL)
tst_brkm(TBROK | TERRNO, cleanup,
"getpwnam failed for user id %s", nobody_uid);
SAFE_SETEUID(cleanup, ltpuser->pw_uid);
/* this pid is not used by the OS */
free_pid = tst_get_unused_pid(cleanup);
}
int main(int argc, char *argv[])
{
const char *msg;
int lc;
int i;
msg = parse_opts(argc, argv, NULL, NULL);
if (msg != NULL)
tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
setup();
for (lc = 0; TEST_LOOPING(lc); lc++) {
tst_count = 0;
for (i = 0; i < TST_TOTAL; i++) {
/* Avoid calling glibc wrapper function, as it may
* try to read/validate data in cpu mask. This test
* is passing invalid pointer on purpose. */
TEST(ltp_syscall(__NR_sched_setaffinity,
*(test_cases[i].pid),
*(test_cases[i].mask_size),
*(test_cases[i].mask)));
if (TEST_RETURN != -1)
tst_resm(TFAIL,
"sched_setaffinity() unexpectedly succeded");
if (TEST_ERRNO == test_cases[i].exp_errno) {
tst_resm(TPASS, "expected failure with '%s'",
strerror(test_cases[i].exp_errno));
} else {
tst_resm(TFAIL,
"call returned '%s', expected - '%s'",
strerror(TEST_ERRNO),
strerror(test_cases[i].exp_errno));
}
}
}
cleanup();
tst_exit();
}