2fa9e406ahrens * CDDL HEADER START
3fa9e406ahrens *
4fa9e406ahrens * The contents of this file are subject to the terms of the
5441d80alling * Common Development and Distribution License (the "License").
6441d80alling * You may not use this file except in compliance with the License.
7fa9e406ahrens *
8fa9e406ahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e406ahrens * or http://www.opensolaris.org/os/licensing.
10fa9e406ahrens * See the License for the specific language governing permissions
11fa9e406ahrens * and limitations under the License.
12fa9e406ahrens *
13fa9e406ahrens * When distributing Covered Code, include this CDDL HEADER in each
14fa9e406ahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e406ahrens * If applicable, add the following below this CDDL HEADER, with the
16fa9e406ahrens * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e406ahrens * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e406ahrens *
19fa9e406ahrens * CDDL HEADER END
20fa9e406ahrens */
21ad135b5Christopher Siden
233f9d6adLin Ling * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
240d8fa8fMartin Matuska * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
251df56adMartin Matuska * Portions Copyright 2011 Martin Matuska
265878fadDan McDonald * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
276ccda74loli * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
2828df1aeJason King * Copyright 2019 Joyent, Inc.
292840dceChris Williamson * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
30a6f561bSašo Kiselkov * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
31a7a845eSteven Hartland * Copyright (c) 2013 Steven Hartland. All rights reserved.
32c3d26abMatthew Ahrens * Copyright (c) 2014 Integros [integros.com]
33c8811bdToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com>
346ccda74loli * Copyright (c) 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
35a4b8c9aAndrew Stormont * Copyright 2017 RackTop Systems.
36eb63303Tom Caputi * Copyright (c) 2017, Datto, Inc. All rights reserved.
374445fffMatthew Ahrens */
384445fffMatthew Ahrens
394445fffMatthew Ahrens/*
404445fffMatthew Ahrens * ZFS ioctls.
414445fffMatthew Ahrens *
424445fffMatthew Ahrens * This file handles the ioctls to /dev/zfs, used for configuring ZFS storage
434445fffMatthew Ahrens * pools and filesystems, e.g. with /sbin/zfs and /sbin/zpool.
444445fffMatthew Ahrens *
454445fffMatthew Ahrens * There are two ways that we handle ioctls: the legacy way where almost
464445fffMatthew Ahrens * all of the logic is in the ioctl callback, and the new way where most
474445fffMatthew Ahrens * of the marshalling is handled in the common entry point, zfsdev_ioctl().
484445fffMatthew Ahrens *
494445fffMatthew Ahrens * Non-legacy ioctls should be registered by calling
504445fffMatthew Ahrens * zfs_ioctl_register() from zfs_ioctl_init().  The ioctl is invoked
514445fffMatthew Ahrens * from userland by lzc_ioctl().
524445fffMatthew Ahrens *
534445fffMatthew Ahrens * The registration arguments are as follows:
544445fffMatthew Ahrens *
554445fffMatthew Ahrens * const char *name
564445fffMatthew Ahrens *   The name of the ioctl.  This is used for history logging.  If the
574445fffMatthew Ahrens *   ioctl returns successfully (the callback returns 0), and allow_log
584445fffMatthew Ahrens *   is true, then a history log entry will be recorded with the input &
594445fffMatthew Ahrens *   output nvlists.  The log entry can be printed with "zpool history -i".
604445fffMatthew Ahrens *
614445fffMatthew Ahrens * zfs_ioc_t ioc
624445fffMatthew Ahrens *   The ioctl request number, which userland will pass to ioctl(2).
634445fffMatthew Ahrens *   The ioctl numbers can change from release to release, because
644445fffMatthew Ahrens *   the caller (libzfs) must be matched to the kernel.
654445fffMatthew Ahrens *
664445fffMatthew Ahrens * zfs_secpolicy_func_t *secpolicy
674445fffMatthew Ahrens *   This function will be called before the zfs_ioc_func_t, to
684445fffMatthew Ahrens *   determine if this operation is permitted.  It should return EPERM
694445fffMatthew Ahrens *   on failure, and 0 on success.  Checks include determining if the
704445fffMatthew Ahrens *   dataset is visible in this zone, and if the user has either all
714445fffMatthew Ahrens *   zfs privileges in the zone (SYS_MOUNT), or has been granted permission
724445fffMatthew Ahrens *   to do this operation on this dataset with "zfs allow".
734445fffMatthew Ahrens *
744445fffMatthew Ahrens * zfs_ioc_namecheck_t namecheck
754445fffMatthew Ahrens *   This specifies what to expect in the zfs_cmd_t:zc_name -- a pool
764445fffMatthew Ahrens *   name, a dataset name, or nothing.  If the name is not well-formed,
774445fffMatthew Ahrens *   the ioctl will fail and the callback will not be called.
784445fffMatthew Ahrens *   Therefore, the callback can assume that the name is well-formed
794445fffMatthew Ahrens *   (e.g. is null-terminated, doesn't have more than one '@' character,
804445fffMatthew Ahrens *   doesn't have invalid characters).
814445fffMatthew Ahrens *
824445fffMatthew Ahrens * zfs_ioc_poolcheck_t pool_check
834445fffMatthew Ahrens *   This specifies requirements on the pool state.  If the pool does
844445fffMatthew Ahrens *   not meet them (is suspended or is readonly), the ioctl will fail
854445fffMatthew Ahrens *   and the callback will not be called.  If any checks are specified
864445fffMatthew Ahrens *   (i.e. it is not POOL_CHECK_NONE), namecheck must not be NO_NAME.
874445fffMatthew Ahrens *   Multiple checks can be or-ed together (e.g. POOL_CHECK_SUSPENDED |
884445fffMatthew Ahrens *   POOL_CHECK_READONLY).
894445fffMatthew Ahrens *
904445fffMatthew Ahrens * boolean_t smush_outnvlist
914445fffMatthew Ahrens *   If smush_outnvlist is true, then the output is presumed to be a
924445fffMatthew Ahrens *   list of errors, and it will be "smushed" down to fit into the
934445fffMatthew Ahrens *   caller's buffer, by removing some entries and replacing them with a
944445fffMatthew Ahrens *   single "N_MORE_ERRORS" entry indicating how many were removed.  See
954445fffMatthew Ahrens *   nvlist_smush() for details.  If smush_outnvlist is false, and the
964445fffMatthew Ahrens *   outnvlist does not fit into the userland-provided buffer, then the
974445fffMatthew Ahrens *   ioctl will fail with ENOMEM.
984445fffMatthew Ahrens *
994445fffMatthew Ahrens * zfs_ioc_func_t *func
1004445fffMatthew Ahrens *   The callback function that will perform the operation.
1014445fffMatthew Ahrens *
1024445fffMatthew Ahrens *   The callback should return 0 on success, or an error number on
1034445fffMatthew Ahrens *   failure.  If the function fails, the userland ioctl will return -1,
1044445fffMatthew Ahrens *   and errno will be set to the callback's return value.  The callback
1054445fffMatthew Ahrens *   will be called with the following arguments:
1064445fffMatthew Ahrens *
1074445fffMatthew Ahrens *   const char *name
1084445fffMatthew Ahrens *     The name of the pool or dataset to operate on, from
1094445fffMatthew Ahrens *     zfs_cmd_t:zc_name.  The 'namecheck' argument specifies the
1104445fffMatthew Ahrens *     expected type (pool, dataset, or none).
1114445fffMatthew Ahrens *
1124445fffMatthew Ahrens *   nvlist_t *innvl
1134445fffMatthew Ahrens *     The input nvlist, deserialized from zfs_cmd_t:zc_nvlist_src.  Or
1144445fffMatthew Ahrens *     NULL if no input nvlist was provided.  Changes to this nvlist are
1154445fffMatthew Ahrens *     ignored.  If the input nvlist could not be deserialized, the
1164445fffMatthew Ahrens *     ioctl will fail and the callback will not be called.
1174445fffMatthew Ahrens *
1184445fffMatthew Ahrens *   nvlist_t *outnvl
1194445fffMatthew Ahrens *     The output nvlist, initially empty.  The callback can fill it in,
1204445fffMatthew Ahrens *     and it will be returned to userland by serializing it into
1214445fffMatthew Ahrens *     zfs_cmd_t:zc_nvlist_dst.  If it is non-empty, and serialization
1224445fffMatthew Ahrens *     fails (e.g. because the caller didn't supply a large enough
1234445fffMatthew Ahrens *     buffer), then the overall ioctl will fail.  See the
1244445fffMatthew Ahrens *     'smush_nvlist' argument above for additional behaviors.
1254445fffMatthew Ahrens *
1264445fffMatthew Ahrens *     There are two typical uses of the output nvlist:
1274445fffMatthew Ahrens *       - To return state, e.g. property values.  In this case,
1284445fffMatthew Ahrens *         smush_outnvlist should be false.  If the buffer was not large
1294445fffMatthew Ahrens *         enough, the caller will reallocate a larger buffer and try
1304445fffMatthew Ahrens *         the ioctl again.
1314445fffMatthew Ahrens *
1324445fffMatthew Ahrens *       - To return multiple errors from an ioctl which makes on-disk
1334445fffMatthew Ahrens *         changes.  In this case, smush_outnvlist should be true.
1344445fffMatthew Ahrens *         Ioctls which make on-disk modifications should generally not
1354445fffMatthew Ahrens *         use the outnvl if they succeed, because the caller can not
1364445fffMatthew Ahrens *         distinguish between the operation failing, and
1374445fffMatthew Ahrens *         deserialization failing.
138e9103aaGarrett D'Amore */
140fa9e406ahrens#include <sys/types.h>
141fa9e406ahrens#include <sys/param.h>
142fa9e406ahrens#include <sys/errno.h>
143fa9e406ahrens#include <sys/uio.h>
144fa9e406ahrens#include <sys/buf.h>
145fa9e406ahrens#include <sys/modctl.h>
146fa9e406ahrens#include <sys/open.h>
147fa9e406ahrens#include <sys/file.h>
148fa9e406ahrens#include <sys/kmem.h>
149fa9e406ahrens#include <sys/conf.h>
150fa9e406ahrens#include <sys/cmn_err.h>
151fa9e406ahrens#include <sys/stat.h>
152fa9e406ahrens#include <sys/zfs_ioctl.h>
1534201a95Ric Aleshire#include <sys/zfs_vfsops.h>
154da6c28aamw#include <sys/zfs_znode.h>
155fa9e406ahrens#include <sys/zap.h>
156fa9e406ahrens#include <sys/spa.h>
157b1b8ab3lling#include <sys/spa_impl.h>
158fa9e406ahrens#include <sys/vdev.h>
1594201a95Ric Aleshire#include <sys/priv_impl.h>
160fa9e406ahrens#include <sys/dmu.h>
161fa9e406ahrens#include <sys/dsl_dir.h>
162fa9e406ahrens#include <sys/dsl_dataset.h>
163fa9e406ahrens#include <sys/dsl_prop.h>
164ecd6cf8marks#include <sys/dsl_deleg.h>
165ecd6cf8marks#include <sys/dmu_objset.h>
1664e3c9f4Bill Pijewski#include <sys/dmu_impl.h>
1673b2aab1Matthew Ahrens#include <sys/dmu_tx.h>
168fa9e406ahrens#include <sys/ddi.h>
169fa9e406ahrens#include <sys/sunddi.h>
170fa9e406ahrens#include <sys/sunldi.h>
171fa9e406ahrens#include <sys/policy.h>
172fa9e406ahrens#include <sys/zone.h>
173fa9e406ahrens#include <sys/nvpair.h>
174fa9e406ahrens#include <sys/pathname.h>
175fa9e406ahrens#include <sys/mount.h>
176fa9e406ahrens#include <sys/sdt.h>
177fa9e406ahrens#include <sys/fs/zfs.h>
178fa9e406ahrens#include <sys/zfs_ctldir.h>
179da6c28aamw#include <sys/zfs_dir.h>
180c99e4bdChris Kirby#include <sys/zfs_onexit.h>
181a2eea2eahrens#include <sys/zvol.h>
1823f9d6adLin Ling#include <sys/dsl_scan.h>
183ecd6cf8marks#include <sharefs/share.h>
184f18faf3ek#include <sys/dmu_objset.h>
1850fa1b3cPaul Dagnelie#include <sys/dmu_recv.h>
1863b2aab1Matthew Ahrens#include <sys/dmu_send.h>
1873b2aab1Matthew Ahrens#include <sys/dsl_destroy.h>
18878f1710Matthew Ahrens#include <sys/dsl_bookmark.h>
1893b2aab1Matthew Ahrens#include <sys/dsl_userhold.h>
190a6f561bSašo Kiselkov#include <sys/zfeature.h>
191dfc1153Chris Williamson#include <sys/zcp.h>
19245818eeMatthew Ahrens#include <sys/zio_checksum.h>
1935cabbc6Prashanth Sreenivasa#include <sys/vdev_removal.h>
194094e47eGeorge Wilson#include <sys/vdev_impl.h>
195094e47eGeorge Wilson#include <sys/vdev_initialize.h>
196084fd14Brian Behlendorf#include <sys/vdev_trim.h>
197eb63303Tom Caputi#include <sys/dsl_crypt.h>
199fa9e406ahrens#include "zfs_namecheck.h"
200e9dbad6eschrock#include "zfs_prop.h"
201ecd6cf8marks#include "zfs_deleg.h"
2020a586ceMark Shellenbaum#include "zfs_comutil.h"
204dfc1153Chris Williamson#include "lua.h"
205dfc1153Chris Williamson#include "lauxlib.h"
206dfc1153Chris Williamson
207fa9e406ahrensextern struct modlfs zfs_modlfs;
209fa9e406ahrensextern void zfs_init(void);
210fa9e406ahrensextern void zfs_fini(void);
212fa9e406ahrensldi_ident_t zfs_li = NULL;
213fa9e406ahrensdev_info_t *zfs_dip;
2154445fffMatthew Ahrensuint_t zfs_fsyncer_key;
2164445fffMatthew Ahrensextern uint_t rrw_tsd_key;
2174445fffMatthew Ahrensstatic uint_t zfs_allow_log_key;
2184445fffMatthew Ahrens
2194445fffMatthew Ahrenstypedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
2204445fffMatthew Ahrenstypedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
2214445fffMatthew Ahrenstypedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
22354d692bGeorge Wilsontypedef enum {
22454d692bGeorge Wilson	NO_NAME,
22554d692bGeorge Wilson	POOL_NAME,
22654d692bGeorge Wilson	DATASET_NAME
22754d692bGeorge Wilson} zfs_ioc_namecheck_t;
22854d692bGeorge Wilson
229f9af39bGeorge Wilsontypedef enum {
230f9af39bGeorge Wilson	POOL_CHECK_NONE		= 1 << 0,
231f9af39bGeorge Wilson	POOL_CHECK_SUSPENDED	= 1 << 1,
2324445fffMatthew Ahrens	POOL_CHECK_READONLY	= 1 << 2,
233f9af39bGeorge Wilson} zfs_ioc_poolcheck_t;
234f9af39bGeorge Wilson
235fa9e406ahrenstypedef struct zfs_ioc_vec {
2364445fffMatthew Ahrens	zfs_ioc_legacy_func_t	*zvec_legacy_func;
237fa9e406ahrens	zfs_ioc_func_t		*zvec_func;
238fa9e406ahrens	zfs_secpolicy_func_t	*zvec_secpolicy;
23954d692bGeorge Wilson	zfs_ioc_namecheck_t	zvec_namecheck;
2404445fffMatthew Ahrens	boolean_t		zvec_allow_log;
241f9af39bGeorge Wilson	zfs_ioc_poolcheck_t	zvec_pool_check;
2424445fffMatthew Ahrens	boolean_t		zvec_smush_outnvlist;
2434445fffMatthew Ahrens	const char		*zvec_name;
244fa9e406ahrens} zfs_ioc_vec_t;
2461484342Matthew Ahrens/* This array is indexed by zfs_userquota_prop_t */
2471484342Matthew Ahrensstatic const char *userquota_perms[] = {
2481484342Matthew Ahrens	ZFS_DELEG_PERM_USERUSED,
2491484342Matthew Ahrens	ZFS_DELEG_PERM_USERQUOTA,
2501484342Matthew Ahrens	ZFS_DELEG_PERM_GROUPUSED,
2511484342Matthew Ahrens	ZFS_DELEG_PERM_GROUPQUOTA,
2601484342Matthew Ahrens};
2611484342Matthew Ahrens
2621484342Matthew Ahrensstatic int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc);
263f67950bNasf-Fanstatic int zfs_ioc_id_quota_upgrade(zfs_cmd_t *zc);
26492241e0Tom Ericksonstatic int zfs_check_settable(const char *name, nvpair_t *property,
26592241e0Tom Erickson    cred_t *cr);
26692241e0Tom Ericksonstatic int zfs_check_clearable(char *dataset, nvlist_t *props,
26792241e0Tom Erickson    nvlist_t **errors);
2680a48a24timhstatic int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *,
2690a48a24timh    boolean_t *);
2704445fffMatthew Ahrensint zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *);
2714445fffMatthew Ahrensstatic int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp);
2732acef22Matthew Ahrensstatic int zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature);
274a6f561bSašo Kiselkov
275fa9e406ahrens/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
277fa9e406ahrens__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
279fa9e406ahrens	const char *newfile;
2803f9d6adLin Ling	char buf[512];
281fa9e406ahrens	va_list adx;
283fa9e406ahrens	/*
284fa9e406ahrens	 * Get rid of annoying "../common/" prefix to filename.
285fa9e406ahrens	 */
286fa9e406ahrens	newfile = strrchr(file, '/');
287fa9e406ahrens	if (newfile != NULL) {
288fa9e406ahrens		newfile = newfile + 1; /* Get rid of leading / */
289fa9e406ahrens	} else {
290fa9e406ahrens		newfile = file;
291fa9e406ahrens	}
293fa9e406ahrens	va_start(adx, fmt);
294fa9e406ahrens	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
295fa9e406ahrens	va_end(adx);
297fa9e406ahrens	/*
298fa9e406ahrens	 * To get this data, use the zfs-dprintf probe as so:
299fa9e406ahrens	 * dtrace -q -n 'zfs-dprintf \
300fa9e406ahrens	 *	/stringof(arg0) == "dbuf.c"/ \
301fa9e406ahrens	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
302fa9e406ahrens	 * arg0 = file name
303fa9e406ahrens	 * arg1 = function name
304fa9e406ahrens	 * arg2 = line number
305fa9e406ahrens	 * arg3 = message
306fa9e406ahrens	 */
307fa9e406ahrens	DTRACE_PROBE4(zfs__dprintf,
308fa9e406ahrens	    char *, newfile, char *, func, int, line, char *, buf);
311ecd6cf8marksstatic void
312228975cekhistory_str_free(char *buf)
314228975cek	kmem_free(buf, HIS_MAX_RECORD_LEN);
317228975cekstatic char *
318228975cekhistory_str_get(zfs_cmd_t *zc)
32040feaa9ahrens	char *buf;
322dd328bfToomas Soome	if (zc->zc_history == 0)
323228975cek		return (NULL);
325ecd6cf8marks	buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP);
326ecd6cf8marks	if (copyinstr((void *)(uintptr_t)zc->zc_history,
327ecd6cf8marks	    buf, HIS_MAX_RECORD_LEN, NULL) != 0) {
328228975cek		history_str_free(buf);
329228975cek		return (NULL);
330ecd6cf8marks	}
332ecd6cf8marks	buf[HIS_MAX_RECORD_LEN -1] = '\0';
334228975cek	return (buf);
33815e6edfgw * Check to see if the named dataset is currently defined as bootable
33915e6edfgw */
34015e6edfgwstatic boolean_t
34115e6edfgwzfs_is_bootfs(const char *name)
343503ad85Matthew Ahrens	objset_t *os;
345503ad85Matthew Ahrens	if (dmu_objset_hold(name, FTAG, &os) == 0) {
346503ad85Matthew Ahrens		boolean_t ret;
347b24ab67Jeff Bonwick		ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os)));
348503ad85Matthew Ahrens		dmu_objset_rele(os, FTAG);
349503ad85Matthew Ahrens		return (ret);
35015e6edfgw	}
351503ad85Matthew Ahrens	return (B_FALSE);
355f717074Will Andrews * Return non-zero if the spa version is less than requested version.
356c2a93d4timh */
357da6c28aamwstatic int
3580a48a24timhzfs_earlier_version(const char *name, int version)
360da6c28aamw	spa_t *spa;
362da6c28aamw	if (spa_open(name, &spa, FTAG) == 0) {
363da6c28aamw		if (spa_version(spa) < version) {
364da6c28aamw			spa_close(spa, FTAG);
365da6c28aamw			return (1);
366da6c28aamw		}
367da6c28aamw		spa_close(spa, FTAG);
368da6c28aamw	}
369da6c28aamw	return (0);
373745cd3cmaybee * Return TRUE if the ZPL version is less than requested version.
3749e6eda5marks */
375745cd3cmaybeestatic boolean_t
376745cd3cmaybeezpl_earlier_version(const char *name, int version)
3789e6eda5marks	objset_t *os;
379745cd3cmaybee	boolean_t rc = B_TRUE;
381503ad85Matthew Ahrens	if (dmu_objset_hold(name, FTAG, &os) == 0) {
382745cd3cmaybee		uint64_t zplversion;
384503ad85Matthew Ahrens		if (dmu_objset_type(os) != DMU_OST_ZFS) {
385503ad85Matthew Ahrens			dmu_objset_rele(os, FTAG);
386503ad85Matthew Ahrens			return (B_TRUE);
387503ad85Matthew Ahrens		}
388503ad85Matthew Ahrens		/* XXX reading from non-owned objset */
389745cd3cmaybee		if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0)
390745cd3cmaybee			rc = zplversion < version;
391503ad85Matthew Ahrens		dmu_objset_rele(os, FTAG);
3929e6eda5marks	}
3939e6eda5marks	return (rc);
396228975cekstatic void
397228975cekzfs_log_history(zfs_cmd_t *zc)
399228975cek	spa_t *spa;
400228975cek	char *buf;
402228975cek	if ((buf = history_str_get(zc)) == NULL)
403228975cek		return;
405228975cek	if (spa_open(zc->zc_name, &spa, FTAG) == 0) {
406228975cek		if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
4074445fffMatthew Ahrens			(void) spa_history_log(spa, buf);
408228975cek		spa_close(spa, FTAG);
409228975cek	}
410228975cek	history_str_free(buf);
414fa9e406ahrens * Policy for top-level read operations (list pools).  Requires no privileges,
415fa9e406ahrens * and can be used in the local zone, as there is no associated dataset.
416fa9e406ahrens */
417fa9e406ahrens/* ARGSUSED */
418fa9e406ahrensstatic int
4194445fffMatthew Ahrenszfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
421fa9e406ahrens	return (0);
425fa9e406ahrens * Policy for dataset read operations (list children, get statistics).  Requires
426fa9e406ahrens * no privileges, but must be visible in the local zone.
427fa9e406ahrens */
428fa9e406ahrens/* ARGSUSED */
429fa9e406ahrensstatic int
4304445fffMatthew Ahrenszfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
432fa9e406ahrens	if (INGLOBALZONE(curproc) ||
433ecd6cf8marks	    zone_dataset_visible(zc->zc_name, NULL))
434fa9e406ahrens		return (0);
436be6fd75Matthew Ahrens	return (SET_ERROR(ENOENT));
439fa9e406ahrensstatic int
440a7f53a5Chris Kirbyzfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr)
442fa9e406ahrens	int writable = 1;
444fa9e406ahrens	/*
445fa9e406ahrens	 * The dataset must be visible by this zone -- check this first
446fa9e406ahrens	 * so they don't see EPERM on something they shouldn't know about.
447fa9e406ahrens	 */
448fa9e406ahrens	if (!INGLOBALZONE(curproc) &&
449fa9e406ahrens	    !zone_dataset_visible(dataset, &writable))
450be6fd75Matthew Ahrens		return (SET_ERROR(ENOENT));
452fa9e406ahrens	if (INGLOBALZONE(curproc)) {
453fa9e406ahrens		/*
454fa9e406ahrens		 * If the fs is zoned, only root can access it from the
455fa9e406ahrens		 * global zone.
456fa9e406ahrens		 */
457fa9e406ahrens		if (secpolicy_zfs(cr) && zoned)
458be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
459fa9e406ahrens	} else {
460fa9e406ahrens		/*
461fa9e406ahrens		 * If we are in a local zone, the 'zoned' property must be set.
462fa9e406ahrens		 */
463fa9e406ahrens		if (!zoned)
464be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
466fa9e406ahrens		/* must be writable by this zone */
467fa9e406ahrens		if (!writable)
468be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
469fa9e406ahrens	}
470fa9e406ahrens	return (0);
473a7f53a5Chris Kirbystatic int
474a7f53a5Chris Kirbyzfs_dozonecheck(const char *dataset, cred_t *cr)
475a7f53a5Chris Kirby{
476a7f53a5Chris Kirby	uint64_t zoned;
477a7f53a5Chris Kirby
478a7f53a5Chris Kirby	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
479be6fd75Matthew Ahrens		return (SET_ERROR(ENOENT));
480a7f53a5Chris Kirby
481a7f53a5Chris Kirby	return (zfs_dozonecheck_impl(dataset, zoned, cr));
482a7f53a5Chris Kirby}
483a7f53a5Chris Kirby
484a7f53a5Chris Kirbystatic int
485a7f53a5Chris Kirbyzfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr)
486a7f53a5Chris Kirby{
487a7f53a5Chris Kirby	uint64_t zoned;
488a7f53a5Chris Kirby
4893b2aab1Matthew Ahrens	if (dsl_prop_get_int_ds(ds, "zoned", &zoned))
490be6fd75Matthew Ahrens		return (SET_ERROR(ENOENT));
491a7f53a5Chris Kirby
492a7f53a5Chris Kirby	return (zfs_dozonecheck_impl(dataset, zoned, cr));
493a7f53a5Chris Kirby}
494a7f53a5Chris Kirby
4954445fffMatthew Ahrensstatic int
4963b2aab1Matthew Ahrenszfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds,
4973b2aab1Matthew Ahrens    const char *perm, cred_t *cr)
499fa9e406ahrens	int error;
50119b94dfMatthew Ahrens	error = zfs_dozonecheck_ds(name, ds, cr);
502ecd6cf8marks	if (error == 0) {
503ecd6cf8marks		error = secpolicy_zfs(cr);
5043b2aab1Matthew Ahrens		if (error != 0)
5054445fffMatthew Ahrens			error = dsl_deleg_access_impl(ds, perm, cr);
506ecd6cf8marks	}
507ecd6cf8marks	return (error);
5104445fffMatthew Ahrensstatic int
5113b2aab1Matthew Ahrenszfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
512a7f53a5Chris Kirby{
513a7f53a5Chris Kirby	int error;
5143b2aab1Matthew Ahrens	dsl_dataset_t *ds;
5153b2aab1Matthew Ahrens	dsl_pool_t *dp;
516a7f53a5Chris Kirby
51725f7d99Matthew Ahrens	/*
51825f7d99Matthew Ahrens	 * First do a quick check for root in the global zone, which
51925f7d99Matthew Ahrens	 * is allowed to do all write_perms.  This ensures that zfs_ioc_*
52025f7d99Matthew Ahrens	 * will get to handle nonexistent datasets.
52125f7d99Matthew Ahrens	 */
52225f7d99Matthew Ahrens	if (INGLOBALZONE(curproc) && secpolicy_zfs(cr) == 0)
52325f7d99Matthew Ahrens		return (0);
52425f7d99Matthew Ahrens
5253b2aab1Matthew Ahrens	error = dsl_pool_hold(name, FTAG, &dp);
5263b2aab1Matthew Ahrens	if (error != 0)
5273b2aab1Matthew Ahrens		return (error);
5283b2aab1Matthew Ahrens
5293b2aab1Matthew Ahrens	error = dsl_dataset_hold(dp, name, FTAG, &ds);
5303b2aab1Matthew Ahrens	if (error != 0) {
5313b2aab1Matthew Ahrens		dsl_pool_rele(dp, FTAG);
5323b2aab1Matthew Ahrens		return (error);
533a7f53a5Chris Kirby	}
5343b2aab1Matthew Ahrens
5353b2aab1Matthew Ahrens	error = zfs_secpolicy_write_perms_ds(name, ds, perm, cr);
5363b2aab1Matthew Ahrens
5373b2aab1Matthew Ahrens	dsl_dataset_rele(ds, FTAG);
5383b2aab1Matthew Ahrens	dsl_pool_rele(dp, FTAG);
539a7f53a5Chris Kirby	return (error);
540a7f53a5Chris Kirby}
541a7f53a5Chris Kirby
5424201a95Ric Aleshire/*
5434201a95Ric Aleshire * Policy for setting the security label property.
5444201a95Ric Aleshire *
5454201a95Ric Aleshire * Returns 0 for success, non-zero for access and other errors.
5464201a95Ric Aleshire */
5474201a95Ric Aleshirestatic int
54892241e0Tom Ericksonzfs_set_slabel_policy(const char *name, char *strval, cred_t *cr)
5494201a95Ric Aleshire{
5504201a95Ric Aleshire	char		ds_hexsl[MAXNAMELEN];
5514201a95Ric Aleshire	bslabel_t	ds_sl, new_sl;
5524201a95Ric Aleshire	boolean_t	new_default = FALSE;
5534201a95Ric Aleshire	uint64_t	zoned;
5544201a95Ric Aleshire	int		needed_priv = -1;
5554201a95Ric Aleshire	int		error;
5564201a95Ric Aleshire
5574201a95Ric Aleshire	/* First get the existing dataset label. */
5584201a95Ric Aleshire	error = dsl_prop_get(name, zfs_prop_to_name(ZFS_PROP_MLSLABEL),
5594201a95Ric Aleshire	    1, sizeof (ds_hexsl), &ds_hexsl, NULL);
5603b2aab1Matthew Ahrens	if (error != 0)
561be6fd75Matthew Ahrens		return (SET_ERROR(EPERM));
5624201a95Ric Aleshire
5634201a95Ric Aleshire	if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
5644201a95Ric Aleshire		new_default = TRUE;
5654201a95Ric Aleshire
5664201a95Ric Aleshire	/* The label must be translatable */
5674201a95Ric Aleshire	if (!new_default && (hexstr_to_label(strval, &new_sl) != 0))
568be6fd75Matthew Ahrens		return (SET_ERROR(EINVAL));
5694201a95Ric Aleshire
5704201a95Ric Aleshire	/*
5714201a95Ric Aleshire	 * In a non-global zone, disallow attempts to set a label that
5724201a95Ric Aleshire	 * doesn't match that of the zone; otherwise no other checks
5734201a95Ric Aleshire	 * are needed.
5744201a95Ric Aleshire	 */
5754201a95Ric Aleshire	if (!INGLOBALZONE(curproc)) {
5764201a95Ric Aleshire		if (new_default || !blequal(&new_sl, CR_SL(CRED())))
577be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
5784201a95Ric Aleshire		return (0);
5794201a95Ric Aleshire	}
5804201a95Ric Aleshire
5814201a95Ric Aleshire	/*
5824201a95Ric Aleshire	 * For global-zone datasets (i.e., those whose zoned property is
5834201a95Ric Aleshire	 * "off", verify that the specified new label is valid for the
5844201a95Ric Aleshire	 * global zone.
5854201a95Ric Aleshire	 */
5864201a95Ric Aleshire	if (dsl_prop_get_integer(name,
5874201a95Ric Aleshire	    zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL))
588be6fd75Matthew Ahrens		return (SET_ERROR(EPERM));
5894201a95Ric Aleshire	if (!zoned) {
5904201a95Ric Aleshire		if (zfs_check_global_label(name, strval) != 0)
591be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
5924201a95Ric Aleshire	}
5934201a95Ric Aleshire
5944201a95Ric Aleshire	/*
5954201a95Ric Aleshire	 * If the existing dataset label is nondefault, check if the
5964201a95Ric Aleshire	 * dataset is mounted (label cannot be changed while mounted).
5974201a95Ric Aleshire	 * Get the zfsvfs; if there isn't one, then the dataset isn't
5984201a95Ric Aleshire	 * mounted (or isn't a dataset, doesn't exist, ...).
5994201a95Ric Aleshire	 */
6004201a95Ric Aleshire	if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) {
60192241e0Tom Erickson		objset_t *os;
60292241e0Tom Erickson		static char *setsl_tag = "setsl_tag";
60392241e0Tom Erickson
6044201a95Ric Aleshire		/*
6054201a95Ric Aleshire		 * Try to own the dataset; abort if there is any error,
6064201a95Ric Aleshire		 * (e.g., already mounted, in use, or other error).
6074201a95Ric Aleshire		 */
608eb63303Tom Caputi		error = dmu_objset_own(name, DMU_OST_ZFS, B_TRUE, B_TRUE,
60992241e0Tom Erickson		    setsl_tag, &os);
6103b2aab1Matthew Ahrens		if (error != 0)
611be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
6124201a95Ric Aleshire
613eb63303Tom Caputi		dmu_objset_disown(os, B_TRUE, setsl_tag);
61492241e0Tom Erickson
6154201a95Ric Aleshire		if (new_default) {
6164201a95Ric Aleshire			needed_priv = PRIV_FILE_DOWNGRADE_SL;
6174201a95Ric Aleshire			goto out_check;
6184201a95Ric Aleshire		}
6194201a95Ric Aleshire
6204201a95Ric Aleshire		if (hexstr_to_label(strval, &new_sl) != 0)
621be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
6224201a95Ric Aleshire
6234201a95Ric Aleshire		if (blstrictdom(&ds_sl, &new_sl))
6244201a95Ric Aleshire			needed_priv = PRIV_FILE_DOWNGRADE_SL;
6254201a95Ric Aleshire		else if (blstrictdom(&new_sl, &ds_sl))
6264201a95Ric Aleshire			needed_priv = PRIV_FILE_UPGRADE_SL;
6274201a95Ric Aleshire	} else {
6284201a95Ric Aleshire		/* dataset currently has a default label */
6294201a95Ric Aleshire		if (!new_default)
6304201a95Ric Aleshire			needed_priv = PRIV_FILE_UPGRADE_SL;
6314201a95Ric Aleshire	}
6324201a95Ric Aleshire
6334201a95Ric Aleshireout_check:
6344201a95Ric Aleshire	if (needed_priv != -1)
6354201a95Ric Aleshire		return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL));
6364201a95Ric Aleshire	return (0);
6374201a95Ric Aleshire}
6384201a95Ric Aleshire
639ecd6cf8marksstatic int
64092241e0Tom Ericksonzfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
64192241e0Tom Erickson    cred_t *cr)
64392241e0Tom Erickson	char *strval;
64492241e0Tom Erickson
645ecd6cf8marks	/*
646ecd6cf8marks	 * Check permissions for special properties.
647ecd6cf8marks	 */
648ecd6cf8marks	switch (prop) {
649ecd6cf8marks	case ZFS_PROP_ZONED:
650ecd6cf8marks		/*
651ecd6cf8marks		 * Disallow setting of 'zoned' from within a local zone.
652ecd6cf8marks		 */
653ecd6cf8marks		if (!INGLOBALZONE(curproc))
654be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
655ecd6cf8marks		break;
657ecd6cf8marks	case ZFS_PROP_QUOTA:
658a2afb61Jerry Jelinek	case ZFS_PROP_FILESYSTEM_LIMIT:
659a2afb61Jerry Jelinek	case ZFS_PROP_SNAPSHOT_LIMIT:
660ecd6cf8marks		if (!INGLOBALZONE(curproc)) {
661ecd6cf8marks			uint64_t zoned;
6629adfa60Matthew Ahrens			char setpoint[ZFS_MAX_DATASET_NAME_LEN];
663ecd6cf8marks			/*
664ecd6cf8marks			 * Unprivileged users are allowed to modify the
665a2afb61Jerry Jelinek			 * limit on things *under* (ie. contained by)
666ecd6cf8marks			 * the thing they own.
667ecd6cf8marks			 */
66892241e0Tom Erickson			if (dsl_prop_get_integer(dsname, "zoned", &zoned,
669ecd6cf8marks			    setpoint))
670be6fd75Matthew Ahrens				return (SET_ERROR(EPERM));
67192241e0Tom Erickson			if (!zoned || strlen(dsname) <= strlen(setpoint))
672be6fd75Matthew Ahrens				return (SET_ERROR(EPERM));
673ecd6cf8marks		}
674db870a0ahrens		break;
6754201a95Ric Aleshire
6764201a95Ric Aleshire	case ZFS_PROP_MLSLABEL:
6774201a95Ric Aleshire		if (!is_system_labeled())
678be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
67992241e0Tom Erickson
68092241e0Tom Erickson		if (nvpair_value_string(propval, &strval) == 0) {
68192241e0Tom Erickson			int err;
68292241e0Tom Erickson
68392241e0Tom Erickson			err = zfs_set_slabel_policy(dsname, strval, CRED());
68492241e0Tom Erickson			if (err != 0)
68592241e0Tom Erickson				return (err);
68692241e0Tom Erickson		}
6874201a95Ric Aleshire		break;
688ecd6cf8marks	}
69092241e0Tom Erickson	return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr));
6934445fffMatthew Ahrens/* ARGSUSED */
6944445fffMatthew Ahrensstatic int
6954445fffMatthew Ahrenszfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
697ecd6cf8marks	int error;
699ecd6cf8marks	error = zfs_dozonecheck(zc->zc_name, cr);
7003b2aab1Matthew Ahrens	if (error != 0)
701fa9e406ahrens		return (error);
703ecd6cf8marks	/*
704ecd6cf8marks	 * permission to set permissions will be evaluated later in
705ecd6cf8marks	 * dsl_deleg_can_allow()
706ecd6cf8marks	 */
707ecd6cf8marks	return (0);
7104445fffMatthew Ahrens/* ARGSUSED */
7114445fffMatthew Ahrensstatic int
7124445fffMatthew Ahrenszfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
714681d976Eric Taylor	return (zfs_secpolicy_write_perms(zc->zc_name,
715681d976Eric Taylor	    ZFS_DELEG_PERM_ROLLBACK, cr));
7184445fffMatthew Ahrens/* ARGSUSED */
7194445fffMatthew Ahrensstatic int
7204445fffMatthew Ahrenszfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
722a7f53a5Chris Kirby	dsl_pool_t *dp;
723a7f53a5Chris Kirby	dsl_dataset_t *ds;
724a7f53a5Chris Kirby	char *cp;
725a7f53a5Chris Kirby	int error;
726a7f53a5Chris Kirby
727a7f53a5Chris Kirby	/*
728a7f53a5Chris Kirby	 * Generate the current snapshot name from the given objsetid, then
729a7f53a5Chris Kirby	 * use that name for the secpolicy/zone checks.
730a7f53a5Chris Kirby	 */
731a7f53a5Chris Kirby	cp = strchr(zc->zc_name, '@');
732a7f53a5Chris Kirby	if (cp == NULL)
733be6fd75Matthew Ahrens		return (SET_ERROR(EINVAL));
7343b2aab1Matthew Ahrens	error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
7353b2aab1Matthew Ahrens	if (error != 0)
736a7f53a5Chris Kirby		return (error);
737a7f53a5Chris Kirby
738a7f53a5Chris Kirby	error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds);
7393b2aab1Matthew Ahrens	if (error != 0) {
7403b2aab1Matthew Ahrens		dsl_pool_rele(dp, FTAG);
741a7f53a5Chris Kirby		return (error);
7423b2aab1Matthew Ahrens	}
743a7f53a5Chris Kirby
744a7f53a5Chris Kirby	dsl_dataset_name(ds, zc->zc_name);
745a7f53a5Chris Kirby
746a7f53a5Chris Kirby	error = zfs_secpolicy_write_perms_ds(zc->zc_name, ds,
747a7f53a5Chris Kirby	    ZFS_DELEG_PERM_SEND, cr);
748a7f53a5Chris Kirby	dsl_dataset_rele(ds, FTAG);
7493b2aab1Matthew Ahrens	dsl_pool_rele(dp, FTAG);
750a7f53a5Chris Kirby
751a7f53a5Chris Kirby	return (error);
7544445fffMatthew Ahrens/* ARGSUSED */
755743a77eAlan Wrightstatic int
7564445fffMatthew Ahrenszfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
7574445fffMatthew Ahrens{
7584445fffMatthew Ahrens	return (zfs_secpolicy_write_perms(zc->zc_name,
7594445fffMatthew Ahrens	    ZFS_DELEG_PERM_SEND, cr));
7604445fffMatthew Ahrens}
7614445fffMatthew Ahrens
7624445fffMatthew Ahrens/* ARGSUSED */
7634445fffMatthew Ahrensstatic int
7644445fffMatthew Ahrenszfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
765743a77eAlan Wright{
766743a77eAlan Wright	vnode_t *vp;
767743a77eAlan Wright	int error;
768743a77eAlan Wright
769743a77eAlan Wright	if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
770743a77eAlan Wright	    NO_FOLLOW, NULL, &vp)) != 0)
771743a77eAlan Wright		return (error);
772743a77eAlan Wright
773743a77eAlan Wright	/* Now make sure mntpnt and dataset are ZFS */
774743a77eAlan Wright
775743a77eAlan Wright	if (vp->v_vfsp->vfs_fstype != zfsfstype ||
776743a77eAlan Wright	    (strcmp((char *)refstr_value(vp->v_vfsp->vfs_resource),
777743a77eAlan Wright	    zc->zc_name) != 0)) {
778743a77eAlan Wright		VN_RELE(vp);
779be6fd75Matthew Ahrens		return (SET_ERROR(EPERM));
780743a77eAlan Wright	}