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