]>
Commit | Line | Data |
---|---|---|
75b07eca FG |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Wolfgang Bumiller <Blub@users.noreply.github.com> | |
3 | Date: Thu, 8 Mar 2018 00:40:42 +0100 | |
4 | Subject: [PATCH] Take user namespaces into account in policy checks | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | Change file related checks to use user namespaces and make | |
10 | sure involved uids/gids are mappable in the current | |
11 | namespace. | |
12 | ||
13 | Note that checks without file ownership information will | |
14 | still not take user namespaces into account, as some of | |
15 | these should be handled via 'zfs allow' (otherwise root in a | |
16 | user namespace could issue commands such as `zpool export`). | |
17 | ||
18 | This also adds an initial user namespace regression test | |
19 | for the setgid bit loss, with a user_ns_exec helper usable | |
20 | in further tests. | |
21 | ||
22 | Additionally, configure checks for the required user | |
23 | namespace related features are added for: | |
24 | * ns_capable | |
25 | * kuid/kgid_has_mapping() | |
26 | * user_ns in cred_t | |
27 | ||
28 | Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> | |
29 | Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com> | |
30 | Closes #6800 | |
31 | Closes #7270 | |
32 | (cherry picked from commit 3808006edfc46b18f0a40a2e9df54c6567bf52cc) | |
33 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
34 | --- | |
35 | configure.ac | 2 + | |
36 | tests/zfs-tests/cmd/Makefile.am | 1 + | |
37 | tests/zfs-tests/cmd/user_ns_exec/Makefile.am | 6 + | |
38 | tests/zfs-tests/tests/functional/Makefile.am | 1 + | |
39 | .../tests/functional/user_namespace/Makefile.am | 7 + | |
40 | module/zfs/policy.c | 66 +++++++- | |
41 | tests/zfs-tests/cmd/user_ns_exec/user_ns_exec.c | 179 +++++++++++++++++++++ | |
42 | config/kernel-userns-capabilities.m4 | 67 ++++++++ | |
43 | config/kernel.m4 | 1 + | |
44 | tests/runfiles/linux.run | 4 + | |
45 | tests/zfs-tests/cmd/user_ns_exec/.gitignore | 1 + | |
46 | tests/zfs-tests/include/commands.cfg | 1 + | |
47 | .../tests/functional/user_namespace/cleanup.ksh | 25 +++ | |
48 | .../tests/functional/user_namespace/setup.ksh | 32 ++++ | |
49 | .../functional/user_namespace/user_namespace.cfg | 23 +++ | |
50 | .../user_namespace/user_namespace_001.ksh | 89 ++++++++++ | |
51 | .../user_namespace/user_namespace_common.kshlib | 23 +++ | |
52 | 17 files changed, 521 insertions(+), 7 deletions(-) | |
53 | create mode 100644 tests/zfs-tests/cmd/user_ns_exec/Makefile.am | |
54 | create mode 100644 tests/zfs-tests/tests/functional/user_namespace/Makefile.am | |
55 | create mode 100644 tests/zfs-tests/cmd/user_ns_exec/user_ns_exec.c | |
56 | create mode 100644 config/kernel-userns-capabilities.m4 | |
57 | create mode 100644 tests/zfs-tests/cmd/user_ns_exec/.gitignore | |
58 | create mode 100755 tests/zfs-tests/tests/functional/user_namespace/cleanup.ksh | |
59 | create mode 100755 tests/zfs-tests/tests/functional/user_namespace/setup.ksh | |
60 | create mode 100644 tests/zfs-tests/tests/functional/user_namespace/user_namespace.cfg | |
61 | create mode 100755 tests/zfs-tests/tests/functional/user_namespace/user_namespace_001.ksh | |
62 | create mode 100644 tests/zfs-tests/tests/functional/user_namespace/user_namespace_common.kshlib | |
63 | ||
64 | diff --git a/configure.ac b/configure.ac | |
65 | index d71712e4c..77e5764fc 100644 | |
66 | --- a/configure.ac | |
67 | +++ b/configure.ac | |
68 | @@ -153,6 +153,7 @@ AC_CONFIG_FILES([ | |
69 | tests/zfs-tests/callbacks/Makefile | |
70 | tests/zfs-tests/cmd/Makefile | |
71 | tests/zfs-tests/cmd/chg_usr_exec/Makefile | |
72 | + tests/zfs-tests/cmd/user_ns_exec/Makefile | |
73 | tests/zfs-tests/cmd/devname2devid/Makefile | |
74 | tests/zfs-tests/cmd/dir_rd_update/Makefile | |
75 | tests/zfs-tests/cmd/file_check/Makefile | |
76 | @@ -284,6 +285,7 @@ AC_CONFIG_FILES([ | |
77 | tests/zfs-tests/tests/functional/threadsappend/Makefile | |
78 | tests/zfs-tests/tests/functional/tmpfile/Makefile | |
79 | tests/zfs-tests/tests/functional/truncate/Makefile | |
80 | + tests/zfs-tests/tests/functional/user_namespace/Makefile | |
81 | tests/zfs-tests/tests/functional/userquota/Makefile | |
82 | tests/zfs-tests/tests/functional/upgrade/Makefile | |
83 | tests/zfs-tests/tests/functional/vdev_zaps/Makefile | |
84 | diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am | |
85 | index f55ff8ce2..1cce6947b 100644 | |
86 | --- a/tests/zfs-tests/cmd/Makefile.am | |
87 | +++ b/tests/zfs-tests/cmd/Makefile.am | |
88 | @@ -2,6 +2,7 @@ EXTRA_DIST = file_common.h | |
89 | ||
90 | SUBDIRS = \ | |
91 | chg_usr_exec \ | |
92 | + user_ns_exec \ | |
93 | devname2devid \ | |
94 | dir_rd_update \ | |
95 | file_check \ | |
96 | diff --git a/tests/zfs-tests/cmd/user_ns_exec/Makefile.am b/tests/zfs-tests/cmd/user_ns_exec/Makefile.am | |
97 | new file mode 100644 | |
98 | index 000000000..5b4bc9aaa | |
99 | --- /dev/null | |
100 | +++ b/tests/zfs-tests/cmd/user_ns_exec/Makefile.am | |
101 | @@ -0,0 +1,6 @@ | |
102 | +include $(top_srcdir)/config/Rules.am | |
103 | + | |
104 | +pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin | |
105 | + | |
106 | +pkgexec_PROGRAMS = user_ns_exec | |
107 | +user_ns_exec_SOURCES = user_ns_exec.c | |
108 | diff --git a/tests/zfs-tests/tests/functional/Makefile.am b/tests/zfs-tests/tests/functional/Makefile.am | |
109 | index d68f254ef..cd60324f3 100644 | |
110 | --- a/tests/zfs-tests/tests/functional/Makefile.am | |
111 | +++ b/tests/zfs-tests/tests/functional/Makefile.am | |
112 | @@ -58,6 +58,7 @@ SUBDIRS = \ | |
113 | tmpfile \ | |
114 | truncate \ | |
115 | upgrade \ | |
116 | + user_namespace \ | |
117 | userquota \ | |
118 | vdev_zaps \ | |
119 | write_dirs \ | |
120 | diff --git a/tests/zfs-tests/tests/functional/user_namespace/Makefile.am b/tests/zfs-tests/tests/functional/user_namespace/Makefile.am | |
121 | new file mode 100644 | |
122 | index 000000000..0c0f6887a | |
123 | --- /dev/null | |
124 | +++ b/tests/zfs-tests/tests/functional/user_namespace/Makefile.am | |
125 | @@ -0,0 +1,7 @@ | |
126 | +pkgdatadir = $(datadir)/@PACKAGE@/zfs-tests/tests/functional/user_namespace | |
127 | +dist_pkgdata_SCRIPTS = \ | |
128 | + setup.ksh \ | |
129 | + cleanup.ksh \ | |
130 | + user_namespace_common.kshlib \ | |
131 | + user_namespace.cfg \ | |
132 | + user_namespace_001.ksh | |
133 | diff --git a/module/zfs/policy.c b/module/zfs/policy.c | |
134 | index 03e8f748b..55c932747 100644 | |
135 | --- a/module/zfs/policy.c | |
136 | +++ b/module/zfs/policy.c | |
137 | @@ -42,19 +42,47 @@ | |
138 | * all other cases this function must fail and return the passed err. | |
139 | */ | |
140 | static int | |
141 | -priv_policy(const cred_t *cr, int capability, boolean_t all, int err) | |
142 | +priv_policy_ns(const cred_t *cr, int capability, boolean_t all, int err, | |
143 | + struct user_namespace *ns) | |
144 | { | |
145 | ASSERT3S(all, ==, B_FALSE); | |
146 | ||
147 | if (cr != CRED() && (cr != kcred)) | |
148 | return (err); | |
149 | ||
150 | +#if defined(CONFIG_USER_NS) && defined(HAVE_NS_CAPABLE) | |
151 | + if (!(ns ? ns_capable(ns, capability) : capable(capability))) | |
152 | +#else | |
153 | if (!capable(capability)) | |
154 | +#endif | |
155 | return (err); | |
156 | ||
157 | return (0); | |
158 | } | |
159 | ||
160 | +static int | |
161 | +priv_policy(const cred_t *cr, int capability, boolean_t all, int err) | |
162 | +{ | |
163 | + return (priv_policy_ns(cr, capability, all, err, NULL)); | |
164 | +} | |
165 | + | |
166 | +static int | |
167 | +priv_policy_user(const cred_t *cr, int capability, boolean_t all, int err) | |
168 | +{ | |
169 | + /* | |
170 | + * All priv_policy_user checks are preceeded by kuid/kgid_has_mapping() | |
171 | + * checks. If we cannot do them, we shouldn't be using ns_capable() | |
172 | + * since we don't know whether the affected files are valid in our | |
173 | + * namespace. Note that kuid_has_mapping() came after cred->user_ns, so | |
174 | + * we shouldn't need to re-check for HAVE_CRED_USER_NS | |
175 | + */ | |
176 | +#if defined(CONFIG_USER_NS) && defined(HAVE_KUID_HAS_MAPPING) | |
177 | + return (priv_policy_ns(cr, capability, all, err, cr->user_ns)); | |
178 | +#else | |
179 | + return (priv_policy_ns(cr, capability, all, err, NULL)); | |
180 | +#endif | |
181 | +} | |
182 | + | |
183 | /* | |
184 | * Checks for operations that are either client-only or are used by | |
185 | * both clients and servers. | |
186 | @@ -102,10 +130,15 @@ secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner) | |
187 | if (zpl_inode_owner_or_capable(ip)) | |
188 | return (0); | |
189 | ||
190 | - if (priv_policy(cr, CAP_DAC_OVERRIDE, B_FALSE, EPERM) == 0) | |
191 | +#if defined(CONFIG_USER_NS) && defined(HAVE_KUID_HAS_MAPPING) | |
192 | + if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) | |
193 | + return (EPERM); | |
194 | +#endif | |
195 | + | |
196 | + if (priv_policy_user(cr, CAP_DAC_OVERRIDE, B_FALSE, EPERM) == 0) | |
197 | return (0); | |
198 | ||
199 | - if (priv_policy(cr, CAP_DAC_READ_SEARCH, B_FALSE, EPERM) == 0) | |
200 | + if (priv_policy_user(cr, CAP_DAC_READ_SEARCH, B_FALSE, EPERM) == 0) | |
201 | return (0); | |
202 | ||
203 | return (EPERM); | |
204 | @@ -120,7 +153,12 @@ secpolicy_vnode_chown(const cred_t *cr, uid_t owner) | |
205 | if (crgetfsuid(cr) == owner) | |
206 | return (0); | |
207 | ||
208 | - return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM)); | |
209 | +#if defined(CONFIG_USER_NS) && defined(HAVE_KUID_HAS_MAPPING) | |
210 | + if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) | |
211 | + return (EPERM); | |
212 | +#endif | |
213 | + | |
214 | + return (priv_policy_user(cr, CAP_FOWNER, B_FALSE, EPERM)); | |
215 | } | |
216 | ||
217 | /* | |
218 | @@ -152,7 +190,12 @@ secpolicy_vnode_setdac(const cred_t *cr, uid_t owner) | |
219 | if (crgetfsuid(cr) == owner) | |
220 | return (0); | |
221 | ||
222 | - return (priv_policy(cr, CAP_FOWNER, B_FALSE, EPERM)); | |
223 | +#if defined(CONFIG_USER_NS) && defined(HAVE_KUID_HAS_MAPPING) | |
224 | + if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) | |
225 | + return (EPERM); | |
226 | +#endif | |
227 | + | |
228 | + return (priv_policy_user(cr, CAP_FOWNER, B_FALSE, EPERM)); | |
229 | } | |
230 | ||
231 | /* | |
232 | @@ -175,8 +218,12 @@ secpolicy_vnode_setid_retain(const cred_t *cr, boolean_t issuidroot) | |
233 | int | |
234 | secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid) | |
235 | { | |
236 | +#if defined(CONFIG_USER_NS) && defined(HAVE_KUID_HAS_MAPPING) | |
237 | + if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid))) | |
238 | + return (EPERM); | |
239 | +#endif | |
240 | if (crgetfsgid(cr) != gid && !groupmember(gid, cr)) | |
241 | - return (priv_policy(cr, CAP_FSETID, B_FALSE, EPERM)); | |
242 | + return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM)); | |
243 | ||
244 | return (0); | |
245 | } | |
246 | @@ -222,7 +269,12 @@ secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) | |
247 | if (crgetfsuid(cr) == owner) | |
248 | return (0); | |
249 | ||
250 | - return (priv_policy(cr, CAP_FSETID, B_FALSE, EPERM)); | |
251 | +#if defined(CONFIG_USER_NS) && defined(HAVE_KUID_HAS_MAPPING) | |
252 | + if (!kuid_has_mapping(cr->user_ns, SUID_TO_KUID(owner))) | |
253 | + return (EPERM); | |
254 | +#endif | |
255 | + | |
256 | + return (priv_policy_user(cr, CAP_FSETID, B_FALSE, EPERM)); | |
257 | } | |
258 | ||
259 | /* | |
260 | diff --git a/tests/zfs-tests/cmd/user_ns_exec/user_ns_exec.c b/tests/zfs-tests/cmd/user_ns_exec/user_ns_exec.c | |
261 | new file mode 100644 | |
262 | index 000000000..cd46738bd | |
263 | --- /dev/null | |
264 | +++ b/tests/zfs-tests/cmd/user_ns_exec/user_ns_exec.c | |
265 | @@ -0,0 +1,179 @@ | |
266 | +/* | |
267 | + * CDDL HEADER START | |
268 | + * | |
269 | + * The contents of this file are subject to the terms of the | |
270 | + * Common Development and Distribution License (the "License"). | |
271 | + * You may not use this file except in compliance with the License. | |
272 | + * | |
273 | + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
274 | + * or http://www.opensolaris.org/os/licensing. | |
275 | + * See the License for the specific language governing permissions | |
276 | + * and limitations under the License. | |
277 | + * | |
278 | + * When distributing Covered Code, include this CDDL HEADER in each | |
279 | + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
280 | + * If applicable, add the following below this CDDL HEADER, with the | |
281 | + * fields enclosed by brackets "[]" replaced with your own identifying | |
282 | + * information: Portions Copyright [yyyy] [name of copyright owner] | |
283 | + * | |
284 | + * CDDL HEADER END | |
285 | + */ | |
286 | + | |
287 | +#include <stdio.h> | |
288 | +#include <unistd.h> | |
289 | +#include <string.h> | |
290 | +#include <limits.h> | |
291 | +#include <sys/types.h> | |
292 | +#include <sys/types.h> | |
293 | +#include <sys/socket.h> | |
294 | +#include <sys/wait.h> | |
295 | +#include <fcntl.h> | |
296 | +#include <errno.h> | |
297 | +#include <signal.h> | |
298 | +#include <sched.h> | |
299 | + | |
300 | +#define EXECSHELL "/bin/sh" | |
301 | +#define UIDMAP "0 100000 65536" | |
302 | + | |
303 | +static int | |
304 | +child_main(int argc, char *argv[], int sync_pipe) | |
305 | +{ | |
306 | + char sync_buf; | |
307 | + char cmds[BUFSIZ] = { 0 }; | |
308 | + char sep[] = " "; | |
309 | + int i, len; | |
310 | + | |
311 | + if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0) { | |
312 | + perror("unshare"); | |
313 | + return (1); | |
314 | + } | |
315 | + | |
316 | + /* tell parent we entered the new namespace */ | |
317 | + if (write(sync_pipe, "1", 1) != 1) { | |
318 | + perror("write"); | |
319 | + return (1); | |
320 | + } | |
321 | + | |
322 | + /* wait for parent to setup the uid mapping */ | |
323 | + if (read(sync_pipe, &sync_buf, 1) != 1) { | |
324 | + (void) fprintf(stderr, "user namespace setup failed\n"); | |
325 | + return (1); | |
326 | + } | |
327 | + | |
328 | + close(sync_pipe); | |
329 | + | |
330 | + if (setuid(0) != 0) { | |
331 | + perror("setuid"); | |
332 | + return (1); | |
333 | + } | |
334 | + if (setgid(0) != 0) { | |
335 | + perror("setgid"); | |
336 | + return (1); | |
337 | + } | |
338 | + | |
339 | + len = 0; | |
340 | + for (i = 1; i < argc; i++) { | |
341 | + (void) snprintf(cmds+len, sizeof (cmds)-len, | |
342 | + "%s%s", argv[i], sep); | |
343 | + len += strlen(argv[i]) + strlen(sep); | |
344 | + } | |
345 | + | |
346 | + if (execl(EXECSHELL, "sh", "-c", cmds, (char *)NULL) != 0) { | |
347 | + perror("execl: " EXECSHELL); | |
348 | + return (1); | |
349 | + } | |
350 | + | |
351 | + return (0); | |
352 | +} | |
353 | + | |
354 | +static int | |
355 | +set_idmap(pid_t pid, const char *file) | |
356 | +{ | |
357 | + int result = 0; | |
358 | + int mapfd; | |
359 | + char path[PATH_MAX]; | |
360 | + | |
361 | + (void) snprintf(path, sizeof (path), "/proc/%d/%s", (int)pid, file); | |
362 | + | |
363 | + mapfd = open(path, O_WRONLY); | |
364 | + if (mapfd < 0) { | |
365 | + result = errno; | |
366 | + perror("open"); | |
367 | + return (errno); | |
368 | + } | |
369 | + | |
370 | + if (write(mapfd, UIDMAP, sizeof (UIDMAP)-1) != sizeof (UIDMAP)-1) { | |
371 | + perror("write"); | |
372 | + result = (errno); | |
373 | + } | |
374 | + | |
375 | + close(mapfd); | |
376 | + | |
377 | + return (result); | |
378 | +} | |
379 | + | |
380 | +int | |
381 | +main(int argc, char *argv[]) | |
382 | +{ | |
383 | + char sync_buf; | |
384 | + int result, wstatus; | |
385 | + int syncfd[2]; | |
386 | + pid_t child; | |
387 | + | |
388 | + if (argc < 2 || strlen(argv[1]) == 0) { | |
389 | + (void) printf("\tUsage: %s <commands> ...\n", argv[0]); | |
390 | + return (1); | |
391 | + } | |
392 | + | |
393 | + if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfd) != 0) { | |
394 | + perror("socketpair"); | |
395 | + return (1); | |
396 | + } | |
397 | + | |
398 | + child = fork(); | |
399 | + if (child == (pid_t)-1) { | |
400 | + perror("fork"); | |
401 | + return (1); | |
402 | + } | |
403 | + | |
404 | + if (child == 0) { | |
405 | + close(syncfd[0]); | |
406 | + return (child_main(argc, argv, syncfd[1])); | |
407 | + } | |
408 | + | |
409 | + close(syncfd[1]); | |
410 | + | |
411 | + result = 0; | |
412 | + /* wait for the child to have unshared its namespaces */ | |
413 | + if (read(syncfd[0], &sync_buf, 1) != 1) { | |
414 | + perror("read"); | |
415 | + kill(child, SIGKILL); | |
416 | + result = 1; | |
417 | + goto reap; | |
418 | + } | |
419 | + | |
420 | + /* write uid mapping */ | |
421 | + if (set_idmap(child, "uid_map") != 0 || | |
422 | + set_idmap(child, "gid_map") != 0) { | |
423 | + result = 1; | |
424 | + kill(child, SIGKILL); | |
425 | + goto reap; | |
426 | + } | |
427 | + | |
428 | + /* tell the child to proceed */ | |
429 | + if (write(syncfd[0], "1", 1) != 1) { | |
430 | + perror("write"); | |
431 | + kill(child, SIGKILL); | |
432 | + result = 1; | |
433 | + goto reap; | |
434 | + } | |
435 | + close(syncfd[0]); | |
436 | + | |
437 | +reap: | |
438 | + while (waitpid(child, &wstatus, 0) != child) | |
439 | + kill(child, SIGKILL); | |
440 | + if (result == 0) | |
441 | + result = WEXITSTATUS(wstatus); | |
442 | + | |
443 | + return (result); | |
444 | +} | |
445 | diff --git a/config/kernel-userns-capabilities.m4 b/config/kernel-userns-capabilities.m4 | |
446 | new file mode 100644 | |
447 | index 000000000..fa3381978 | |
448 | --- /dev/null | |
449 | +++ b/config/kernel-userns-capabilities.m4 | |
450 | @@ -0,0 +1,67 @@ | |
451 | +dnl # | |
452 | +dnl # 2.6.38 API change | |
453 | +dnl # ns_capable() was introduced | |
454 | +dnl # | |
455 | +AC_DEFUN([ZFS_AC_KERNEL_NS_CAPABLE], [ | |
456 | + AC_MSG_CHECKING([whether ns_capable exists]) | |
457 | + ZFS_LINUX_TRY_COMPILE([ | |
458 | + #include <linux/capability.h> | |
459 | + ],[ | |
460 | + ns_capable((struct user_namespace *)NULL, CAP_SYS_ADMIN); | |
461 | + ],[ | |
462 | + AC_MSG_RESULT(yes) | |
463 | + AC_DEFINE(HAVE_NS_CAPABLE, 1, | |
464 | + [ns_capable exists]) | |
465 | + ],[ | |
466 | + AC_MSG_RESULT(no) | |
467 | + ]) | |
468 | +]) | |
469 | + | |
470 | +dnl # | |
471 | +dnl # 2.6.39 API change | |
472 | +dnl # struct user_namespace was added to struct cred_t as | |
473 | +dnl # cred->user_ns member | |
474 | +dnl # Note that current_user_ns() was added in 2.6.28. | |
475 | +dnl # | |
476 | +AC_DEFUN([ZFS_AC_KERNEL_CRED_USER_NS], [ | |
477 | + AC_MSG_CHECKING([whether cred_t->user_ns exists]) | |
478 | + ZFS_LINUX_TRY_COMPILE([ | |
479 | + #include <linux/cred.h> | |
480 | + ],[ | |
481 | + struct cred cr; | |
482 | + cr.user_ns = (struct user_namespace *)NULL; | |
483 | + ],[ | |
484 | + AC_MSG_RESULT(yes) | |
485 | + AC_DEFINE(HAVE_CRED_USER_NS, 1, | |
486 | + [cred_t->user_ns exists]) | |
487 | + ],[ | |
488 | + AC_MSG_RESULT(no) | |
489 | + ]) | |
490 | +]) | |
491 | + | |
492 | +dnl # | |
493 | +dnl # 3.4 API change | |
494 | +dnl # kuid_has_mapping() and kgid_has_mapping() were added to distinguish | |
495 | +dnl # between internal kernel uids/gids and user namespace uids/gids. | |
496 | +dnl # | |
497 | +AC_DEFUN([ZFS_AC_KERNEL_KUID_HAS_MAPPING], [ | |
498 | + AC_MSG_CHECKING([whether kuid_has_mapping/kgid_has_mapping exist]) | |
499 | + ZFS_LINUX_TRY_COMPILE([ | |
500 | + #include <linux/uidgid.h> | |
501 | + ],[ | |
502 | + kuid_has_mapping((struct user_namespace *)NULL, KUIDT_INIT(0)); | |
503 | + kgid_has_mapping((struct user_namespace *)NULL, KGIDT_INIT(0)); | |
504 | + ],[ | |
505 | + AC_MSG_RESULT(yes) | |
506 | + AC_DEFINE(HAVE_KUID_HAS_MAPPING, 1, | |
507 | + [kuid_has_mapping/kgid_has_mapping exist]) | |
508 | + ],[ | |
509 | + AC_MSG_RESULT(no) | |
510 | + ]) | |
511 | +]) | |
512 | + | |
513 | +AC_DEFUN([ZFS_AC_KERNEL_USERNS_CAPABILITIES], [ | |
514 | + ZFS_AC_KERNEL_NS_CAPABLE | |
515 | + ZFS_AC_KERNEL_CRED_USER_NS | |
516 | + ZFS_AC_KERNEL_KUID_HAS_MAPPING | |
517 | +]) | |
518 | diff --git a/config/kernel.m4 b/config/kernel.m4 | |
519 | index 419ed1a2c..910d4ff25 100644 | |
520 | --- a/config/kernel.m4 | |
521 | +++ b/config/kernel.m4 | |
522 | @@ -126,6 +126,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [ | |
523 | ZFS_AC_KERNEL_CURRENT_TIME | |
524 | ZFS_AC_KERNEL_GLOBAL_PAGE_STATE | |
525 | ZFS_AC_KERNEL_ACL_HAS_REFCOUNT | |
526 | + ZFS_AC_KERNEL_USERNS_CAPABILITIES | |
527 | ||
528 | AS_IF([test "$LINUX_OBJ" != "$LINUX"], [ | |
529 | KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ" | |
530 | diff --git a/tests/runfiles/linux.run b/tests/runfiles/linux.run | |
531 | index 89c923db1..25ae3fe5e 100644 | |
532 | --- a/tests/runfiles/linux.run | |
533 | +++ b/tests/runfiles/linux.run | |
534 | @@ -648,6 +648,10 @@ tags = ['functional', 'truncate'] | |
535 | tests = [ 'upgrade_userobj_001_pos' ] | |
536 | tags = ['functional', 'upgrade'] | |
537 | ||
538 | +[tests/functional/user_namespace] | |
539 | +tests = ['user_namespace_001'] | |
540 | +tags = ['functional', 'user_namespace'] | |
541 | + | |
542 | [tests/functional/userquota] | |
543 | tests = [ | |
544 | 'userquota_001_pos', 'userquota_002_pos', 'userquota_003_pos', | |
545 | diff --git a/tests/zfs-tests/cmd/user_ns_exec/.gitignore b/tests/zfs-tests/cmd/user_ns_exec/.gitignore | |
546 | new file mode 100644 | |
547 | index 000000000..655867a64 | |
548 | --- /dev/null | |
549 | +++ b/tests/zfs-tests/cmd/user_ns_exec/.gitignore | |
550 | @@ -0,0 +1 @@ | |
551 | +/user_ns_exec | |
552 | diff --git a/tests/zfs-tests/include/commands.cfg b/tests/zfs-tests/include/commands.cfg | |
553 | index 936e54c1a..0d768a3cf 100644 | |
554 | --- a/tests/zfs-tests/include/commands.cfg | |
555 | +++ b/tests/zfs-tests/include/commands.cfg | |
556 | @@ -164,4 +164,5 @@ export ZFSTEST_FILES='chg_usr_exec | |
557 | rename_dir | |
558 | rm_lnkcnt_zero_file | |
559 | threadsappend | |
560 | + user_ns_exec | |
561 | xattrtest' | |
562 | diff --git a/tests/zfs-tests/tests/functional/user_namespace/cleanup.ksh b/tests/zfs-tests/tests/functional/user_namespace/cleanup.ksh | |
563 | new file mode 100755 | |
564 | index 000000000..61caf3910 | |
565 | --- /dev/null | |
566 | +++ b/tests/zfs-tests/tests/functional/user_namespace/cleanup.ksh | |
567 | @@ -0,0 +1,25 @@ | |
568 | +#!/bin/ksh -p | |
569 | +# | |
570 | +# CDDL HEADER START | |
571 | +# | |
572 | +# The contents of this file are subject to the terms of the | |
573 | +# Common Development and Distribution License (the "License"). | |
574 | +# You may not use this file except in compliance with the License. | |
575 | +# | |
576 | +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
577 | +# or http://www.opensolaris.org/os/licensing. | |
578 | +# See the License for the specific language governing permissions | |
579 | +# and limitations under the License. | |
580 | +# | |
581 | +# When distributing Covered Code, include this CDDL HEADER in each | |
582 | +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
583 | +# If applicable, add the following below this CDDL HEADER, with the | |
584 | +# fields enclosed by brackets "[]" replaced with your own identifying | |
585 | +# information: Portions Copyright [yyyy] [name of copyright owner] | |
586 | +# | |
587 | +# CDDL HEADER END | |
588 | +# | |
589 | + | |
590 | +. $STF_SUITE/include/libtest.shlib | |
591 | + | |
592 | +default_cleanup | |
593 | diff --git a/tests/zfs-tests/tests/functional/user_namespace/setup.ksh b/tests/zfs-tests/tests/functional/user_namespace/setup.ksh | |
594 | new file mode 100755 | |
595 | index 000000000..354cc9a6b | |
596 | --- /dev/null | |
597 | +++ b/tests/zfs-tests/tests/functional/user_namespace/setup.ksh | |
598 | @@ -0,0 +1,32 @@ | |
599 | +#!/bin/ksh -p | |
600 | +# | |
601 | +# CDDL HEADER START | |
602 | +# | |
603 | +# The contents of this file are subject to the terms of the | |
604 | +# Common Development and Distribution License (the "License"). | |
605 | +# You may not use this file except in compliance with the License. | |
606 | +# | |
607 | +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
608 | +# or http://www.opensolaris.org/os/licensing. | |
609 | +# See the License for the specific language governing permissions | |
610 | +# and limitations under the License. | |
611 | +# | |
612 | +# When distributing Covered Code, include this CDDL HEADER in each | |
613 | +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
614 | +# If applicable, add the following below this CDDL HEADER, with the | |
615 | +# fields enclosed by brackets "[]" replaced with your own identifying | |
616 | +# information: Portions Copyright [yyyy] [name of copyright owner] | |
617 | +# | |
618 | +# CDDL HEADER END | |
619 | +# | |
620 | + | |
621 | +. $STF_SUITE/include/libtest.shlib | |
622 | + | |
623 | +if ! [ -f /proc/self/uid_map ]; then | |
624 | + log_unsupported "The kernel doesn't support user namespaces." | |
625 | +fi | |
626 | + | |
627 | +verify_runnable "both" | |
628 | + | |
629 | +DISK=${DISKS%% *} | |
630 | +default_setup $DISK | |
631 | diff --git a/tests/zfs-tests/tests/functional/user_namespace/user_namespace.cfg b/tests/zfs-tests/tests/functional/user_namespace/user_namespace.cfg | |
632 | new file mode 100644 | |
633 | index 000000000..9e55398e2 | |
634 | --- /dev/null | |
635 | +++ b/tests/zfs-tests/tests/functional/user_namespace/user_namespace.cfg | |
636 | @@ -0,0 +1,23 @@ | |
637 | +# | |
638 | +# CDDL HEADER START | |
639 | +# | |
640 | +# The contents of this file are subject to the terms of the | |
641 | +# Common Development and Distribution License (the "License"). | |
642 | +# You may not use this file except in compliance with the License. | |
643 | +# | |
644 | +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
645 | +# or http://www.opensolaris.org/os/licensing. | |
646 | +# See the License for the specific language governing permissions | |
647 | +# and limitations under the License. | |
648 | +# | |
649 | +# When distributing Covered Code, include this CDDL HEADER in each | |
650 | +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
651 | +# If applicable, add the following below this CDDL HEADER, with the | |
652 | +# fields enclosed by brackets "[]" replaced with your own identifying | |
653 | +# information: Portions Copyright [yyyy] [name of copyright owner] | |
654 | +# | |
655 | +# CDDL HEADER END | |
656 | +# | |
657 | + | |
658 | +export ROOT_UID=100000 | |
659 | +export OTHER_UID=101000 | |
660 | diff --git a/tests/zfs-tests/tests/functional/user_namespace/user_namespace_001.ksh b/tests/zfs-tests/tests/functional/user_namespace/user_namespace_001.ksh | |
661 | new file mode 100755 | |
662 | index 000000000..6be30ab4d | |
663 | --- /dev/null | |
664 | +++ b/tests/zfs-tests/tests/functional/user_namespace/user_namespace_001.ksh | |
665 | @@ -0,0 +1,89 @@ | |
666 | +#!/bin/ksh -p | |
667 | +# | |
668 | +# CDDL HEADER START | |
669 | +# | |
670 | +# The contents of this file are subject to the terms of the | |
671 | +# Common Development and Distribution License (the "License"). | |
672 | +# You may not use this file except in compliance with the License. | |
673 | +# | |
674 | +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
675 | +# or http://www.opensolaris.org/os/licensing. | |
676 | +# See the License for the specific language governing permissions | |
677 | +# and limitations under the License. | |
678 | +# | |
679 | +# When distributing Covered Code, include this CDDL HEADER in each | |
680 | +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
681 | +# If applicable, add the following below this CDDL HEADER, with the | |
682 | +# fields enclosed by brackets "[]" replaced with your own identifying | |
683 | +# information: Portions Copyright [yyyy] [name of copyright owner] | |
684 | +# | |
685 | +# CDDL HEADER END | |
686 | +# | |
687 | + | |
688 | +. $STF_SUITE/tests/functional/user_namespace/user_namespace_common.kshlib | |
689 | + | |
690 | +# | |
691 | +# | |
692 | +# DESCRIPTION: | |
693 | +# Regression test for secpolicy_vnode_setids_setgids | |
694 | +# | |
695 | +# | |
696 | +# STRATEGY: | |
697 | +# 1. Create files with various owners. | |
698 | +# 2. Try to set setgid bit. | |
699 | +# | |
700 | + | |
701 | +verify_runnable "both" | |
702 | + | |
703 | +# rroot: real root, | |
704 | +# uroot: root within user namespace | |
705 | +# uother: other user within user namespace | |
706 | +set -A files rroot_rroot uroot_uroot uroot_other uother_uroot uother_uother | |
707 | + | |
708 | +function cleanup | |
709 | +{ | |
710 | + for i in ${files[*]}; do | |
711 | + log_must rm -f $TESTDIR/$i | |
712 | + done | |
713 | +} | |
714 | + | |
715 | +log_onexit cleanup | |
716 | + | |
717 | +log_assert "Check root in user namespaces" | |
718 | + | |
719 | +TOUCH=$(readlink -e $(which touch)) | |
720 | +CHMOD=$(readlink -e $(which chmod)) | |
721 | + | |
722 | +for i in ${files[*]}; do | |
723 | + log_must $TOUCH $TESTDIR/$i | |
724 | + log_must $CHMOD 0644 $TESTDIR/$i | |
725 | +done | |
726 | + | |
727 | +log_must chown 0:0 $TESTDIR/rroot_rroot | |
728 | +log_must chown $ROOT_UID:$ROOT_UID $TESTDIR/uroot_uroot | |
729 | +log_must chown $ROOT_UID:$OTHER_UID $TESTDIR/uroot_other | |
730 | +log_must chown $OTHER_UID:$ROOT_UID $TESTDIR/uother_uroot | |
731 | +log_must chown $OTHER_UID:$OTHER_UID $TESTDIR/uother_uother | |
732 | + | |
733 | +log_mustnot user_ns_exec $CHMOD 02755 $TESTDIR/rroot_rroot | |
734 | +log_mustnot test -g $TESTDIR/rroot_rroot | |
735 | + | |
736 | +log_must user_ns_exec $CHMOD 02755 $TESTDIR/uroot_uroot | |
737 | +log_must test -g $TESTDIR/uroot_uroot | |
738 | + | |
739 | +log_must user_ns_exec $CHMOD 02755 $TESTDIR/uroot_other | |
740 | +log_must test -g $TESTDIR/uroot_other | |
741 | + | |
742 | +log_must user_ns_exec $CHMOD 02755 $TESTDIR/uother_uroot | |
743 | +log_must test -g $TESTDIR/uother_uroot | |
744 | + | |
745 | +log_must user_ns_exec $CHMOD 02755 $TESTDIR/uother_uother | |
746 | +log_must test -g $TESTDIR/uother_uother | |
747 | + | |
748 | +log_mustnot user_ns_exec $TOUCH $TESTDIR/rroot_rroot | |
749 | +log_must $CHMOD 0666 $TESTDIR/rroot_rroot | |
750 | +for i in ${files[*]}; do | |
751 | + log_must user_ns_exec $TOUCH $TESTDIR/$i | |
752 | +done | |
753 | + | |
754 | +log_pass "Check root in user namespaces" | |
755 | diff --git a/tests/zfs-tests/tests/functional/user_namespace/user_namespace_common.kshlib b/tests/zfs-tests/tests/functional/user_namespace/user_namespace_common.kshlib | |
756 | new file mode 100644 | |
757 | index 000000000..8577294d0 | |
758 | --- /dev/null | |
759 | +++ b/tests/zfs-tests/tests/functional/user_namespace/user_namespace_common.kshlib | |
760 | @@ -0,0 +1,23 @@ | |
761 | +# | |
762 | +# CDDL HEADER START | |
763 | +# | |
764 | +# The contents of this file are subject to the terms of the | |
765 | +# Common Development and Distribution License (the "License"). | |
766 | +# You may not use this file except in compliance with the License. | |
767 | +# | |
768 | +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
769 | +# or http://www.opensolaris.org/os/licensing. | |
770 | +# See the License for the specific language governing permissions | |
771 | +# and limitations under the License. | |
772 | +# | |
773 | +# When distributing Covered Code, include this CDDL HEADER in each | |
774 | +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
775 | +# If applicable, add the following below this CDDL HEADER, with the | |
776 | +# fields enclosed by brackets "[]" replaced with your own identifying | |
777 | +# information: Portions Copyright [yyyy] [name of copyright owner] | |
778 | +# | |
779 | +# CDDL HEADER END | |
780 | +# | |
781 | + | |
782 | +. $STF_SUITE/include/libtest.shlib | |
783 | +. $STF_SUITE/tests/functional/user_namespace/user_namespace.cfg | |
784 | -- | |
785 | 2.14.2 | |
786 |