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