1*61145dc2SMartin Matuska // SPDX-License-Identifier: BSD-2-Clause
21f1e2261SMartin Matuska /*
31f1e2261SMartin Matuska * Copyright (c) 2021 Klara Systems, Inc.
41f1e2261SMartin Matuska * All rights reserved.
51f1e2261SMartin Matuska *
61f1e2261SMartin Matuska * Redistribution and use in source and binary forms, with or without
71f1e2261SMartin Matuska * modification, are permitted provided that the following conditions
81f1e2261SMartin Matuska * are met:
91f1e2261SMartin Matuska * 1. Redistributions of source code must retain the above copyright
101f1e2261SMartin Matuska * notice, this list of conditions and the following disclaimer.
111f1e2261SMartin Matuska * 2. Redistributions in binary form must reproduce the above copyright
121f1e2261SMartin Matuska * notice, this list of conditions and the following disclaimer in the
131f1e2261SMartin Matuska * documentation and/or other materials provided with the distribution.
141f1e2261SMartin Matuska *
151f1e2261SMartin Matuska * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
161f1e2261SMartin Matuska * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
171f1e2261SMartin Matuska * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
181f1e2261SMartin Matuska * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
191f1e2261SMartin Matuska * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
201f1e2261SMartin Matuska * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
211f1e2261SMartin Matuska * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221f1e2261SMartin Matuska * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
231f1e2261SMartin Matuska * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
241f1e2261SMartin Matuska * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
251f1e2261SMartin Matuska * SUCH DAMAGE.
261f1e2261SMartin Matuska */
271f1e2261SMartin Matuska
281f1e2261SMartin Matuska #include <sys/types.h>
291f1e2261SMartin Matuska #include <sys/sysmacros.h>
301f1e2261SMartin Matuska #include <sys/kmem.h>
311f1e2261SMartin Matuska #include <linux/file.h>
321f1e2261SMartin Matuska #include <linux/magic.h>
331f1e2261SMartin Matuska #include <sys/zone.h>
34fd45b686SMartin Matuska #include <sys/string.h>
351f1e2261SMartin Matuska
361f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
371f1e2261SMartin Matuska #include <linux/statfs.h>
381f1e2261SMartin Matuska #include <linux/proc_ns.h>
391f1e2261SMartin Matuska #endif
401f1e2261SMartin Matuska
41dbd5678dSMartin Matuska #include <sys/mutex.h>
42dbd5678dSMartin Matuska
431f1e2261SMartin Matuska static kmutex_t zone_datasets_lock;
441f1e2261SMartin Matuska static struct list_head zone_datasets;
451f1e2261SMartin Matuska
461f1e2261SMartin Matuska typedef struct zone_datasets {
471f1e2261SMartin Matuska struct list_head zds_list; /* zone_datasets linkage */
481f1e2261SMartin Matuska struct user_namespace *zds_userns; /* namespace reference */
491f1e2261SMartin Matuska struct list_head zds_datasets; /* datasets for the namespace */
501f1e2261SMartin Matuska } zone_datasets_t;
511f1e2261SMartin Matuska
521f1e2261SMartin Matuska typedef struct zone_dataset {
531f1e2261SMartin Matuska struct list_head zd_list; /* zone_dataset linkage */
541f1e2261SMartin Matuska size_t zd_dsnamelen; /* length of name */
5515f0b8c3SMartin Matuska char zd_dsname[]; /* name of the member dataset */
561f1e2261SMartin Matuska } zone_dataset_t;
571f1e2261SMartin Matuska
587a7741afSMartin Matuska #ifdef CONFIG_USER_NS
591f1e2261SMartin Matuska /*
601f1e2261SMartin Matuska * Returns:
611f1e2261SMartin Matuska * - 0 on success
621f1e2261SMartin Matuska * - EBADF if it cannot open the provided file descriptor
631f1e2261SMartin Matuska * - ENOTTY if the file itself is a not a user namespace file. We want to
641f1e2261SMartin Matuska * intercept this error in the ZFS layer. We cannot just return one of the
651f1e2261SMartin Matuska * ZFS_ERR_* errors here as we want to preserve the seperation of the ZFS
661f1e2261SMartin Matuska * and the SPL layers.
671f1e2261SMartin Matuska */
681f1e2261SMartin Matuska static int
user_ns_get(int fd,struct user_namespace ** userns)691f1e2261SMartin Matuska user_ns_get(int fd, struct user_namespace **userns)
701f1e2261SMartin Matuska {
711f1e2261SMartin Matuska struct kstatfs st;
721f1e2261SMartin Matuska struct file *nsfile;
731f1e2261SMartin Matuska struct ns_common *ns;
741f1e2261SMartin Matuska int error;
751f1e2261SMartin Matuska
761f1e2261SMartin Matuska if ((nsfile = fget(fd)) == NULL)
771f1e2261SMartin Matuska return (EBADF);
781f1e2261SMartin Matuska if (vfs_statfs(&nsfile->f_path, &st) != 0) {
791f1e2261SMartin Matuska error = ENOTTY;
801f1e2261SMartin Matuska goto done;
811f1e2261SMartin Matuska }
821f1e2261SMartin Matuska if (st.f_type != NSFS_MAGIC) {
831f1e2261SMartin Matuska error = ENOTTY;
841f1e2261SMartin Matuska goto done;
851f1e2261SMartin Matuska }
861f1e2261SMartin Matuska ns = get_proc_ns(file_inode(nsfile));
871f1e2261SMartin Matuska if (ns->ops->type != CLONE_NEWUSER) {
881f1e2261SMartin Matuska error = ENOTTY;
891f1e2261SMartin Matuska goto done;
901f1e2261SMartin Matuska }
911f1e2261SMartin Matuska *userns = container_of(ns, struct user_namespace, ns);
921f1e2261SMartin Matuska
931f1e2261SMartin Matuska error = 0;
941f1e2261SMartin Matuska done:
951f1e2261SMartin Matuska fput(nsfile);
961f1e2261SMartin Matuska
971f1e2261SMartin Matuska return (error);
981f1e2261SMartin Matuska }
997a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
1001f1e2261SMartin Matuska
1011f1e2261SMartin Matuska static unsigned int
user_ns_zoneid(struct user_namespace * user_ns)1021f1e2261SMartin Matuska user_ns_zoneid(struct user_namespace *user_ns)
1031f1e2261SMartin Matuska {
1041f1e2261SMartin Matuska unsigned int r;
1051f1e2261SMartin Matuska
1061f1e2261SMartin Matuska r = user_ns->ns.inum;
1071f1e2261SMartin Matuska
1081f1e2261SMartin Matuska return (r);
1091f1e2261SMartin Matuska }
1101f1e2261SMartin Matuska
1111f1e2261SMartin Matuska static struct zone_datasets *
zone_datasets_lookup(unsigned int nsinum)1121f1e2261SMartin Matuska zone_datasets_lookup(unsigned int nsinum)
1131f1e2261SMartin Matuska {
1141f1e2261SMartin Matuska zone_datasets_t *zds;
1151f1e2261SMartin Matuska
1161f1e2261SMartin Matuska list_for_each_entry(zds, &zone_datasets, zds_list) {
1171f1e2261SMartin Matuska if (user_ns_zoneid(zds->zds_userns) == nsinum)
1181f1e2261SMartin Matuska return (zds);
1191f1e2261SMartin Matuska }
1201f1e2261SMartin Matuska return (NULL);
1211f1e2261SMartin Matuska }
1221f1e2261SMartin Matuska
1237a7741afSMartin Matuska #ifdef CONFIG_USER_NS
1241f1e2261SMartin Matuska static struct zone_dataset *
zone_dataset_lookup(zone_datasets_t * zds,const char * dataset,size_t dsnamelen)1251f1e2261SMartin Matuska zone_dataset_lookup(zone_datasets_t *zds, const char *dataset, size_t dsnamelen)
1261f1e2261SMartin Matuska {
1271f1e2261SMartin Matuska zone_dataset_t *zd;
1281f1e2261SMartin Matuska
1291f1e2261SMartin Matuska list_for_each_entry(zd, &zds->zds_datasets, zd_list) {
1301f1e2261SMartin Matuska if (zd->zd_dsnamelen != dsnamelen)
1311f1e2261SMartin Matuska continue;
1321f1e2261SMartin Matuska if (strncmp(zd->zd_dsname, dataset, dsnamelen) == 0)
1331f1e2261SMartin Matuska return (zd);
1341f1e2261SMartin Matuska }
1351f1e2261SMartin Matuska
1361f1e2261SMartin Matuska return (NULL);
1371f1e2261SMartin Matuska }
1381f1e2261SMartin Matuska
1391f1e2261SMartin Matuska static int
zone_dataset_cred_check(cred_t * cred)1401f1e2261SMartin Matuska zone_dataset_cred_check(cred_t *cred)
1411f1e2261SMartin Matuska {
1421f1e2261SMartin Matuska
1431f1e2261SMartin Matuska if (!uid_eq(cred->uid, GLOBAL_ROOT_UID))
1441f1e2261SMartin Matuska return (EPERM);
1451f1e2261SMartin Matuska
1461f1e2261SMartin Matuska return (0);
1471f1e2261SMartin Matuska }
1487a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
1491f1e2261SMartin Matuska
1501f1e2261SMartin Matuska static int
zone_dataset_name_check(const char * dataset,size_t * dsnamelen)1511f1e2261SMartin Matuska zone_dataset_name_check(const char *dataset, size_t *dsnamelen)
1521f1e2261SMartin Matuska {
1531f1e2261SMartin Matuska
1541f1e2261SMartin Matuska if (dataset[0] == '\0' || dataset[0] == '/')
1551f1e2261SMartin Matuska return (ENOENT);
1561f1e2261SMartin Matuska
1571f1e2261SMartin Matuska *dsnamelen = strlen(dataset);
1581f1e2261SMartin Matuska /* Ignore trailing slash, if supplied. */
1591f1e2261SMartin Matuska if (dataset[*dsnamelen - 1] == '/')
1601f1e2261SMartin Matuska (*dsnamelen)--;
1611f1e2261SMartin Matuska
1621f1e2261SMartin Matuska return (0);
1631f1e2261SMartin Matuska }
1641f1e2261SMartin Matuska
1651f1e2261SMartin Matuska int
zone_dataset_attach(cred_t * cred,const char * dataset,int userns_fd)1661f1e2261SMartin Matuska zone_dataset_attach(cred_t *cred, const char *dataset, int userns_fd)
1671f1e2261SMartin Matuska {
1687a7741afSMartin Matuska #ifdef CONFIG_USER_NS
1691f1e2261SMartin Matuska struct user_namespace *userns;
1701f1e2261SMartin Matuska zone_datasets_t *zds;
1711f1e2261SMartin Matuska zone_dataset_t *zd;
1721f1e2261SMartin Matuska int error;
1731f1e2261SMartin Matuska size_t dsnamelen;
1741f1e2261SMartin Matuska
1751f1e2261SMartin Matuska if ((error = zone_dataset_cred_check(cred)) != 0)
1761f1e2261SMartin Matuska return (error);
1771f1e2261SMartin Matuska if ((error = zone_dataset_name_check(dataset, &dsnamelen)) != 0)
1781f1e2261SMartin Matuska return (error);
1791f1e2261SMartin Matuska if ((error = user_ns_get(userns_fd, &userns)) != 0)
1801f1e2261SMartin Matuska return (error);
1811f1e2261SMartin Matuska
1821f1e2261SMartin Matuska mutex_enter(&zone_datasets_lock);
1831f1e2261SMartin Matuska zds = zone_datasets_lookup(user_ns_zoneid(userns));
1841f1e2261SMartin Matuska if (zds == NULL) {
1851f1e2261SMartin Matuska zds = kmem_alloc(sizeof (zone_datasets_t), KM_SLEEP);
1861f1e2261SMartin Matuska INIT_LIST_HEAD(&zds->zds_list);
1871f1e2261SMartin Matuska INIT_LIST_HEAD(&zds->zds_datasets);
1881f1e2261SMartin Matuska zds->zds_userns = userns;
1891f1e2261SMartin Matuska /*
1901f1e2261SMartin Matuska * Lock the namespace by incresing its refcount to prevent
1911f1e2261SMartin Matuska * the namespace ID from being reused.
1921f1e2261SMartin Matuska */
1931f1e2261SMartin Matuska get_user_ns(userns);
1941f1e2261SMartin Matuska list_add_tail(&zds->zds_list, &zone_datasets);
1951f1e2261SMartin Matuska } else {
1961f1e2261SMartin Matuska zd = zone_dataset_lookup(zds, dataset, dsnamelen);
1971f1e2261SMartin Matuska if (zd != NULL) {
1981f1e2261SMartin Matuska mutex_exit(&zone_datasets_lock);
1991f1e2261SMartin Matuska return (EEXIST);
2001f1e2261SMartin Matuska }
2011f1e2261SMartin Matuska }
2021f1e2261SMartin Matuska
2031f1e2261SMartin Matuska zd = kmem_alloc(sizeof (zone_dataset_t) + dsnamelen + 1, KM_SLEEP);
2041f1e2261SMartin Matuska zd->zd_dsnamelen = dsnamelen;
205be181ee2SMartin Matuska strlcpy(zd->zd_dsname, dataset, dsnamelen + 1);
2061f1e2261SMartin Matuska INIT_LIST_HEAD(&zd->zd_list);
2071f1e2261SMartin Matuska list_add_tail(&zd->zd_list, &zds->zds_datasets);
2081f1e2261SMartin Matuska
2091f1e2261SMartin Matuska mutex_exit(&zone_datasets_lock);
2101f1e2261SMartin Matuska return (0);
2111f1e2261SMartin Matuska #else
2121f1e2261SMartin Matuska return (ENXIO);
2137a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
2141f1e2261SMartin Matuska }
2151f1e2261SMartin Matuska EXPORT_SYMBOL(zone_dataset_attach);
2161f1e2261SMartin Matuska
2171f1e2261SMartin Matuska int
zone_dataset_detach(cred_t * cred,const char * dataset,int userns_fd)2181f1e2261SMartin Matuska zone_dataset_detach(cred_t *cred, const char *dataset, int userns_fd)
2191f1e2261SMartin Matuska {
2207a7741afSMartin Matuska #ifdef CONFIG_USER_NS
2211f1e2261SMartin Matuska struct user_namespace *userns;
2221f1e2261SMartin Matuska zone_datasets_t *zds;
2231f1e2261SMartin Matuska zone_dataset_t *zd;
2241f1e2261SMartin Matuska int error;
2251f1e2261SMartin Matuska size_t dsnamelen;
2261f1e2261SMartin Matuska
2271f1e2261SMartin Matuska if ((error = zone_dataset_cred_check(cred)) != 0)
2281f1e2261SMartin Matuska return (error);
2291f1e2261SMartin Matuska if ((error = zone_dataset_name_check(dataset, &dsnamelen)) != 0)
2301f1e2261SMartin Matuska return (error);
2311f1e2261SMartin Matuska if ((error = user_ns_get(userns_fd, &userns)) != 0)
2321f1e2261SMartin Matuska return (error);
2331f1e2261SMartin Matuska
2341f1e2261SMartin Matuska mutex_enter(&zone_datasets_lock);
2351f1e2261SMartin Matuska zds = zone_datasets_lookup(user_ns_zoneid(userns));
2361f1e2261SMartin Matuska if (zds != NULL)
2371f1e2261SMartin Matuska zd = zone_dataset_lookup(zds, dataset, dsnamelen);
2381f1e2261SMartin Matuska if (zds == NULL || zd == NULL) {
2391f1e2261SMartin Matuska mutex_exit(&zone_datasets_lock);
2401f1e2261SMartin Matuska return (ENOENT);
2411f1e2261SMartin Matuska }
2421f1e2261SMartin Matuska
2431f1e2261SMartin Matuska list_del(&zd->zd_list);
2441f1e2261SMartin Matuska kmem_free(zd, sizeof (*zd) + zd->zd_dsnamelen + 1);
2451f1e2261SMartin Matuska
2461f1e2261SMartin Matuska /* Prune the namespace entry if it has no more delegations. */
2471f1e2261SMartin Matuska if (list_empty(&zds->zds_datasets)) {
2481f1e2261SMartin Matuska /*
2491f1e2261SMartin Matuska * Decrease the refcount now that the namespace is no longer
2501f1e2261SMartin Matuska * used. It is no longer necessary to prevent the namespace ID
2511f1e2261SMartin Matuska * from being reused.
2521f1e2261SMartin Matuska */
2531f1e2261SMartin Matuska put_user_ns(userns);
2541f1e2261SMartin Matuska list_del(&zds->zds_list);
2551f1e2261SMartin Matuska kmem_free(zds, sizeof (*zds));
2561f1e2261SMartin Matuska }
2571f1e2261SMartin Matuska
2581f1e2261SMartin Matuska mutex_exit(&zone_datasets_lock);
2591f1e2261SMartin Matuska return (0);
2601f1e2261SMartin Matuska #else
2611f1e2261SMartin Matuska return (ENXIO);
2627a7741afSMartin Matuska #endif /* CONFIG_USER_NS */
2631f1e2261SMartin Matuska }
2641f1e2261SMartin Matuska EXPORT_SYMBOL(zone_dataset_detach);
2651f1e2261SMartin Matuska
2661f1e2261SMartin Matuska /*
2671f1e2261SMartin Matuska * A dataset is visible if:
2681f1e2261SMartin Matuska * - It is a parent of a namespace entry.
2691f1e2261SMartin Matuska * - It is one of the namespace entries.
2701f1e2261SMartin Matuska * - It is a child of a namespace entry.
2711f1e2261SMartin Matuska *
2721f1e2261SMartin Matuska * A dataset is writable if:
2731f1e2261SMartin Matuska * - It is one of the namespace entries.
2741f1e2261SMartin Matuska * - It is a child of a namespace entry.
2751f1e2261SMartin Matuska *
2761f1e2261SMartin Matuska * The parent datasets of namespace entries are visible and
2771f1e2261SMartin Matuska * read-only to provide a path back to the root of the pool.
2781f1e2261SMartin Matuska */
2791f1e2261SMartin Matuska int
zone_dataset_visible(const char * dataset,int * write)2801f1e2261SMartin Matuska zone_dataset_visible(const char *dataset, int *write)
2811f1e2261SMartin Matuska {
2821f1e2261SMartin Matuska zone_datasets_t *zds;
2831f1e2261SMartin Matuska zone_dataset_t *zd;
2841f1e2261SMartin Matuska size_t dsnamelen, zd_len;
2851f1e2261SMartin Matuska int visible;
2861f1e2261SMartin Matuska
2871f1e2261SMartin Matuska /* Default to read-only, in case visible is returned. */
2881f1e2261SMartin Matuska if (write != NULL)
2891f1e2261SMartin Matuska *write = 0;
2901f1e2261SMartin Matuska if (zone_dataset_name_check(dataset, &dsnamelen) != 0)
2911f1e2261SMartin Matuska return (0);
2921f1e2261SMartin Matuska if (INGLOBALZONE(curproc)) {
2931f1e2261SMartin Matuska if (write != NULL)
2941f1e2261SMartin Matuska *write = 1;
2951f1e2261SMartin Matuska return (1);
2961f1e2261SMartin Matuska }
2971f1e2261SMartin Matuska
2981f1e2261SMartin Matuska mutex_enter(&zone_datasets_lock);
2991f1e2261SMartin Matuska zds = zone_datasets_lookup(crgetzoneid(curproc->cred));
3001f1e2261SMartin Matuska if (zds == NULL) {
3011f1e2261SMartin Matuska mutex_exit(&zone_datasets_lock);
3021f1e2261SMartin Matuska return (0);
3031f1e2261SMartin Matuska }
3041f1e2261SMartin Matuska
3051f1e2261SMartin Matuska visible = 0;
3061f1e2261SMartin Matuska list_for_each_entry(zd, &zds->zds_datasets, zd_list) {
3071f1e2261SMartin Matuska zd_len = strlen(zd->zd_dsname);
3081f1e2261SMartin Matuska if (zd_len > dsnamelen) {
3091f1e2261SMartin Matuska /*
3101f1e2261SMartin Matuska * The name of the namespace entry is longer than that
3111f1e2261SMartin Matuska * of the dataset, so it could be that the dataset is a
3121f1e2261SMartin Matuska * parent of the namespace entry.
3131f1e2261SMartin Matuska */
3141f1e2261SMartin Matuska visible = memcmp(zd->zd_dsname, dataset,
3151f1e2261SMartin Matuska dsnamelen) == 0 &&
3161f1e2261SMartin Matuska zd->zd_dsname[dsnamelen] == '/';
3171f1e2261SMartin Matuska if (visible)
3181f1e2261SMartin Matuska break;
3191f1e2261SMartin Matuska } else if (zd_len == dsnamelen) {
3201f1e2261SMartin Matuska /*
3211f1e2261SMartin Matuska * The name of the namespace entry is as long as that
3221f1e2261SMartin Matuska * of the dataset, so perhaps the dataset itself is the
3231f1e2261SMartin Matuska * namespace entry.
3241f1e2261SMartin Matuska */
3251f1e2261SMartin Matuska visible = memcmp(zd->zd_dsname, dataset, zd_len) == 0;
3261f1e2261SMartin Matuska if (visible) {
3271f1e2261SMartin Matuska if (write != NULL)
3281f1e2261SMartin Matuska *write = 1;
3291f1e2261SMartin Matuska break;
3301f1e2261SMartin Matuska }
3311f1e2261SMartin Matuska } else {
3321f1e2261SMartin Matuska /*
3331f1e2261SMartin Matuska * The name of the namespace entry is shorter than that
3341f1e2261SMartin Matuska * of the dataset, so perhaps the dataset is a child of
3351f1e2261SMartin Matuska * the namespace entry.
3361f1e2261SMartin Matuska */
3371f1e2261SMartin Matuska visible = memcmp(zd->zd_dsname, dataset,
3381f1e2261SMartin Matuska zd_len) == 0 && dataset[zd_len] == '/';
3391f1e2261SMartin Matuska if (visible) {
3401f1e2261SMartin Matuska if (write != NULL)
3411f1e2261SMartin Matuska *write = 1;
3421f1e2261SMartin Matuska break;
3431f1e2261SMartin Matuska }
3441f1e2261SMartin Matuska }
3451f1e2261SMartin Matuska }
3461f1e2261SMartin Matuska
3471f1e2261SMartin Matuska mutex_exit(&zone_datasets_lock);
3481f1e2261SMartin Matuska return (visible);
3491f1e2261SMartin Matuska }
3501f1e2261SMartin Matuska EXPORT_SYMBOL(zone_dataset_visible);
3511f1e2261SMartin Matuska
3521f1e2261SMartin Matuska unsigned int
global_zoneid(void)3531f1e2261SMartin Matuska global_zoneid(void)
3541f1e2261SMartin Matuska {
3551f1e2261SMartin Matuska unsigned int z = 0;
3561f1e2261SMartin Matuska
3571f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
3581f1e2261SMartin Matuska z = user_ns_zoneid(&init_user_ns);
3591f1e2261SMartin Matuska #endif
3601f1e2261SMartin Matuska
3611f1e2261SMartin Matuska return (z);
3621f1e2261SMartin Matuska }
3631f1e2261SMartin Matuska EXPORT_SYMBOL(global_zoneid);
3641f1e2261SMartin Matuska
3651f1e2261SMartin Matuska unsigned int
crgetzoneid(const cred_t * cr)3661f1e2261SMartin Matuska crgetzoneid(const cred_t *cr)
3671f1e2261SMartin Matuska {
3681f1e2261SMartin Matuska unsigned int r = 0;
3691f1e2261SMartin Matuska
3701f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
3711f1e2261SMartin Matuska r = user_ns_zoneid(cr->user_ns);
3721f1e2261SMartin Matuska #endif
3731f1e2261SMartin Matuska
3741f1e2261SMartin Matuska return (r);
3751f1e2261SMartin Matuska }
3761f1e2261SMartin Matuska EXPORT_SYMBOL(crgetzoneid);
3771f1e2261SMartin Matuska
3781f1e2261SMartin Matuska boolean_t
inglobalzone(proc_t * proc)3791f1e2261SMartin Matuska inglobalzone(proc_t *proc)
3801f1e2261SMartin Matuska {
3811f1e2261SMartin Matuska #if defined(CONFIG_USER_NS)
3821f1e2261SMartin Matuska return (proc->cred->user_ns == &init_user_ns);
3831f1e2261SMartin Matuska #else
3841f1e2261SMartin Matuska return (B_TRUE);
3851f1e2261SMartin Matuska #endif
3861f1e2261SMartin Matuska }
3871f1e2261SMartin Matuska EXPORT_SYMBOL(inglobalzone);
3881f1e2261SMartin Matuska
3891f1e2261SMartin Matuska int
spl_zone_init(void)3901f1e2261SMartin Matuska spl_zone_init(void)
3911f1e2261SMartin Matuska {
3921f1e2261SMartin Matuska mutex_init(&zone_datasets_lock, NULL, MUTEX_DEFAULT, NULL);
3931f1e2261SMartin Matuska INIT_LIST_HEAD(&zone_datasets);
3941f1e2261SMartin Matuska return (0);
3951f1e2261SMartin Matuska }
3961f1e2261SMartin Matuska
3971f1e2261SMartin Matuska void
spl_zone_fini(void)3981f1e2261SMartin Matuska spl_zone_fini(void)
3991f1e2261SMartin Matuska {
4001f1e2261SMartin Matuska zone_datasets_t *zds;
4011f1e2261SMartin Matuska zone_dataset_t *zd;
4021f1e2261SMartin Matuska
4031f1e2261SMartin Matuska /*
4041f1e2261SMartin Matuska * It would be better to assert an empty zone_datasets, but since
4051f1e2261SMartin Matuska * there's no automatic mechanism for cleaning them up if the user
4061f1e2261SMartin Matuska * namespace is destroyed, just do it here, since spl is about to go
4071f1e2261SMartin Matuska * out of context.
4081f1e2261SMartin Matuska */
4091f1e2261SMartin Matuska while (!list_empty(&zone_datasets)) {
4101f1e2261SMartin Matuska zds = list_entry(zone_datasets.next, zone_datasets_t, zds_list);
4111f1e2261SMartin Matuska while (!list_empty(&zds->zds_datasets)) {
4121f1e2261SMartin Matuska zd = list_entry(zds->zds_datasets.next,
4131f1e2261SMartin Matuska zone_dataset_t, zd_list);
4141f1e2261SMartin Matuska list_del(&zd->zd_list);
4151f1e2261SMartin Matuska kmem_free(zd, sizeof (*zd) + zd->zd_dsnamelen + 1);
4161f1e2261SMartin Matuska }
417c7046f76SMartin Matuska put_user_ns(zds->zds_userns);
4181f1e2261SMartin Matuska list_del(&zds->zds_list);
4191f1e2261SMartin Matuska kmem_free(zds, sizeof (*zds));
4201f1e2261SMartin Matuska }
4211f1e2261SMartin Matuska mutex_destroy(&zone_datasets_lock);
4221f1e2261SMartin Matuska }
423