1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved.
4 * Copyright (c) Linux Test Project, 2003-2023
5 * Author: Yang Xu <xuyang2018.jy@fujitsu.com>
6 */
7
8/*\
9 * [Description]
10 *
11 * Test basic error handling of faccessat2 syscall:
12 *
13 * - faccessat2() fails with EFAULT if pathname is a bad pathname point.
14 * - faccessat2() fails with EINVAL if flags is -1.
15 * - faccessat2() fails with EINVAL if mode is -1.
16 * - faccessat2() fails with EBADF if dirfd is -1.
17 * - faccessat2() fails with ENOTDIR if pathname is relative path to a
18 *   file and dir_fd is file descriptor for this file.
19 * - faccessat2() fails with EACCES if flags is AT_EACCESS and not using
20 *   the effective user and group IDs.
21 *
22 * Minimum Linux version required is v5.8.
23 */
24
25#include <pwd.h>
26
27#include "tst_test.h"
28#include "lapi/syscalls.h"
29#include "lapi/faccessat.h"
30
31#define TESTUSER        "nobody"
32#define TESTDIR         "faccessat2dir"
33#define RELPATH         "faccessat2dir/faccessat2file"
34
35static int fd;
36static int bad_fd = -1;
37static int atcwd_fd = AT_FDCWD;
38static char *bad_path;
39static char *rel_path;
40
41static struct passwd *ltpuser;
42
43static struct tcase {
44	int *fd;
45	char **filename;
46	int mode;
47	int flags;
48	int exp_errno;
49	const char *desc;
50} tcases[] = {
51	{&atcwd_fd, &bad_path, R_OK, 0, EFAULT, "invalid address"},
52	{&atcwd_fd, &rel_path, R_OK, -1, EINVAL, "invalid flags"},
53	{&atcwd_fd, &rel_path, -1, 0, EINVAL, "invalid mode"},
54	{&bad_fd, &rel_path, R_OK, 0, EBADF, "invalid fd"},
55	{&fd, &rel_path, R_OK, 0, ENOTDIR, "fd pointing to file"},
56	{&atcwd_fd, &rel_path, R_OK, AT_EACCESS, EACCES,
57         "AT_EACCESS and unprivileged EUID"},
58};
59
60static void verify_faccessat2(unsigned int i)
61{
62	struct tcase *tc = &tcases[i];
63
64	if (tc->exp_errno == EACCES)
65		SAFE_SETEUID(ltpuser->pw_uid);
66
67	TST_EXP_FAIL(faccessat2(*tc->fd, *tc->filename, tc->mode, tc->flags),
68		     tc->exp_errno, "faccessat2() with %s", tc->desc);
69
70	if (tc->exp_errno == EACCES)
71		SAFE_SETEUID(0);
72}
73
74static void setup(void)
75{
76	SAFE_MKDIR(TESTDIR, 0666);
77	SAFE_TOUCH(RELPATH, 0444, NULL);
78
79	fd = SAFE_OPEN(RELPATH, O_RDONLY);
80	bad_path = tst_get_bad_addr(NULL);
81
82	ltpuser = SAFE_GETPWNAM(TESTUSER);
83}
84
85static void cleanup(void)
86{
87	if (fd > -1)
88		SAFE_CLOSE(fd);
89}
90
91static struct tst_test test = {
92	.test = verify_faccessat2,
93	.tcnt = ARRAY_SIZE(tcases),
94	.setup = setup,
95	.cleanup = cleanup,
96	.bufs = (struct tst_buffers []) {
97		{&rel_path, .str = RELPATH},
98		{},
99	},
100	.needs_tmpdir = 1,
101	.needs_root = 1,
102};
103