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