• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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