1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) Linux Test Project, 2012
4f08c3bdfSopenharmony_ci * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*\
8f08c3bdfSopenharmony_ci * [Description]
9f08c3bdfSopenharmony_ci *
10f08c3bdfSopenharmony_ci * Test errno codes in process_vm_readv and process_vm_writev syscalls.
11f08c3bdfSopenharmony_ci */
12f08c3bdfSopenharmony_ci
13f08c3bdfSopenharmony_ci#include <pwd.h>
14f08c3bdfSopenharmony_ci#include <stdlib.h>
15f08c3bdfSopenharmony_ci#include "tst_test.h"
16f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
17f08c3bdfSopenharmony_ci
18f08c3bdfSopenharmony_cistruct process_vm_params {
19f08c3bdfSopenharmony_ci	int len;
20f08c3bdfSopenharmony_ci	char *ldummy;
21f08c3bdfSopenharmony_ci	char *rdummy;
22f08c3bdfSopenharmony_ci	pid_t pid;
23f08c3bdfSopenharmony_ci	struct iovec *lvec;
24f08c3bdfSopenharmony_ci	unsigned long liovcnt;
25f08c3bdfSopenharmony_ci	struct iovec *rvec;
26f08c3bdfSopenharmony_ci	unsigned long riovcnt;
27f08c3bdfSopenharmony_ci	unsigned long flags;
28f08c3bdfSopenharmony_ci};
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_cistatic char *str_read;
31f08c3bdfSopenharmony_cistatic void (*test_params)(struct process_vm_params *params);
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic struct process_vm_params *alloc_params(void)
34f08c3bdfSopenharmony_ci{
35f08c3bdfSopenharmony_ci	struct process_vm_params *sane_params;
36f08c3bdfSopenharmony_ci	int len;
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_ci	len = getpagesize();
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci	sane_params = SAFE_MALLOC(sizeof(struct process_vm_params));
41f08c3bdfSopenharmony_ci	sane_params->len = len;
42f08c3bdfSopenharmony_ci	sane_params->ldummy = SAFE_MALLOC(len);
43f08c3bdfSopenharmony_ci	sane_params->rdummy = SAFE_MALLOC(len);
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci	sane_params->lvec = SAFE_MALLOC(sizeof(struct process_vm_params));
46f08c3bdfSopenharmony_ci	sane_params->lvec->iov_base = sane_params->ldummy;
47f08c3bdfSopenharmony_ci	sane_params->lvec->iov_len = len;
48f08c3bdfSopenharmony_ci	sane_params->liovcnt = 1;
49f08c3bdfSopenharmony_ci
50f08c3bdfSopenharmony_ci	sane_params->rvec = SAFE_MALLOC(sizeof(struct process_vm_params));
51f08c3bdfSopenharmony_ci	sane_params->rvec->iov_base = sane_params->rdummy;
52f08c3bdfSopenharmony_ci	sane_params->rvec->iov_len = len;
53f08c3bdfSopenharmony_ci	sane_params->riovcnt = 1;
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	sane_params->flags = 0;
56f08c3bdfSopenharmony_ci	sane_params->pid = getpid();
57f08c3bdfSopenharmony_ci
58f08c3bdfSopenharmony_ci	return sane_params;
59f08c3bdfSopenharmony_ci}
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_cistatic void free_params(struct process_vm_params *params)
62f08c3bdfSopenharmony_ci{
63f08c3bdfSopenharmony_ci	if (params) {
64f08c3bdfSopenharmony_ci		free(params->ldummy);
65f08c3bdfSopenharmony_ci		free(params->rdummy);
66f08c3bdfSopenharmony_ci		free(params->lvec);
67f08c3bdfSopenharmony_ci		free(params->rvec);
68f08c3bdfSopenharmony_ci		free(params);
69f08c3bdfSopenharmony_ci	}
70f08c3bdfSopenharmony_ci}
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_cistatic void test_readv(struct process_vm_params *params)
73f08c3bdfSopenharmony_ci{
74f08c3bdfSopenharmony_ci	TEST(tst_syscall(__NR_process_vm_readv,
75f08c3bdfSopenharmony_ci		params->pid,
76f08c3bdfSopenharmony_ci		params->lvec, params->liovcnt,
77f08c3bdfSopenharmony_ci		params->rvec, params->riovcnt,
78f08c3bdfSopenharmony_ci		params->flags));
79f08c3bdfSopenharmony_ci}
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_cistatic void test_writev(struct process_vm_params *params)
82f08c3bdfSopenharmony_ci{
83f08c3bdfSopenharmony_ci	TEST(tst_syscall(__NR_process_vm_writev,
84f08c3bdfSopenharmony_ci		params->pid,
85f08c3bdfSopenharmony_ci		params->lvec, params->liovcnt,
86f08c3bdfSopenharmony_ci		params->rvec, params->riovcnt,
87f08c3bdfSopenharmony_ci		params->flags));
88f08c3bdfSopenharmony_ci}
89f08c3bdfSopenharmony_ci
90f08c3bdfSopenharmony_cistatic void check_errno(long expected_errno)
91f08c3bdfSopenharmony_ci{
92f08c3bdfSopenharmony_ci	if (TST_ERR == expected_errno)
93f08c3bdfSopenharmony_ci		tst_res(TPASS | TTERRNO, "expected failure");
94f08c3bdfSopenharmony_ci	else if (TST_ERR == 0)
95f08c3bdfSopenharmony_ci		tst_res(TFAIL, "call succeeded unexpectedly");
96f08c3bdfSopenharmony_ci	else
97f08c3bdfSopenharmony_ci		tst_res(TFAIL | TTERRNO, "unexpected failure - "
98f08c3bdfSopenharmony_ci			"expected = %ld : %s, actual",
99f08c3bdfSopenharmony_ci			expected_errno, strerror(expected_errno));
100f08c3bdfSopenharmony_ci}
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_cistatic void test_sane_params(void)
103f08c3bdfSopenharmony_ci{
104f08c3bdfSopenharmony_ci	struct process_vm_params *sane_params;
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing sane parameters");
107f08c3bdfSopenharmony_ci
108f08c3bdfSopenharmony_ci	sane_params = alloc_params();
109f08c3bdfSopenharmony_ci	test_params(sane_params);
110f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, sane_params->len);
111f08c3bdfSopenharmony_ci	free_params(sane_params);
112f08c3bdfSopenharmony_ci}
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_cistatic void test_flags(void)
115f08c3bdfSopenharmony_ci{
116f08c3bdfSopenharmony_ci	struct process_vm_params *params;
117f08c3bdfSopenharmony_ci	long flags[] = { -INT_MAX, -1, 1, INT_MAX, 0 };
118f08c3bdfSopenharmony_ci	int flags_size = ARRAY_SIZE(flags) / sizeof(flags[0]);
119f08c3bdfSopenharmony_ci	int i;
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_ci	params = alloc_params();
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_ci	for (i = 0; i < flags_size; i++) {
124f08c3bdfSopenharmony_ci		params->flags = flags[i];
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_ci		tst_res(TINFO, "Testing flags=%ld", flags[i]);
127f08c3bdfSopenharmony_ci		test_params(params);
128f08c3bdfSopenharmony_ci
129f08c3bdfSopenharmony_ci		/* atm. only flags == 0 is allowed, everything else
130f08c3bdfSopenharmony_ci		 * should fail with EINVAL
131f08c3bdfSopenharmony_ci		 */
132f08c3bdfSopenharmony_ci		if (flags[i] != 0) {
133f08c3bdfSopenharmony_ci			TST_EXP_EQ_LI(TST_RET, -1);
134f08c3bdfSopenharmony_ci			check_errno(EINVAL);
135f08c3bdfSopenharmony_ci		} else {
136f08c3bdfSopenharmony_ci			TST_EXP_EQ_LI(TST_RET, params->len);
137f08c3bdfSopenharmony_ci		}
138f08c3bdfSopenharmony_ci	}
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci	free_params(params);
141f08c3bdfSopenharmony_ci}
142f08c3bdfSopenharmony_ci
143f08c3bdfSopenharmony_cistatic void test_iov_len_overflow(void)
144f08c3bdfSopenharmony_ci{
145f08c3bdfSopenharmony_ci	struct process_vm_params *params;
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing iov_len = -1");
148f08c3bdfSopenharmony_ci
149f08c3bdfSopenharmony_ci	params = alloc_params();
150f08c3bdfSopenharmony_ci	params->lvec->iov_len = -1;
151f08c3bdfSopenharmony_ci	params->rvec->iov_len = -1;
152f08c3bdfSopenharmony_ci	test_params(params);
153f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
154f08c3bdfSopenharmony_ci	check_errno(EINVAL);
155f08c3bdfSopenharmony_ci	free_params(params);
156f08c3bdfSopenharmony_ci}
157f08c3bdfSopenharmony_ci
158f08c3bdfSopenharmony_cistatic void test_iov_invalid(void)
159f08c3bdfSopenharmony_ci{
160f08c3bdfSopenharmony_ci	struct process_vm_params *sane_params;
161f08c3bdfSopenharmony_ci	struct process_vm_params params_copy;
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci	sane_params = alloc_params();
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing lvec->iov_base = -1");
166f08c3bdfSopenharmony_ci	params_copy = *sane_params;
167f08c3bdfSopenharmony_ci	params_copy.lvec->iov_base = (void *)-1;
168f08c3bdfSopenharmony_ci	test_params(&params_copy);
169f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
170f08c3bdfSopenharmony_ci	check_errno(EFAULT);
171f08c3bdfSopenharmony_ci
172f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing rvec->iov_base = -1");
173f08c3bdfSopenharmony_ci	params_copy = *sane_params;
174f08c3bdfSopenharmony_ci	params_copy.rvec->iov_base = (void *)-1;
175f08c3bdfSopenharmony_ci	test_params(&params_copy);
176f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
177f08c3bdfSopenharmony_ci	check_errno(EFAULT);
178f08c3bdfSopenharmony_ci
179f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing lvec = -1");
180f08c3bdfSopenharmony_ci	params_copy = *sane_params;
181f08c3bdfSopenharmony_ci	params_copy.lvec = (void *)-1;
182f08c3bdfSopenharmony_ci	test_params(&params_copy);
183f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
184f08c3bdfSopenharmony_ci	check_errno(EFAULT);
185f08c3bdfSopenharmony_ci
186f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing rvec = -1");
187f08c3bdfSopenharmony_ci	params_copy = *sane_params;
188f08c3bdfSopenharmony_ci	params_copy.rvec = (void *)-1;
189f08c3bdfSopenharmony_ci	test_params(&params_copy);
190f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
191f08c3bdfSopenharmony_ci	check_errno(EFAULT);
192f08c3bdfSopenharmony_ci
193f08c3bdfSopenharmony_ci	free_params(sane_params);
194f08c3bdfSopenharmony_ci}
195f08c3bdfSopenharmony_ci
196f08c3bdfSopenharmony_cistatic void test_invalid_pid(void)
197f08c3bdfSopenharmony_ci{
198f08c3bdfSopenharmony_ci	pid_t invalid_pid = -1;
199f08c3bdfSopenharmony_ci	struct process_vm_params *params;
200f08c3bdfSopenharmony_ci	struct process_vm_params params_copy;
201f08c3bdfSopenharmony_ci
202f08c3bdfSopenharmony_ci	params = alloc_params();
203f08c3bdfSopenharmony_ci
204f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing invalid PID");
205f08c3bdfSopenharmony_ci	params_copy = *params;
206f08c3bdfSopenharmony_ci	params_copy.pid = invalid_pid;
207f08c3bdfSopenharmony_ci	test_params(&params_copy);
208f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
209f08c3bdfSopenharmony_ci	check_errno(ESRCH);
210f08c3bdfSopenharmony_ci
211f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing unused PID");
212f08c3bdfSopenharmony_ci	params_copy = *params;
213f08c3bdfSopenharmony_ci	invalid_pid = tst_get_unused_pid();
214f08c3bdfSopenharmony_ci	params_copy.pid = invalid_pid;
215f08c3bdfSopenharmony_ci	test_params(&params_copy);
216f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
217f08c3bdfSopenharmony_ci	check_errno(ESRCH);
218f08c3bdfSopenharmony_ci
219f08c3bdfSopenharmony_ci	free_params(params);
220f08c3bdfSopenharmony_ci}
221f08c3bdfSopenharmony_ci
222f08c3bdfSopenharmony_cistatic void test_invalid_perm(void)
223f08c3bdfSopenharmony_ci{
224f08c3bdfSopenharmony_ci	char nobody_uid[] = "nobody";
225f08c3bdfSopenharmony_ci	struct passwd *ltpuser;
226f08c3bdfSopenharmony_ci	struct process_vm_params *params;
227f08c3bdfSopenharmony_ci	pid_t child_pid;
228f08c3bdfSopenharmony_ci	pid_t parent_pid;
229f08c3bdfSopenharmony_ci
230f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing invalid permissions on given PID");
231f08c3bdfSopenharmony_ci
232f08c3bdfSopenharmony_ci	parent_pid = getpid();
233f08c3bdfSopenharmony_ci	child_pid = SAFE_FORK();
234f08c3bdfSopenharmony_ci	if (!child_pid) {
235f08c3bdfSopenharmony_ci		ltpuser = SAFE_GETPWNAM(nobody_uid);
236f08c3bdfSopenharmony_ci		SAFE_SETUID(ltpuser->pw_uid);
237f08c3bdfSopenharmony_ci
238f08c3bdfSopenharmony_ci		params = alloc_params();
239f08c3bdfSopenharmony_ci		params->pid = parent_pid;
240f08c3bdfSopenharmony_ci		test_params(params);
241f08c3bdfSopenharmony_ci		TST_EXP_EQ_LI(TST_RET, -1);
242f08c3bdfSopenharmony_ci		check_errno(EPERM);
243f08c3bdfSopenharmony_ci		free_params(params);
244f08c3bdfSopenharmony_ci		return;
245f08c3bdfSopenharmony_ci	}
246f08c3bdfSopenharmony_ci
247f08c3bdfSopenharmony_ci	/* collect result from child  before the next test, otherwise
248f08c3bdfSopenharmony_ci	 * TFAIL/TPASS messages will arrive asynchronously
249f08c3bdfSopenharmony_ci	 */
250f08c3bdfSopenharmony_ci	tst_reap_children();
251f08c3bdfSopenharmony_ci}
252f08c3bdfSopenharmony_ci
253f08c3bdfSopenharmony_cistatic void test_invalid_protection(void)
254f08c3bdfSopenharmony_ci{
255f08c3bdfSopenharmony_ci	struct process_vm_params *sane_params;
256f08c3bdfSopenharmony_ci	struct process_vm_params params_copy;
257f08c3bdfSopenharmony_ci	void *data;
258f08c3bdfSopenharmony_ci	int len;
259f08c3bdfSopenharmony_ci
260f08c3bdfSopenharmony_ci	len = getpagesize();
261f08c3bdfSopenharmony_ci	sane_params = alloc_params();
262f08c3bdfSopenharmony_ci	data = SAFE_MMAP(NULL, len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
263f08c3bdfSopenharmony_ci
264f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing data with invalid protection (lvec)");
265f08c3bdfSopenharmony_ci	params_copy = *sane_params;
266f08c3bdfSopenharmony_ci	params_copy.lvec->iov_base = data;
267f08c3bdfSopenharmony_ci	test_params(&params_copy);
268f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
269f08c3bdfSopenharmony_ci	check_errno(EFAULT);
270f08c3bdfSopenharmony_ci
271f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing data with invalid protection (rvec)");
272f08c3bdfSopenharmony_ci	params_copy = *sane_params;
273f08c3bdfSopenharmony_ci	params_copy.rvec->iov_base = data;
274f08c3bdfSopenharmony_ci	test_params(&params_copy);
275f08c3bdfSopenharmony_ci	TST_EXP_EQ_LI(TST_RET, -1);
276f08c3bdfSopenharmony_ci	check_errno(EFAULT);
277f08c3bdfSopenharmony_ci
278f08c3bdfSopenharmony_ci	SAFE_MUNMAP(data, len);
279f08c3bdfSopenharmony_ci	free_params(sane_params);
280f08c3bdfSopenharmony_ci}
281f08c3bdfSopenharmony_ci
282f08c3bdfSopenharmony_cistatic void run(void)
283f08c3bdfSopenharmony_ci{
284f08c3bdfSopenharmony_ci	test_sane_params();
285f08c3bdfSopenharmony_ci	test_flags();
286f08c3bdfSopenharmony_ci	test_iov_len_overflow();
287f08c3bdfSopenharmony_ci	test_iov_invalid();
288f08c3bdfSopenharmony_ci	test_invalid_pid();
289f08c3bdfSopenharmony_ci	test_invalid_perm();
290f08c3bdfSopenharmony_ci	test_invalid_protection();
291f08c3bdfSopenharmony_ci}
292f08c3bdfSopenharmony_ci
293f08c3bdfSopenharmony_cistatic void setup(void)
294f08c3bdfSopenharmony_ci{
295f08c3bdfSopenharmony_ci	if (str_read) {
296f08c3bdfSopenharmony_ci		tst_res(TINFO, "Selected process_vm_readv");
297f08c3bdfSopenharmony_ci		test_params = test_readv;
298f08c3bdfSopenharmony_ci	} else {
299f08c3bdfSopenharmony_ci		tst_res(TINFO, "Selected process_vm_writev");
300f08c3bdfSopenharmony_ci		test_params = test_writev;
301f08c3bdfSopenharmony_ci	}
302f08c3bdfSopenharmony_ci}
303f08c3bdfSopenharmony_ci
304f08c3bdfSopenharmony_cistatic struct tst_test test = {
305f08c3bdfSopenharmony_ci	.test_all = run,
306f08c3bdfSopenharmony_ci	.setup = setup,
307f08c3bdfSopenharmony_ci	.forks_child = 1,
308f08c3bdfSopenharmony_ci	.needs_root = 1,
309f08c3bdfSopenharmony_ci	.options = (struct tst_option[]) {
310f08c3bdfSopenharmony_ci		{"r", &str_read, "Use process_vm_read instead of process_vm_write"},
311f08c3bdfSopenharmony_ci		{},
312f08c3bdfSopenharmony_ci	},
313f08c3bdfSopenharmony_ci};
314