1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2014 Oracle and/or its affiliates. All Rights Reserved.
4f08c3bdfSopenharmony_ci * Copyright (c) 2019 FUJITSU LIMITED.
5f08c3bdfSopenharmony_ci *
6f08c3bdfSopenharmony_ci * Author: Stanislav Kholmanskikh <stanislav.kholmanskikh@oracle.com>
7f08c3bdfSopenharmony_ci */
8f08c3bdfSopenharmony_ci
9f08c3bdfSopenharmony_ci/*
10f08c3bdfSopenharmony_ci * Description:
11f08c3bdfSopenharmony_ci * Check various errnos for sched_setaffinity():
12f08c3bdfSopenharmony_ci * 1) EFAULT, if the supplied memory address is invalid.
13f08c3bdfSopenharmony_ci * 2) EINVAL, if the mask doesn't contain at least one permitted cpu.
14f08c3bdfSopenharmony_ci * 3) ESRCH, if the process whose id is pid could not be found.
15f08c3bdfSopenharmony_ci * 4) EPERM, if the calling process doesn't have appropriate privileges.
16f08c3bdfSopenharmony_ci */
17f08c3bdfSopenharmony_ci
18f08c3bdfSopenharmony_ci#define _GNU_SOURCE
19f08c3bdfSopenharmony_ci#include <errno.h>
20f08c3bdfSopenharmony_ci#include <pwd.h>
21f08c3bdfSopenharmony_ci#include <sched.h>
22f08c3bdfSopenharmony_ci#include <signal.h>
23f08c3bdfSopenharmony_ci#include <unistd.h>
24f08c3bdfSopenharmony_ci#include <stdlib.h>
25f08c3bdfSopenharmony_ci
26f08c3bdfSopenharmony_ci#include "tst_test.h"
27f08c3bdfSopenharmony_ci#include "tst_safe_macros.h"
28f08c3bdfSopenharmony_ci#include "lapi/cpuset.h"
29f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_cistatic cpu_set_t *mask, *emask, *fmask;
32f08c3bdfSopenharmony_cistatic size_t mask_size, emask_size;
33f08c3bdfSopenharmony_cistatic pid_t self_pid, privileged_pid, free_pid;
34f08c3bdfSopenharmony_cistatic struct passwd *ltpuser;
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_cistatic struct tcase {
37f08c3bdfSopenharmony_ci	pid_t *pid;
38f08c3bdfSopenharmony_ci	size_t *size;
39f08c3bdfSopenharmony_ci	cpu_set_t **mask;
40f08c3bdfSopenharmony_ci	int exp_errno;
41f08c3bdfSopenharmony_ci} tcases[] = {
42f08c3bdfSopenharmony_ci	{&self_pid, &mask_size, &fmask, EFAULT},
43f08c3bdfSopenharmony_ci	{&self_pid, &emask_size, &emask, EINVAL},
44f08c3bdfSopenharmony_ci	{&free_pid, &mask_size, &mask, ESRCH},
45f08c3bdfSopenharmony_ci	{&privileged_pid, &mask_size, &mask, EPERM},
46f08c3bdfSopenharmony_ci};
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_cistatic void kill_pid(void)
49f08c3bdfSopenharmony_ci{
50f08c3bdfSopenharmony_ci	SAFE_KILL(privileged_pid, SIGKILL);
51f08c3bdfSopenharmony_ci	SAFE_WAITPID(privileged_pid, NULL, 0);
52f08c3bdfSopenharmony_ci	SAFE_SETEUID(0);
53f08c3bdfSopenharmony_ci}
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_cistatic void verify_test(unsigned int n)
56f08c3bdfSopenharmony_ci{
57f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	if (tc->exp_errno == EPERM) {
60f08c3bdfSopenharmony_ci		privileged_pid = SAFE_FORK();
61f08c3bdfSopenharmony_ci		if (privileged_pid == 0) {
62f08c3bdfSopenharmony_ci			pause();
63f08c3bdfSopenharmony_ci			exit(0);
64f08c3bdfSopenharmony_ci		}
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_ci		SAFE_SETEUID(ltpuser->pw_uid);
67f08c3bdfSopenharmony_ci	}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_ci	TEST(tst_syscall(__NR_sched_setaffinity,
70f08c3bdfSopenharmony_ci			*tc->pid, *tc->size, *tc->mask));
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci	if (TST_RET != -1) {
73f08c3bdfSopenharmony_ci		tst_res(TFAIL, "sched_setaffinity() succeded unexpectedly");
74f08c3bdfSopenharmony_ci		kill_pid();
75f08c3bdfSopenharmony_ci		return;
76f08c3bdfSopenharmony_ci	}
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci	if (TST_ERR != tc->exp_errno) {
79f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO,
80f08c3bdfSopenharmony_ci			"sched_setaffinity() should fail with %s, got",
81f08c3bdfSopenharmony_ci			tst_strerrno(tc->exp_errno));
82f08c3bdfSopenharmony_ci	} else {
83f08c3bdfSopenharmony_ci		tst_res(TPASS | TTERRNO, "sched_setaffinity() failed");
84f08c3bdfSopenharmony_ci	}
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	if (tc->exp_errno == EPERM)
87f08c3bdfSopenharmony_ci		kill_pid();
88f08c3bdfSopenharmony_ci}
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_cistatic void setup(void)
91f08c3bdfSopenharmony_ci{
92f08c3bdfSopenharmony_ci	long ncpus;
93f08c3bdfSopenharmony_ci	ncpus = tst_ncpus_max();
94f08c3bdfSopenharmony_ci	fmask = tst_get_bad_addr(NULL);
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	mask = CPU_ALLOC(ncpus);
97f08c3bdfSopenharmony_ci	if (!mask)
98f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "CPU_ALLOC() failed");
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci	mask_size = CPU_ALLOC_SIZE(ncpus);
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci	if (sched_getaffinity(0, mask_size, mask) < 0)
103f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "sched_getaffinity() failed");
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	emask = CPU_ALLOC(ncpus + 1);
106f08c3bdfSopenharmony_ci	if (!emask)
107f08c3bdfSopenharmony_ci		tst_brk(TBROK | TERRNO, "CPU_ALLOC() failed");
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci	emask_size = CPU_ALLOC_SIZE(ncpus + 1);
110f08c3bdfSopenharmony_ci	CPU_ZERO_S(emask_size, emask);
111f08c3bdfSopenharmony_ci	CPU_SET_S(ncpus, emask_size, emask);
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_ci	ltpuser = SAFE_GETPWNAM("nobody");
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_ci	free_pid = tst_get_unused_pid();
116f08c3bdfSopenharmony_ci}
117f08c3bdfSopenharmony_ci
118f08c3bdfSopenharmony_cistatic void cleanup(void)
119f08c3bdfSopenharmony_ci{
120f08c3bdfSopenharmony_ci	if (mask)
121f08c3bdfSopenharmony_ci		CPU_FREE(mask);
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_ci	if (emask)
124f08c3bdfSopenharmony_ci		CPU_FREE(emask);
125f08c3bdfSopenharmony_ci}
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_cistatic struct tst_test test = {
128f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
129f08c3bdfSopenharmony_ci	.test = verify_test,
130f08c3bdfSopenharmony_ci	.setup = setup,
131f08c3bdfSopenharmony_ci	.cleanup = cleanup,
132f08c3bdfSopenharmony_ci	.needs_tmpdir = 1,
133f08c3bdfSopenharmony_ci	.forks_child = 1,
134f08c3bdfSopenharmony_ci	.needs_root = 1,
135f08c3bdfSopenharmony_ci};
136