1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
4 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5 */
6
7/*
8 * Description:
9 * 1) Witout a user namespace, getxattr(2) should get same data when
10 *    acquiring the value of system.posix_acl_access twice.
11 * 2) With/Without mapped root UID in a user namespaces, getxattr(2) should
12 *    get same data when acquiring the value of system.posix_acl_access twice.
13 *
14 * This issue included by getxattr05 has been fixed in kernel:
15 * '82c9a927bc5d ("getxattr: use correct xattr length")'
16 */
17
18#define _GNU_SOURCE
19#include "config.h"
20#include <errno.h>
21#include <unistd.h>
22#include <sys/types.h>
23#include <stdlib.h>
24
25#ifdef HAVE_SYS_XATTR_H
26# include <sys/xattr.h>
27#endif
28
29#ifdef HAVE_LIBACL
30# include <sys/acl.h>
31#endif
32
33#include "tst_test.h"
34#include "lapi/sched.h"
35
36#if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LIBACL)
37
38#define TEST_FILE	"testfile"
39#define SELF_USERNS	"/proc/self/ns/user"
40#define MAX_USERNS	"/proc/sys/user/max_user_namespaces"
41#define UID_MAP	"/proc/self/uid_map"
42
43static acl_t acl;
44static int orig_max_userns = -1;
45static int user_ns_supported = 1;
46
47static struct tcase {
48	/* 0: without userns, 1: with userns */
49	int set_userns;
50	/* 0: don't map root UID in userns, 1: map root UID in userns */
51	int map_root;
52} tcases[] = {
53	{0, 0},
54	{1, 0},
55	{1, 1},
56};
57
58static void verify_getxattr(void)
59{
60	ssize_t i, res1, res2;
61	char buf1[128], buf2[132];
62
63	res1 = SAFE_GETXATTR(TEST_FILE, "system.posix_acl_access",
64			     buf1, sizeof(buf1));
65	res2 = SAFE_GETXATTR(TEST_FILE, "system.posix_acl_access",
66			     buf2, sizeof(buf2));
67
68	if (res1 != res2) {
69		tst_res(TFAIL, "Return different sizes when acquiring "
70			"the value of system.posix_acl_access twice");
71		return;
72	}
73
74	for (i = 0; i < res1; i++) {
75		if (buf1[i] != buf2[i])
76			break;
77	}
78
79	if (i < res1) {
80		tst_res(TFAIL, "Got different data(%02x != %02x) at %ld",
81			buf1[i], buf2[i], i);
82		return;
83	}
84
85	tst_res(TPASS, "Got same data when acquiring the value of "
86		"system.posix_acl_access twice");
87}
88
89static void do_unshare(int map_root)
90{
91	int res;
92
93	/* unshare() should support CLONE_NEWUSER flag since Linux 3.8 */
94	res = unshare(CLONE_NEWUSER);
95	if (res == -1)
96		tst_brk(TFAIL | TERRNO, "unshare(CLONE_NEWUSER) failed");
97
98	if (map_root) {
99		/* uid_map file should exist since Linux 3.8 because
100		 * it is available on Linux 3.5
101		 */
102		SAFE_ACCESS(UID_MAP, F_OK);
103
104		SAFE_FILE_PRINTF(UID_MAP, "%d %d %d", 0, 0, 1);
105	}
106}
107
108static void do_getxattr(unsigned int n)
109{
110	struct tcase *tc = &tcases[n];
111	pid_t pid;
112
113	if (tc->set_userns && !user_ns_supported) {
114		tst_res(TCONF, "user namespace not available");
115		return;
116	}
117
118	pid = SAFE_FORK();
119	if (!pid) {
120		if (tc->set_userns)
121			do_unshare(tc->map_root);
122
123		verify_getxattr();
124		exit(0);
125	}
126
127	tst_reap_children();
128}
129
130static void setup(void)
131{
132	const char *acl_text = "u::rw-,u:root:rwx,g::r--,o::r--,m::rwx";
133	int res;
134
135	SAFE_TOUCH(TEST_FILE, 0644, NULL);
136
137	acl = acl_from_text(acl_text);
138	if (!acl)
139		tst_brk(TBROK | TERRNO, "acl_from_text() failed");
140
141	res = acl_set_file(TEST_FILE, ACL_TYPE_ACCESS, acl);
142	if (res == -1) {
143		if (errno == EOPNOTSUPP)
144			tst_brk(TCONF | TERRNO, "acl_set_file()");
145
146		tst_brk(TBROK | TERRNO, "acl_set_file(%s) failed", TEST_FILE);
147	}
148
149	/* The default value of max_user_namespaces is set to 0 on some distros,
150	 * We need to change the default value to call unshare().
151	 */
152	if (access(SELF_USERNS, F_OK) != 0) {
153		user_ns_supported = 0;
154	} else if (!access(MAX_USERNS, F_OK)) {
155		SAFE_FILE_SCANF(MAX_USERNS, "%d", &orig_max_userns);
156		SAFE_FILE_PRINTF(MAX_USERNS, "%d", 10);
157	}
158
159}
160
161static void cleanup(void)
162{
163	if (orig_max_userns != -1)
164		SAFE_FILE_PRINTF(MAX_USERNS, "%d", orig_max_userns);
165
166	if (acl)
167		acl_free(acl);
168}
169
170static struct tst_test test = {
171	.needs_tmpdir = 1,
172	.needs_root = 1,
173	.forks_child = 1,
174	.setup = setup,
175	.cleanup = cleanup,
176	.tcnt = ARRAY_SIZE(tcases),
177	.test = do_getxattr,
178};
179
180#else /* HAVE_SYS_XATTR_H && HAVE_LIBACL*/
181	TST_TEST_TCONF("<sys/xattr.h> or <sys/acl.h> does not exist.");
182#endif
183