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