]> git.proxmox.com Git - zfsonlinux.git/blob - zfs-patches/0050-Take-user-namespaces-into-account-in-policy-checks.patch
bump version to 0.7.7-pve1~bpo9
[zfsonlinux.git] / zfs-patches / 0050-Take-user-namespaces-into-account-in-policy-checks.patch
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