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.
240dfe541Evan Layton */
250dfe541Evan Layton
260dfe541Evan Layton/*
270d8fa8fMartin Matuska * Copyright (c) 2011-2012 Pawel Jakub Dawidek. All rights reserved.
281df56adMartin Matuska * Portions Copyright 2011 Martin Matuska
295878fadDan McDonald * Copyright 2015, OmniTI Computer Consulting, Inc. All rights reserved.
300dfe541Evan Layton * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
3128df1aeJason King * Copyright 2019 Joyent, Inc.
322840dceChris Williamson * Copyright (c) 2011, 2017 by Delphix. All rights reserved.
33a6f561bSašo Kiselkov * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
34a7a845eSteven Hartland * Copyright (c) 2013 Steven Hartland. All rights reserved.
35c3d26abMatthew Ahrens * Copyright (c) 2014 Integros [integros.com]
36c8811bdToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com>
376ccda74loli * Copyright (c) 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
38a4b8c9aAndrew Stormont * Copyright 2017 RackTop Systems.
39eb63303Tom Caputi * Copyright (c) 2017, Datto, Inc. All rights reserved.
404445fffMatthew Ahrens */
414445fffMatthew Ahrens
424445fffMatthew Ahrens/*
434445fffMatthew Ahrens * ZFS ioctls.
444445fffMatthew Ahrens *
454445fffMatthew Ahrens * This file handles the ioctls to /dev/zfs, used for configuring ZFS storage
464445fffMatthew Ahrens * pools and filesystems, e.g. with /sbin/zfs and /sbin/zpool.
474445fffMatthew Ahrens *
484445fffMatthew Ahrens * There are two ways that we handle ioctls: the legacy way where almost
494445fffMatthew Ahrens * all of the logic is in the ioctl callback, and the new way where most
504445fffMatthew Ahrens * of the marshalling is handled in the common entry point, zfsdev_ioctl().
514445fffMatthew Ahrens *
524445fffMatthew Ahrens * Non-legacy ioctls should be registered by calling
534445fffMatthew Ahrens * zfs_ioctl_register() from zfs_ioctl_init().  The ioctl is invoked
544445fffMatthew Ahrens * from userland by lzc_ioctl().
554445fffMatthew Ahrens *
564445fffMatthew Ahrens * The registration arguments are as follows:
574445fffMatthew Ahrens *
584445fffMatthew Ahrens * const char *name
594445fffMatthew Ahrens *   The name of the ioctl.  This is used for history logging.  If the
604445fffMatthew Ahrens *   ioctl returns successfully (the callback returns 0), and allow_log
614445fffMatthew Ahrens *   is true, then a history log entry will be recorded with the input &
624445fffMatthew Ahrens *   output nvlists.  The log entry can be printed with "zpool history -i".
634445fffMatthew Ahrens *
644445fffMatthew Ahrens * zfs_ioc_t ioc
654445fffMatthew Ahrens *   The ioctl request number, which userland will pass to ioctl(2).
664445fffMatthew Ahrens *   The ioctl numbers can change from release to release, because
674445fffMatthew Ahrens *   the caller (libzfs) must be matched to the kernel.
684445fffMatthew Ahrens *
694445fffMatthew Ahrens * zfs_secpolicy_func_t *secpolicy
704445fffMatthew Ahrens *   This function will be called before the zfs_ioc_func_t, to
714445fffMatthew Ahrens *   determine if this operation is permitted.  It should return EPERM
724445fffMatthew Ahrens *   on failure, and 0 on success.  Checks include determining if the
734445fffMatthew Ahrens *   dataset is visible in this zone, and if the user has either all
744445fffMatthew Ahrens *   zfs privileges in the zone (SYS_MOUNT), or has been granted permission
754445fffMatthew Ahrens *   to do this operation on this dataset with "zfs allow".
764445fffMatthew Ahrens *
774445fffMatthew Ahrens * zfs_ioc_namecheck_t namecheck
784445fffMatthew Ahrens *   This specifies what to expect in the zfs_cmd_t:zc_name -- a pool
794445fffMatthew Ahrens *   name, a dataset name, or nothing.  If the name is not well-formed,
804445fffMatthew Ahrens *   the ioctl will fail and the callback will not be called.
814445fffMatthew Ahrens *   Therefore, the callback can assume that the name is well-formed
824445fffMatthew Ahrens *   (e.g. is null-terminated, doesn't have more than one '@' character,
834445fffMatthew Ahrens *   doesn't have invalid characters).
844445fffMatthew Ahrens *
854445fffMatthew Ahrens * zfs_ioc_poolcheck_t pool_check
864445fffMatthew Ahrens *   This specifies requirements on the pool state.  If the pool does
874445fffMatthew Ahrens *   not meet them (is suspended or is readonly), the ioctl will fail
884445fffMatthew Ahrens *   and the callback will not be called.  If any checks are specified
894445fffMatthew Ahrens *   (i.e. it is not POOL_CHECK_NONE), namecheck must not be NO_NAME.
904445fffMatthew Ahrens *   Multiple checks can be or-ed together (e.g. POOL_CHECK_SUSPENDED |
914445fffMatthew Ahrens *   POOL_CHECK_READONLY).
924445fffMatthew Ahrens *
934445fffMatthew Ahrens * boolean_t smush_outnvlist
944445fffMatthew Ahrens *   If smush_outnvlist is true, then the output is presumed to be a
954445fffMatthew Ahrens *   list of errors, and it will be "smushed" down to fit into the
964445fffMatthew Ahrens *   caller's buffer, by removing some entries and replacing them with a
974445fffMatthew Ahrens *   single "N_MORE_ERRORS" entry indicating how many were removed.  See
984445fffMatthew Ahrens *   nvlist_smush() for details.  If smush_outnvlist is false, and the
994445fffMatthew Ahrens *   outnvlist does not fit into the userland-provided buffer, then the
1004445fffMatthew Ahrens *   ioctl will fail with ENOMEM.
1014445fffMatthew Ahrens *
1024445fffMatthew Ahrens * zfs_ioc_func_t *func
1034445fffMatthew Ahrens *   The callback function that will perform the operation.
1044445fffMatthew Ahrens *
1054445fffMatthew Ahrens *   The callback should return 0 on success, or an error number on
1064445fffMatthew Ahrens *   failure.  If the function fails, the userland ioctl will return -1,
1074445fffMatthew Ahrens *   and errno will be set to the callback's return value.  The callback
1084445fffMatthew Ahrens *   will be called with the following arguments:
1094445fffMatthew Ahrens *
1104445fffMatthew Ahrens *   const char *name
1114445fffMatthew Ahrens *     The name of the pool or dataset to operate on, from
1124445fffMatthew Ahrens *     zfs_cmd_t:zc_name.  The 'namecheck' argument specifies the
1134445fffMatthew Ahrens *     expected type (pool, dataset, or none).
1144445fffMatthew Ahrens *
1154445fffMatthew Ahrens *   nvlist_t *innvl
1164445fffMatthew Ahrens *     The input nvlist, deserialized from zfs_cmd_t:zc_nvlist_src.  Or
1174445fffMatthew Ahrens *     NULL if no input nvlist was provided.  Changes to this nvlist are
1184445fffMatthew Ahrens *     ignored.  If the input nvlist could not be deserialized, the
1194445fffMatthew Ahrens *     ioctl will fail and the callback will not be called.
1204445fffMatthew Ahrens *
1214445fffMatthew Ahrens *   nvlist_t *outnvl
1224445fffMatthew Ahrens *     The output nvlist, initially empty.  The callback can fill it in,
1234445fffMatthew Ahrens *     and it will be returned to userland by serializing it into
1244445fffMatthew Ahrens *     zfs_cmd_t:zc_nvlist_dst.  If it is non-empty, and serialization
1254445fffMatthew Ahrens *     fails (e.g. because the caller didn't supply a large enough
1264445fffMatthew Ahrens *     buffer), then the overall ioctl will fail.  See the
1274445fffMatthew Ahrens *     'smush_nvlist' argument above for additional behaviors.
1284445fffMatthew Ahrens *
1294445fffMatthew Ahrens *     There are two typical uses of the output nvlist:
1304445fffMatthew Ahrens *       - To return state, e.g. property values.  In this case,
1314445fffMatthew Ahrens *         smush_outnvlist should be false.  If the buffer was not large
1324445fffMatthew Ahrens *         enough, the caller will reallocate a larger buffer and try
1334445fffMatthew Ahrens *         the ioctl again.
1344445fffMatthew Ahrens *
1354445fffMatthew Ahrens *       - To return multiple errors from an ioctl which makes on-disk
1364445fffMatthew Ahrens *         changes.  In this case, smush_outnvlist should be true.
1374445fffMatthew Ahrens *         Ioctls which make on-disk modifications should generally not
1384445fffMatthew Ahrens *         use the outnvl if they succeed, because the caller can not
1394445fffMatthew Ahrens *         distinguish between the operation failing, and
1404445fffMatthew Ahrens *         deserialization failing.
141e9103aaGarrett D'Amore */
143fa9e406ahrens#include <sys/types.h>
144fa9e406ahrens#include <sys/param.h>
145fa9e406ahrens#include <sys/errno.h>
146fa9e406ahrens#include <sys/uio.h>
147fa9e406ahrens#include <sys/buf.h>
148fa9e406ahrens#include <sys/modctl.h>
149fa9e406ahrens#include <sys/open.h>
150fa9e406ahrens#include <sys/file.h>
151fa9e406ahrens#include <sys/kmem.h>
152fa9e406ahrens#include <sys/conf.h>
153fa9e406ahrens#include <sys/cmn_err.h>
154fa9e406ahrens#include <sys/stat.h>
155fa9e406ahrens#include <sys/zfs_ioctl.h>
1564201a95Ric Aleshire#include <sys/zfs_vfsops.h>
157da6c28aamw#include <sys/zfs_znode.h>
158fa9e406ahrens#include <sys/zap.h>
159fa9e406ahrens#include <sys/spa.h>
160b1b8ab3lling#include <sys/spa_impl.h>
161fa9e406ahrens#include <sys/vdev.h>
1624201a95Ric Aleshire#include <sys/priv_impl.h>
163fa9e406ahrens#include <sys/dmu.h>
164fa9e406ahrens#include <sys/dsl_dir.h>
165fa9e406ahrens#include <sys/dsl_dataset.h>
166fa9e406ahrens#include <sys/dsl_prop.h>
167ecd6cf8marks#include <sys/dsl_deleg.h>
168ecd6cf8marks#include <sys/dmu_objset.h>
1694e3c9f4Bill Pijewski#include <sys/dmu_impl.h>
1703b2aab1Matthew Ahrens#include <sys/dmu_tx.h>
171fa9e406ahrens#include <sys/ddi.h>
172fa9e406ahrens#include <sys/sunddi.h>
173fa9e406ahrens#include <sys/sunldi.h>
174fa9e406ahrens#include <sys/policy.h>
175fa9e406ahrens#include <sys/zone.h>
176fa9e406ahrens#include <sys/nvpair.h>
177fa9e406ahrens#include <sys/pathname.h>
178fa9e406ahrens#include <sys/mount.h>
179fa9e406ahrens#include <sys/sdt.h>
180fa9e406ahrens#include <sys/fs/zfs.h>
181fa9e406ahrens#include <sys/zfs_ctldir.h>
182da6c28aamw#include <sys/zfs_dir.h>
183c99e4bdChris Kirby#include <sys/zfs_onexit.h>
184a2eea2eahrens#include <sys/zvol.h>
1853f9d6adLin Ling#include <sys/dsl_scan.h>
186ecd6cf8marks#include <sharefs/share.h>
187f18faf3ek#include <sys/dmu_objset.h>
1880fa1b3cPaul Dagnelie#include <sys/dmu_recv.h>
1893b2aab1Matthew Ahrens#include <sys/dmu_send.h>
1903b2aab1Matthew Ahrens#include <sys/dsl_destroy.h>
19178f1710Matthew Ahrens#include <sys/dsl_bookmark.h>
1923b2aab1Matthew Ahrens#include <sys/dsl_userhold.h>
193a6f561bSašo Kiselkov#include <sys/zfeature.h>
194dfc1153Chris Williamson#include <sys/zcp.h>
19545818eeMatthew Ahrens#include <sys/zio_checksum.h>
1965cabbc6Prashanth Sreenivasa#include <sys/vdev_removal.h>
197094e47eGeorge Wilson#include <sys/vdev_impl.h>
198094e47eGeorge Wilson#include <sys/vdev_initialize.h>
199084fd14Brian Behlendorf#include <sys/vdev_trim.h>
200eb63303Tom Caputi#include <sys/dsl_crypt.h>
202fa9e406ahrens#include "zfs_namecheck.h"
203e9dbad6eschrock#include "zfs_prop.h"
204ecd6cf8marks#include "zfs_deleg.h"
2050a586ceMark Shellenbaum#include "zfs_comutil.h"
207dfc1153Chris Williamson#include "lua.h"
208dfc1153Chris Williamson#include "lauxlib.h"
209dfc1153Chris Williamson
210fa9e406ahrensextern struct modlfs zfs_modlfs;
212fa9e406ahrensextern void zfs_init(void);
213fa9e406ahrensextern void zfs_fini(void);
215fa9e406ahrensldi_ident_t zfs_li = NULL;
216fa9e406ahrensdev_info_t *zfs_dip;
2184445fffMatthew Ahrensuint_t zfs_fsyncer_key;
2194445fffMatthew Ahrensextern uint_t rrw_tsd_key;
2204445fffMatthew Ahrensstatic uint_t zfs_allow_log_key;
2214445fffMatthew Ahrens
2224445fffMatthew Ahrenstypedef int zfs_ioc_legacy_func_t(zfs_cmd_t *);
2234445fffMatthew Ahrenstypedef int zfs_ioc_func_t(const char *, nvlist_t *, nvlist_t *);
2244445fffMatthew Ahrenstypedef int zfs_secpolicy_func_t(zfs_cmd_t *, nvlist_t *, cred_t *);
22654d692bGeorge Wilsontypedef enum {
22754d692bGeorge Wilson	NO_NAME,
22854d692bGeorge Wilson	POOL_NAME,
22954d692bGeorge Wilson	DATASET_NAME
23054d692bGeorge Wilson} zfs_ioc_namecheck_t;
23154d692bGeorge Wilson
232f9af39bGeorge Wilsontypedef enum {
233f9af39bGeorge Wilson	POOL_CHECK_NONE		= 1 << 0,
234f9af39bGeorge Wilson	POOL_CHECK_SUSPENDED	= 1 << 1,
2354445fffMatthew Ahrens	POOL_CHECK_READONLY	= 1 << 2,
236f9af39bGeorge Wilson} zfs_ioc_poolcheck_t;
237f9af39bGeorge Wilson
238fa9e406ahrenstypedef struct zfs_ioc_vec {
2394445fffMatthew Ahrens	zfs_ioc_legacy_func_t	*zvec_legacy_func;
240fa9e406ahrens	zfs_ioc_func_t		*zvec_func;
241fa9e406ahrens	zfs_secpolicy_func_t	*zvec_secpolicy;
24254d692bGeorge Wilson	zfs_ioc_namecheck_t	zvec_namecheck;
2434445fffMatthew Ahrens	boolean_t		zvec_allow_log;
244f9af39bGeorge Wilson	zfs_ioc_poolcheck_t	zvec_pool_check;
2454445fffMatthew Ahrens	boolean_t		zvec_smush_outnvlist;
2464445fffMatthew Ahrens	const char		*zvec_name;
247fa9e406ahrens} zfs_ioc_vec_t;
2491484342Matthew Ahrens/* This array is indexed by zfs_userquota_prop_t */
2501484342Matthew Ahrensstatic const char *userquota_perms[] = {
2511484342Matthew Ahrens	ZFS_DELEG_PERM_USERUSED,
2521484342Matthew Ahrens	ZFS_DELEG_PERM_USERQUOTA,
2531484342Matthew Ahrens	ZFS_DELEG_PERM_GROUPUSED,
2541484342Matthew Ahrens	ZFS_DELEG_PERM_GROUPQUOTA,
2631484342Matthew Ahrens};
2641484342Matthew Ahrens
2651484342Matthew Ahrensstatic int zfs_ioc_userspace_upgrade(zfs_cmd_t *zc);
266f67950bNasf-Fanstatic int zfs_ioc_id_quota_upgrade(zfs_cmd_t *zc);
26792241e0Tom Ericksonstatic int zfs_check_settable(const char *name, nvpair_t *property,
26892241e0Tom Erickson    cred_t *cr);
26992241e0Tom Ericksonstatic int zfs_check_clearable(char *dataset, nvlist_t *props,
27092241e0Tom Erickson    nvlist_t **errors);
2710a48a24timhstatic int zfs_fill_zplprops_root(uint64_t, nvlist_t *, nvlist_t *,
2720a48a24timh    boolean_t *);
2734445fffMatthew Ahrensint zfs_set_prop_nvlist(const char *, zprop_source_t, nvlist_t *, nvlist_t *);
2744445fffMatthew Ahrensstatic int get_nvlist(uint64_t nvl, uint64_t size, int iflag, nvlist_t **nvp);
2762acef22Matthew Ahrensstatic int zfs_prop_activate_feature(spa_t *spa, spa_feature_t feature);
277a6f561bSašo Kiselkov
278fa9e406ahrens/* _NOTE(PRINTFLIKE(4)) - this is printf-like, but lint is too whiney */
280fa9e406ahrens__dprintf(const char *file, const char *func, int line, const char *fmt, ...)
282fa9e406ahrens	const char *newfile;
2833f9d6adLin Ling	char buf[512];
284fa9e406ahrens	va_list adx;
286fa9e406ahrens	/*
287fa9e406ahrens	 * Get rid of annoying "../common/" prefix to filename.
288fa9e406ahrens	 */
289fa9e406ahrens	newfile = strrchr(file, '/');
290fa9e406ahrens	if (newfile != NULL) {
291fa9e406ahrens		newfile = newfile + 1; /* Get rid of leading / */
292fa9e406ahrens	} else {
293fa9e406ahrens		newfile = file;
294fa9e406ahrens	}
296fa9e406ahrens	va_start(adx, fmt);
297fa9e406ahrens	(void) vsnprintf(buf, sizeof (buf), fmt, adx);
298fa9e406ahrens	va_end(adx);
300fa9e406ahrens	/*
301fa9e406ahrens	 * To get this data, use the zfs-dprintf probe as so:
302fa9e406ahrens	 * dtrace -q -n 'zfs-dprintf \
303fa9e406ahrens	 *	/stringof(arg0) == "dbuf.c"/ \
304fa9e406ahrens	 *	{printf("%s: %s", stringof(arg1), stringof(arg3))}'
305fa9e406ahrens	 * arg0 = file name
306fa9e406ahrens	 * arg1 = function name
307fa9e406ahrens	 * arg2 = line number
308fa9e406ahrens	 * arg3 = message
309fa9e406ahrens	 */
310fa9e406ahrens	DTRACE_PROBE4(zfs__dprintf,
311fa9e406ahrens	    char *, newfile, char *, func, int, line, char *, buf);
314ecd6cf8marksstatic void
315228975cekhistory_str_free(char *buf)
317228975cek	kmem_free(buf, HIS_MAX_RECORD_LEN);
320228975cekstatic char *
321228975cekhistory_str_get(zfs_cmd_t *zc)
32340feaa9ahrens	char *buf;
325dd328bfToomas Soome	if (zc->zc_history == 0)
326228975cek		return (NULL);
328ecd6cf8marks	buf = kmem_alloc(HIS_MAX_RECORD_LEN, KM_SLEEP);
329ecd6cf8marks	if (copyinstr((void *)(uintptr_t)zc->zc_history,
330ecd6cf8marks	    buf, HIS_MAX_RECORD_LEN, NULL) != 0) {
331228975cek		history_str_free(buf);
332228975cek		return (NULL);
333ecd6cf8marks	}
335ecd6cf8marks	buf[HIS_MAX_RECORD_LEN -1] = '\0';
337228975cek	return (buf);
34115e6edfgw * Check to see if the named dataset is currently defined as bootable
34215e6edfgw */
34315e6edfgwstatic boolean_t
34415e6edfgwzfs_is_bootfs(const char *name)
346503ad85Matthew Ahrens	objset_t *os;
348503ad85Matthew Ahrens	if (dmu_objset_hold(name, FTAG, &os) == 0) {
349503ad85Matthew Ahrens		boolean_t ret;
350b24ab67Jeff Bonwick		ret = (dmu_objset_id(os) == spa_bootfs(dmu_objset_spa(os)));
351503ad85Matthew Ahrens		dmu_objset_rele(os, FTAG);
352503ad85Matthew Ahrens		return (ret);
35315e6edfgw	}
354503ad85Matthew Ahrens	return (B_FALSE);
358f717074Will Andrews * Return non-zero if the spa version is less than requested version.
359c2a93d4timh */
360da6c28aamwstatic int
3610a48a24timhzfs_earlier_version(const char *name, int version)
363da6c28aamw	spa_t *spa;
365da6c28aamw	if (spa_open(name, &spa, FTAG) == 0) {
366da6c28aamw		if (spa_version(spa) < version) {
367da6c28aamw			spa_close(spa, FTAG);
368da6c28aamw			return (1);
369da6c28aamw		}
370da6c28aamw		spa_close(spa, FTAG);
371da6c28aamw	}
372da6c28aamw	return (0);
376745cd3cmaybee * Return TRUE if the ZPL version is less than requested version.
3779e6eda5marks */
378745cd3cmaybeestatic boolean_t
379745cd3cmaybeezpl_earlier_version(const char *name, int version)
3819e6eda5marks	objset_t *os;
382745cd3cmaybee	boolean_t rc = B_TRUE;
384503ad85Matthew Ahrens	if (dmu_objset_hold(name, FTAG, &os) == 0) {
385745cd3cmaybee		uint64_t zplversion;
387503ad85Matthew Ahrens		if (dmu_objset_type(os) != DMU_OST_ZFS) {
388503ad85Matthew Ahrens			dmu_objset_rele(os, FTAG);
389503ad85Matthew Ahrens			return (B_TRUE);
390503ad85Matthew Ahrens		}
391503ad85Matthew Ahrens		/* XXX reading from non-owned objset */
392745cd3cmaybee		if (zfs_get_zplprop(os, ZFS_PROP_VERSION, &zplversion) == 0)
393745cd3cmaybee			rc = zplversion < version;
394503ad85Matthew Ahrens		dmu_objset_rele(os, FTAG);
3959e6eda5marks	}
3969e6eda5marks	return (rc);
399228975cekstatic void
400228975cekzfs_log_history(zfs_cmd_t *zc)
402228975cek	spa_t *spa;
403228975cek	char *buf;
405228975cek	if ((buf = history_str_get(zc)) == NULL)
406228975cek		return;
408228975cek	if (spa_open(zc->zc_name, &spa, FTAG) == 0) {
409228975cek		if (spa_version(spa) >= SPA_VERSION_ZPOOL_HISTORY)
4104445fffMatthew Ahrens			(void) spa_history_log(spa, buf);
411228975cek		spa_close(spa, FTAG);
412228975cek	}
413228975cek	history_str_free(buf);
417fa9e406ahrens * Policy for top-level read operations (list pools).  Requires no privileges,
418fa9e406ahrens * and can be used in the local zone, as there is no associated dataset.
419fa9e406ahrens */
420fa9e406ahrens/* ARGSUSED */
421fa9e406ahrensstatic int
4224445fffMatthew Ahrenszfs_secpolicy_none(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
424fa9e406ahrens	return (0);
428fa9e406ahrens * Policy for dataset read operations (list children, get statistics).  Requires
429fa9e406ahrens * no privileges, but must be visible in the local zone.
430fa9e406ahrens */
431fa9e406ahrens/* ARGSUSED */
432fa9e406ahrensstatic int
4334445fffMatthew Ahrenszfs_secpolicy_read(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
435fa9e406ahrens	if (INGLOBALZONE(curproc) ||
436ecd6cf8marks	    zone_dataset_visible(zc->zc_name, NULL))
437fa9e406ahrens		return (0);
439be6fd75Matthew Ahrens	return (SET_ERROR(ENOENT));
442fa9e406ahrensstatic int
443a7f53a5Chris Kirbyzfs_dozonecheck_impl(const char *dataset, uint64_t zoned, cred_t *cr)
445fa9e406ahrens	int writable = 1;
447fa9e406ahrens	/*
448fa9e406ahrens	 * The dataset must be visible by this zone -- check this first
449fa9e406ahrens	 * so they don't see EPERM on something they shouldn't know about.
450fa9e406ahrens	 */
451fa9e406ahrens	if (!INGLOBALZONE(curproc) &&
452fa9e406ahrens	    !zone_dataset_visible(dataset, &writable))
453be6fd75Matthew Ahrens		return (SET_ERROR(ENOENT));
455fa9e406ahrens	if (INGLOBALZONE(curproc)) {
456fa9e406ahrens		/*
457fa9e406ahrens		 * If the fs is zoned, only root can access it from the
458fa9e406ahrens		 * global zone.
459fa9e406ahrens		 */
460fa9e406ahrens		if (secpolicy_zfs(cr) && zoned)
461be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
462fa9e406ahrens	} else {
463fa9e406ahrens		/*
464fa9e406ahrens		 * If we are in a local zone, the 'zoned' property must be set.
465fa9e406ahrens		 */
466fa9e406ahrens		if (!zoned)
467be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
469fa9e406ahrens		/* must be writable by this zone */
470fa9e406ahrens		if (!writable)
471be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
472fa9e406ahrens	}
473fa9e406ahrens	return (0);
476a7f53a5Chris Kirbystatic int
477a7f53a5Chris Kirbyzfs_dozonecheck(const char *dataset, cred_t *cr)
478a7f53a5Chris Kirby{
479a7f53a5Chris Kirby	uint64_t zoned;
480a7f53a5Chris Kirby
481a7f53a5Chris Kirby	if (dsl_prop_get_integer(dataset, "zoned", &zoned, NULL))
482be6fd75Matthew Ahrens		return (SET_ERROR(ENOENT));
483a7f53a5Chris Kirby
484a7f53a5Chris Kirby	return (zfs_dozonecheck_impl(dataset, zoned, cr));
485a7f53a5Chris Kirby}
486a7f53a5Chris Kirby
487a7f53a5Chris Kirbystatic int
488a7f53a5Chris Kirbyzfs_dozonecheck_ds(const char *dataset, dsl_dataset_t *ds, cred_t *cr)
489a7f53a5Chris Kirby{
490a7f53a5Chris Kirby	uint64_t zoned;
491a7f53a5Chris Kirby
4923b2aab1Matthew Ahrens	if (dsl_prop_get_int_ds(ds, "zoned", &zoned))
493be6fd75Matthew Ahrens		return (SET_ERROR(ENOENT));
494a7f53a5Chris Kirby
495a7f53a5Chris Kirby	return (zfs_dozonecheck_impl(dataset, zoned, cr));
496a7f53a5Chris Kirby}
497a7f53a5Chris Kirby
4984445fffMatthew Ahrensstatic int
4993b2aab1Matthew Ahrenszfs_secpolicy_write_perms_ds(const char *name, dsl_dataset_t *ds,
5003b2aab1Matthew Ahrens    const char *perm, cred_t *cr)
502fa9e406ahrens	int error;
50419b94dfMatthew Ahrens	error = zfs_dozonecheck_ds(name, ds, cr);
505ecd6cf8marks	if (error == 0) {
506ecd6cf8marks		error = secpolicy_zfs(cr);
5073b2aab1Matthew Ahrens		if (error != 0)
5084445fffMatthew Ahrens			error = dsl_deleg_access_impl(ds, perm, cr);
509ecd6cf8marks	}
510ecd6cf8marks	return (error);
5134445fffMatthew Ahrensstatic int
5143b2aab1Matthew Ahrenszfs_secpolicy_write_perms(const char *name, const char *perm, cred_t *cr)
515a7f53a5Chris Kirby{
516a7f53a5Chris Kirby	int error;
5173b2aab1Matthew Ahrens	dsl_dataset_t *ds;
5183b2aab1Matthew Ahrens	dsl_pool_t *dp;
519a7f53a5Chris Kirby
52025f7d99Matthew Ahrens	/*
52125f7d99Matthew Ahrens	 * First do a quick check for root in the global zone, which
52225f7d99Matthew Ahrens	 * is allowed to do all write_perms.  This ensures that zfs_ioc_*
52325f7d99Matthew Ahrens	 * will get to handle nonexistent datasets.
52425f7d99Matthew Ahrens	 */
52525f7d99Matthew Ahrens	if (INGLOBALZONE(curproc) && secpolicy_zfs(cr) == 0)
52625f7d99Matthew Ahrens		return (0);
52725f7d99Matthew Ahrens
5283b2aab1Matthew Ahrens	error = dsl_pool_hold(name, FTAG, &dp);
5293b2aab1Matthew Ahrens	if (error != 0)
5303b2aab1Matthew Ahrens		return (error);
5313b2aab1Matthew Ahrens
5323b2aab1Matthew Ahrens	error = dsl_dataset_hold(dp, name, FTAG, &ds);
5333b2aab1Matthew Ahrens	if (error != 0) {
5343b2aab1Matthew Ahrens		dsl_pool_rele(dp, FTAG);
5353b2aab1Matthew Ahrens		return (error);
536a7f53a5Chris Kirby	}
5373b2aab1Matthew Ahrens
5383b2aab1Matthew Ahrens	error = zfs_secpolicy_write_perms_ds(name, ds, perm, cr);
5393b2aab1Matthew Ahrens
5403b2aab1Matthew Ahrens	dsl_dataset_rele(ds, FTAG);
5413b2aab1Matthew Ahrens	dsl_pool_rele(dp, FTAG);
542a7f53a5Chris Kirby	return (error);
543a7f53a5Chris Kirby}
544a7f53a5Chris Kirby
5454201a95Ric Aleshire/*
5464201a95Ric Aleshire * Policy for setting the security label property.
5474201a95Ric Aleshire *
5484201a95Ric Aleshire * Returns 0 for success, non-zero for access and other errors.
5494201a95Ric Aleshire */
5504201a95Ric Aleshirestatic int
55192241e0Tom Ericksonzfs_set_slabel_policy(const char *name, char *strval, cred_t *cr)
5524201a95Ric Aleshire{
5534201a95Ric Aleshire	char		ds_hexsl[MAXNAMELEN];
5544201a95Ric Aleshire	bslabel_t	ds_sl, new_sl;
5554201a95Ric Aleshire	boolean_t	new_default = FALSE;
5564201a95Ric Aleshire	uint64_t	zoned;
5574201a95Ric Aleshire	int		needed_priv = -1;
5584201a95Ric Aleshire	int		error;
5594201a95Ric Aleshire
5604201a95Ric Aleshire	/* First get the existing dataset label. */
5614201a95Ric Aleshire	error = dsl_prop_get(name, zfs_prop_to_name(ZFS_PROP_MLSLABEL),
5624201a95Ric Aleshire	    1, sizeof (ds_hexsl), &ds_hexsl, NULL);
5633b2aab1Matthew Ahrens	if (error != 0)
564be6fd75Matthew Ahrens		return (SET_ERROR(EPERM));
5654201a95Ric Aleshire
5664201a95Ric Aleshire	if (strcasecmp(strval, ZFS_MLSLABEL_DEFAULT) == 0)
5674201a95Ric Aleshire		new_default = TRUE;
5684201a95Ric Aleshire
5694201a95Ric Aleshire	/* The label must be translatable */
5704201a95Ric Aleshire	if (!new_default && (hexstr_to_label(strval, &new_sl) != 0))
571be6fd75Matthew Ahrens		return (SET_ERROR(EINVAL));
5724201a95Ric Aleshire
5734201a95Ric Aleshire	/*
5744201a95Ric Aleshire	 * In a non-global zone, disallow attempts to set a label that
5754201a95Ric Aleshire	 * doesn't match that of the zone; otherwise no other checks
5764201a95Ric Aleshire	 * are needed.
5774201a95Ric Aleshire	 */
5784201a95Ric Aleshire	if (!INGLOBALZONE(curproc)) {
5794201a95Ric Aleshire		if (new_default || !blequal(&new_sl, CR_SL(CRED())))
580be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
5814201a95Ric Aleshire		return (0);
5824201a95Ric Aleshire	}
5834201a95Ric Aleshire
5844201a95Ric Aleshire	/*
5854201a95Ric Aleshire	 * For global-zone datasets (i.e., those whose zoned property is
5864201a95Ric Aleshire	 * "off", verify that the specified new label is valid for the
5874201a95Ric Aleshire	 * global zone.
5884201a95Ric Aleshire	 */
5894201a95Ric Aleshire	if (dsl_prop_get_integer(name,
5904201a95Ric Aleshire	    zfs_prop_to_name(ZFS_PROP_ZONED), &zoned, NULL))
591be6fd75Matthew Ahrens		return (SET_ERROR(EPERM));
5924201a95Ric Aleshire	if (!zoned) {
5934201a95Ric Aleshire		if (zfs_check_global_label(name, strval) != 0)
594be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
5954201a95Ric Aleshire	}
5964201a95Ric Aleshire
5974201a95Ric Aleshire	/*
5984201a95Ric Aleshire	 * If the existing dataset label is nondefault, check if the
5994201a95Ric Aleshire	 * dataset is mounted (label cannot be changed while mounted).
6004201a95Ric Aleshire	 * Get the zfsvfs; if there isn't one, then the dataset isn't
6014201a95Ric Aleshire	 * mounted (or isn't a dataset, doesn't exist, ...).
6024201a95Ric Aleshire	 */
6034201a95Ric Aleshire	if (strcasecmp(ds_hexsl, ZFS_MLSLABEL_DEFAULT) != 0) {
60492241e0Tom Erickson		objset_t *os;
60592241e0Tom Erickson		static char *setsl_tag = "setsl_tag";
60692241e0Tom Erickson
6074201a95Ric Aleshire		/*
6084201a95Ric Aleshire		 * Try to own the dataset; abort if there is any error,
6094201a95Ric Aleshire		 * (e.g., already mounted, in use, or other error).
6104201a95Ric Aleshire		 */
611eb63303Tom Caputi		error = dmu_objset_own(name, DMU_OST_ZFS, B_TRUE, B_TRUE,
61292241e0Tom Erickson		    setsl_tag, &os);
6133b2aab1Matthew Ahrens		if (error != 0)
614be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
6154201a95Ric Aleshire
616eb63303Tom Caputi		dmu_objset_disown(os, B_TRUE, setsl_tag);
61792241e0Tom Erickson
6184201a95Ric Aleshire		if (new_default) {
6194201a95Ric Aleshire			needed_priv = PRIV_FILE_DOWNGRADE_SL;
6204201a95Ric Aleshire			goto out_check;
6214201a95Ric Aleshire		}
6224201a95Ric Aleshire
6234201a95Ric Aleshire		if (hexstr_to_label(strval, &new_sl) != 0)
624be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
6254201a95Ric Aleshire
6264201a95Ric Aleshire		if (blstrictdom(&ds_sl, &new_sl))
6274201a95Ric Aleshire			needed_priv = PRIV_FILE_DOWNGRADE_SL;
6284201a95Ric Aleshire		else if (blstrictdom(&new_sl, &ds_sl))
6294201a95Ric Aleshire			needed_priv = PRIV_FILE_UPGRADE_SL;
6304201a95Ric Aleshire	} else {
6314201a95Ric Aleshire		/* dataset currently has a default label */
6324201a95Ric Aleshire		if (!new_default)
6334201a95Ric Aleshire			needed_priv = PRIV_FILE_UPGRADE_SL;
6344201a95Ric Aleshire	}
6354201a95Ric Aleshire
6364201a95Ric Aleshireout_check:
6374201a95Ric Aleshire	if (needed_priv != -1)
6384201a95Ric Aleshire		return (PRIV_POLICY(cr, needed_priv, B_FALSE, EPERM, NULL));
6394201a95Ric Aleshire	return (0);
6404201a95Ric Aleshire}
6414201a95Ric Aleshire
642ecd6cf8marksstatic int
64392241e0Tom Ericksonzfs_secpolicy_setprop(const char *dsname, zfs_prop_t prop, nvpair_t *propval,
64492241e0Tom Erickson    cred_t *cr)
64692241e0Tom Erickson	char *strval;
64792241e0Tom Erickson
648ecd6cf8marks	/*
649ecd6cf8marks	 * Check permissions for special properties.
650ecd6cf8marks	 */
651ecd6cf8marks	switch (prop) {
652ecd6cf8marks	case ZFS_PROP_ZONED:
653ecd6cf8marks		/*
654ecd6cf8marks		 * Disallow setting of 'zoned' from within a local zone.
655ecd6cf8marks		 */
656ecd6cf8marks		if (!INGLOBALZONE(curproc))
657be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
658ecd6cf8marks		break;
660ecd6cf8marks	case ZFS_PROP_QUOTA:
661a2afb61Jerry Jelinek	case ZFS_PROP_FILESYSTEM_LIMIT:
662a2afb61Jerry Jelinek	case ZFS_PROP_SNAPSHOT_LIMIT:
663ecd6cf8marks		if (!INGLOBALZONE(curproc)) {
664ecd6cf8marks			uint64_t zoned;
6659adfa60Matthew Ahrens			char setpoint[ZFS_MAX_DATASET_NAME_LEN];
666ecd6cf8marks			/*
667ecd6cf8marks			 * Unprivileged users are allowed to modify the
668a2afb61Jerry Jelinek			 * limit on things *under* (ie. contained by)
669ecd6cf8marks			 * the thing they own.
670ecd6cf8marks			 */
67192241e0Tom Erickson			if (dsl_prop_get_integer(dsname, "zoned", &zoned,
672ecd6cf8marks			    setpoint))
673be6fd75Matthew Ahrens				return (SET_ERROR(EPERM));
67492241e0Tom Erickson			if (!zoned || strlen(dsname) <= strlen(setpoint))
675be6fd75Matthew Ahrens				return (SET_ERROR(EPERM));
676ecd6cf8marks		}
677db870a0ahrens		break;
6784201a95Ric Aleshire
6794201a95Ric Aleshire	case ZFS_PROP_MLSLABEL:
6804201a95Ric Aleshire		if (!is_system_labeled())
681be6fd75Matthew Ahrens			return (SET_ERROR(EPERM));
68292241e0Tom Erickson
68392241e0Tom Erickson		if (nvpair_value_string(propval, &strval) == 0) {
68492241e0Tom Erickson			int err;
68592241e0Tom Erickson
68692241e0Tom Erickson			err = zfs_set_slabel_policy(dsname, strval, CRED());
68792241e0Tom Erickson			if (err != 0)
68892241e0Tom Erickson				return (err);
68992241e0Tom Erickson		}
6904201a95Ric Aleshire		break;
691ecd6cf8marks	}
69392241e0Tom Erickson	return (zfs_secpolicy_write_perms(dsname, zfs_prop_to_name(prop), cr));
6964445fffMatthew Ahrens/* ARGSUSED */
6974445fffMatthew Ahrensstatic int
6984445fffMatthew Ahrenszfs_secpolicy_set_fsacl(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
700ecd6cf8marks	int error;
702ecd6cf8marks	error = zfs_dozonecheck(zc->zc_name, cr);
7033b2aab1Matthew Ahrens	if (error != 0)
704fa9e406ahrens		return (error);
706ecd6cf8marks	/*
707ecd6cf8marks	 * permission to set permissions will be evaluated later in
708ecd6cf8marks	 * dsl_deleg_can_allow()
709ecd6cf8marks	 */
710ecd6cf8marks	return (0);
7134445fffMatthew Ahrens/* ARGSUSED */
7144445fffMatthew Ahrensstatic int
7154445fffMatthew Ahrenszfs_secpolicy_rollback(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
717681d976Eric Taylor	return (zfs_secpolicy_write_perms(zc->zc_name,
718681d976Eric Taylor	    ZFS_DELEG_PERM_ROLLBACK, cr));
7214445fffMatthew Ahrens/* ARGSUSED */
7224445fffMatthew Ahrensstatic int
7234445fffMatthew Ahrenszfs_secpolicy_send(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
725a7f53a5Chris Kirby	dsl_pool_t *dp;
726a7f53a5Chris Kirby	dsl_dataset_t *ds;
727a7f53a5Chris Kirby	char *cp;
728a7f53a5Chris Kirby	int error;
729a7f53a5Chris Kirby
730a7f53a5Chris Kirby	/*
731a7f53a5Chris Kirby	 * Generate the current snapshot name from the given objsetid, then
732a7f53a5Chris Kirby	 * use that name for the secpolicy/zone checks.
733a7f53a5Chris Kirby	 */
734a7f53a5Chris Kirby	cp = strchr(zc->zc_name, '@');
735a7f53a5Chris Kirby	if (cp == NULL)
736be6fd75Matthew Ahrens		return (SET_ERROR(EINVAL));
7373b2aab1Matthew Ahrens	error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
7383b2aab1Matthew Ahrens	if (error != 0)
739a7f53a5Chris Kirby		return (error);
740a7f53a5Chris Kirby
741a7f53a5Chris Kirby	error = dsl_dataset_hold_obj(dp, zc->zc_sendobj, FTAG, &ds);
7423b2aab1Matthew Ahrens	if (error != 0) {
7433b2aab1Matthew Ahrens		dsl_pool_rele(dp, FTAG);
744a7f53a5Chris Kirby		return (error);
7453b2aab1Matthew Ahrens	}
746a7f53a5Chris Kirby
747a7f53a5Chris Kirby	dsl_dataset_name(ds, zc->zc_name);
748a7f53a5Chris Kirby
749a7f53a5Chris Kirby	error = zfs_secpolicy_write_perms_ds(zc->zc_name, ds,
750a7f53a5Chris Kirby	    ZFS_DELEG_PERM_SEND, cr);
751a7f53a5Chris Kirby	dsl_dataset_rele(ds, FTAG);
7523b2aab1Matthew Ahrens	dsl_pool_rele(dp, FTAG);
753a7f53a5Chris Kirby
754a7f53a5Chris Kirby	return (error);
7574445fffMatthew Ahrens/* ARGSUSED */
758743a77eAlan Wrightstatic int
7594445fffMatthew Ahrenszfs_secpolicy_send_new(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
7604445fffMatthew Ahrens{
7614445fffMatthew Ahrens	return (zfs_secpolicy_write_perms(zc->zc_name,
7624445fffMatthew Ahrens	    ZFS_DELEG_PERM_SEND, cr));
7634445fffMatthew Ahrens}
7644445fffMatthew Ahrens
7654445fffMatthew Ahrens/* ARGSUSED */
7664445fffMatthew Ahrensstatic int
7674445fffMatthew Ahrenszfs_secpolicy_deleg_share(zfs_cmd_t *zc, nvlist_t *innvl, cred_t *cr)
768743a77eAlan Wright{
769743a77eAlan Wright	vnode_t *vp;
770743a77eAlan Wright	int error;
771743a77eAlan Wright
772743a77eAlan Wright	if ((error = lookupname(zc->zc_value, UIO_SYSSPACE,
773743a77eAlan Wright	    NO_FOLLOW, NULL, &vp)) != 0)
774743a77eAlan Wright		return (error);
775743a77eAlan Wright
776743a77eAlan Wright	/* Now make sure mntpnt and dataset are ZFS */
777743a77eAlan Wright
778743a77eAlan Wright	if (vp->v_vfsp->vfs_fstype != zfsfstype ||