• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
43 static acl_t acl;
44 static int orig_max_userns = -1;
45 static int user_ns_supported = 1;
46 
47 static 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 
verify_getxattr(void)58 static 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 
do_unshare(int map_root)89 static 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 
do_getxattr(unsigned int n)108 static 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 
setup(void)130 static 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 
cleanup(void)161 static 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 
170 static 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