Add FreeBSD jail support hooks

Add the 'zfs jail/unjail' subcommands along with the relevant 
documentation from FreeBSD.  This feature is not supported on
Linux and still requires the match kernel ioctls which will
be included when the FreeBSD platform code is integrated.

Reviewed-by: Jorgen Lundman <lundman@lundman.net>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Matt Macy <mmacy@FreeBSD.org>
Signed-off-by: Ryan Moeller <ryan@ixsystems.com>
Closes #9686
This commit is contained in:
Matthew Macy 2019-12-11 11:58:37 -08:00 committed by Brian Behlendorf
parent 657ce25357
commit 4bc721965f
11 changed files with 254 additions and 9 deletions

View File

@ -15,3 +15,7 @@ zfs_LDADD = \
$(top_builddir)/lib/libuutil/libuutil.la \ $(top_builddir)/lib/libuutil/libuutil.la \
$(top_builddir)/lib/libzfs/libzfs.la \ $(top_builddir)/lib/libzfs/libzfs.la \
$(top_builddir)/lib/libzfs_core/libzfs_core.la $(top_builddir)/lib/libzfs_core/libzfs_core.la
if BUILD_FREEBSD
zfs_LDADD += -L/usr/local/lib -lintl -lgeom -ljail
endif

View File

@ -122,6 +122,11 @@ static int zfs_do_project(int argc, char **argv);
static int zfs_do_version(int argc, char **argv); static int zfs_do_version(int argc, char **argv);
static int zfs_do_redact(int argc, char **argv); static int zfs_do_redact(int argc, char **argv);
#ifdef __FreeBSD__
static int zfs_do_jail(int argc, char **argv);
static int zfs_do_unjail(int argc, char **argv);
#endif
/* /*
* Enable a reasonable set of defaults for libumem debugging on DEBUG builds. * Enable a reasonable set of defaults for libumem debugging on DEBUG builds.
*/ */
@ -176,6 +181,8 @@ typedef enum {
HELP_CHANGE_KEY, HELP_CHANGE_KEY,
HELP_VERSION, HELP_VERSION,
HELP_REDACT, HELP_REDACT,
HELP_JAIL,
HELP_UNJAIL
} zfs_help_t; } zfs_help_t;
typedef struct zfs_command { typedef struct zfs_command {
@ -240,6 +247,11 @@ static zfs_command_t command_table[] = {
{ "unload-key", zfs_do_unload_key, HELP_UNLOAD_KEY }, { "unload-key", zfs_do_unload_key, HELP_UNLOAD_KEY },
{ "change-key", zfs_do_change_key, HELP_CHANGE_KEY }, { "change-key", zfs_do_change_key, HELP_CHANGE_KEY },
{ "redact", zfs_do_redact, HELP_REDACT }, { "redact", zfs_do_redact, HELP_REDACT },
#ifdef __FreeBSD__
{ "jail", zfs_do_jail, HELP_JAIL },
{ "unjail", zfs_do_unjail, HELP_UNJAIL },
#endif
}; };
#define NCOMMAND (sizeof (command_table) / sizeof (command_table[0])) #define NCOMMAND (sizeof (command_table) / sizeof (command_table[0]))
@ -391,6 +403,10 @@ get_usage(zfs_help_t idx)
case HELP_REDACT: case HELP_REDACT:
return (gettext("\tredact <snapshot> <bookmark> " return (gettext("\tredact <snapshot> <bookmark> "
"<redaction_snapshot> ...")); "<redaction_snapshot> ..."));
case HELP_JAIL:
return (gettext("\tjail <jailid|jailname> <filesystem>\n"));
case HELP_UNJAIL:
return (gettext("\tunjail <jailid|jailname> <filesystem>\n"));
} }
abort(); abort();
@ -734,7 +750,7 @@ zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type)
*/ */
if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type, B_FALSE) && if (zfs_prop_valid_for_type(ZFS_PROP_CANMOUNT, type, B_FALSE) &&
zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON) { zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_ON) {
if (geteuid() != 0) { if (zfs_mount_delegation_check()) {
(void) fprintf(stderr, gettext("filesystem " (void) fprintf(stderr, gettext("filesystem "
"successfully created, but it may only be " "successfully created, but it may only be "
"mounted by root\n")); "mounted by root\n"));
@ -6970,7 +6986,6 @@ unshare_unmount_path(int op, char *path, int flags, boolean_t is_manual)
const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount"; const char *cmdname = (op == OP_SHARE) ? "unshare" : "unmount";
ino_t path_inode; ino_t path_inode;
/* /*
* Search for the given (major,minor) pair in the mount table. * Search for the given (major,minor) pair in the mount table.
*/ */
@ -7233,8 +7248,12 @@ unshare_unmount(int op, int argc, char **argv)
nomem(); nomem();
while ((node = uu_avl_walk_next(walk)) != NULL) { while ((node = uu_avl_walk_next(walk)) != NULL) {
uu_avl_remove(tree, node); const char *mntarg = NULL;
uu_avl_remove(tree, node);
#ifndef __FreeBSD__
mntarg = node->un_zhp->zfs_name;
#endif
switch (op) { switch (op) {
case OP_SHARE: case OP_SHARE:
if (zfs_unshareall_bytype(node->un_zhp, if (zfs_unshareall_bytype(node->un_zhp,
@ -7244,7 +7263,7 @@ unshare_unmount(int op, int argc, char **argv)
case OP_MOUNT: case OP_MOUNT:
if (zfs_unmount(node->un_zhp, if (zfs_unmount(node->un_zhp,
node->un_zhp->zfs_name, flags) != 0) mntarg, flags) != 0)
ret = 1; ret = 1;
break; break;
} }
@ -8350,3 +8369,67 @@ main(int argc, char **argv)
return (ret); return (ret);
} }
#ifdef __FreeBSD__
#include <sys/jail.h>
#include <jail.h>
/*
* Attach/detach the given dataset to/from the given jail
*/
/* ARGSUSED */
static int
zfs_do_jail_impl(int argc, char **argv, boolean_t attach)
{
zfs_handle_t *zhp;
int jailid, ret;
/* check number of arguments */
if (argc < 3) {
(void) fprintf(stderr, gettext("missing argument(s)\n"));
usage(B_FALSE);
}
if (argc > 3) {
(void) fprintf(stderr, gettext("too many arguments\n"));
usage(B_FALSE);
}
jailid = jail_getid(argv[1]);
if (jailid < 0) {
(void) fprintf(stderr, gettext("invalid jail id or name\n"));
usage(B_FALSE);
}
zhp = zfs_open(g_zfs, argv[2], ZFS_TYPE_FILESYSTEM);
if (zhp == NULL)
return (1);
ret = (zfs_jail(zhp, jailid, attach) != 0);
zfs_close(zhp);
return (ret);
}
/*
* zfs jail jailid filesystem
*
* Attach the given dataset to the given jail
*/
/* ARGSUSED */
static int
zfs_do_jail(int argc, char **argv)
{
return (zfs_do_jail_impl(argc, argv, B_TRUE));
}
/*
* zfs unjail jailid filesystem
*
* Detach the given dataset from the given jail
*/
/* ARGSUSED */
static int
zfs_do_unjail(int argc, char **argv)
{
return (zfs_do_jail_impl(argc, argv, B_FALSE));
}
#endif

View File

@ -237,7 +237,7 @@ extern proto_table_t proto_table[PROTO_END];
extern int do_mount(const char *src, const char *mntpt, char *opts, int flags); extern int do_mount(const char *src, const char *mntpt, char *opts, int flags);
extern int do_unmount(const char *mntpt, int flags); extern int do_unmount(const char *mntpt, int flags);
extern int zfs_can_user_mount(void); extern int zfs_mount_delegation_check(void);
extern int zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto); extern int zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto);
extern int unshare_one(libzfs_handle_t *hdl, const char *name, extern int unshare_one(libzfs_handle_t *hdl, const char *name,
const char *mountpoint, zfs_share_proto_t proto); const char *mountpoint, zfs_share_proto_t proto);

View File

@ -361,7 +361,7 @@ do_unmount(const char *mntpt, int flags)
} }
int int
zfs_can_user_mount(void) zfs_mount_delegation_check(void)
{ {
return (geteuid() == 0); return ((geteuid() != 0) ? EACCES : 0);
} }

View File

@ -17,6 +17,7 @@ dist_man_MANS = \
zfs-groupspace.8 \ zfs-groupspace.8 \
zfs-hold.8 \ zfs-hold.8 \
zfs-inherit.8 \ zfs-inherit.8 \
zfs-jail.8 \
zfs-list.8 \ zfs-list.8 \
zfs-load-key.8 \ zfs-load-key.8 \
zfs-mount.8 \ zfs-mount.8 \
@ -35,6 +36,7 @@ dist_man_MANS = \
zfs-share.8 \ zfs-share.8 \
zfs-snapshot.8 \ zfs-snapshot.8 \
zfs-unallow.8 \ zfs-unallow.8 \
zfs-unjail.8 \
zfs-unload-key.8 \ zfs-unload-key.8 \
zfs-unmount.8 \ zfs-unmount.8 \
zfs-upgrade.8 \ zfs-upgrade.8 \

119
man/man8/zfs-jail.8 Normal file
View File

@ -0,0 +1,119 @@
.\"
.\" CDDL HEADER START
.\"
.\" The contents of this file are subject to the terms of the
.\" Common Development and Distribution License (the "License").
.\" You may not use this file except in compliance with the License.
.\"
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
.\" or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions
.\" and limitations under the License.
.\"
.\" When distributing Covered Code, include this CDDL HEADER in each
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
.\" If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" CDDL HEADER END
.\"
.\"
.\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org>
.\" Copyright (c) 2011, 2019 by Delphix. All rights reserved.
.\" Copyright (c) 2011, Pawel Jakub Dawidek <pjd@FreeBSD.org>
.\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org>
.\" Copyright (c) 2012, Bryan Drewery <bdrewery@FreeBSD.org>
.\" Copyright (c) 2013, Steven Hartland <smh@FreeBSD.org>
.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
.\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
.\" Copyright (c) 2014 by Adam Stevko. All rights reserved.
.\" Copyright (c) 2014 Integros [integros.com]
.\" Copyright (c) 2014, Xin LI <delphij@FreeBSD.org>
.\" Copyright (c) 2014-2015, The FreeBSD Foundation, All Rights Reserved.
.\" Copyright (c) 2016 Nexenta Systems, Inc. All Rights Reserved.
.\" Copyright 2019 Richard Laager. All rights reserved.
.\" Copyright 2018 Nexenta Systems, Inc.
.\" Copyright 2019 Joyent, Inc.
.\"
.Dd December 9, 2019
.Dt ZFS-JAIL 8
.Os FreeBSD
.Sh NAME
.Nm zfs Ns Pf - Cm jail
.Nd Attaches and detaches ZFS filesystems from FreeBSD jails.
.No A Tn ZFS
dataset can be attached to a jail by using the
.Qq Nm Cm jail
subcommand. You cannot attach a dataset to one jail and the children of the
same dataset to another jail. You can also not attach the root file system
of the jail or any dataset which needs to be mounted before the zfs rc script
is run inside the jail, as it would be attached unmounted until it is
mounted from the rc script inside the jail. To allow management of the
dataset from within a jail, the
.Sy jailed
property has to be set and the jail needs access to the
.Pa /dev/zfs
device. The
.Sy quota
property cannot be changed from within a jail. See
.Xr jail 8
for information on how to allow mounting
.Tn ZFS
datasets from within a jail.
.Pp
.No A Tn ZFS
dataset can be detached from a jail using the
.Qq Nm Cm unjail
subcommand.
.Pp
After a dataset is attached to a jail and the jailed property is set, a jailed
file system cannot be mounted outside the jail, since the jail administrator
might have set the mount point to an unacceptable value.
.Sh SYNOPSIS
.Nm
.Cm jail
.Ar jailid Ns | Ns Ar jailname filesystem
.Nm
.Cm unjail
.Ar jailid Ns | Ns Ar jailname filesystem
.Sh DESCRIPTION
.Bl -tag -width ""
.It Xo
.Nm
.Cm jail
.Ar jailid filesystem
.Xc
.Pp
Attaches the specified
.Ar filesystem
to the jail identified by JID
.Ar jailid .
From now on this file system tree can be managed from within a jail if the
.Sy jailed
property has been set. To use this functuinality, the jail needs the
.Va allow.mount
and
.Va allow.mount.zfs
parameters set to 1 and the
.Va enforce_statfs
parameter set to a value lower than 2.
.Pp
See
.Xr jail 8
for more information on managing jails and configuring the parameters above.
.It Xo
.Nm
.Cm unjail
.Ar jailid filesystem
.Xc
.Pp
Detaches the specified
.Ar filesystem
from the jail identified by JID
.Ar jailid .
.El
.Sh SEE ALSO
.Xr jail 8 ,
.Xr zfsprops 8

1
man/man8/zfs-unjail.8 Symbolic link
View File

@ -0,0 +1 @@
zfs-jail.8

View File

@ -22,10 +22,17 @@
.\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. .\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org> .\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org>
.\" Copyright (c) 2011, 2019 by Delphix. All rights reserved. .\" Copyright (c) 2011, 2019 by Delphix. All rights reserved.
.\" Copyright (c) 2011, Pawel Jakub Dawidek <pjd@FreeBSD.org>
.\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org>
.\" Copyright (c) 2012, Bryan Drewery <bdrewery@FreeBSD.org>
.\" Copyright (c) 2013, Steven Hartland <smh@FreeBSD.org>
.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved. .\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
.\" Copyright (c) 2014, Joyent, Inc. All rights reserved. .\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
.\" Copyright (c) 2014 by Adam Stevko. All rights reserved. .\" Copyright (c) 2014 by Adam Stevko. All rights reserved.
.\" Copyright (c) 2014 Integros [integros.com] .\" Copyright (c) 2014 Integros [integros.com]
.\" Copyright (c) 2014, Xin LI <delphij@FreeBSD.org>
.\" Copyright (c) 2014-2015, The FreeBSD Foundation, All Rights Reserved.
.\" Copyright (c) 2016 Nexenta Systems, Inc. All Rights Reserved.
.\" Copyright 2019 Richard Laager. All rights reserved. .\" Copyright 2019 Richard Laager. All rights reserved.
.\" Copyright 2018 Nexenta Systems, Inc. .\" Copyright 2018 Nexenta Systems, Inc.
.\" Copyright 2019 Joyent, Inc. .\" Copyright 2019 Joyent, Inc.
@ -267,6 +274,13 @@ Unload a key for the specified dataset, removing the ability to access the datas
Execute ZFS administrative operations Execute ZFS administrative operations
programmatically via a Lua script-language channel program. programmatically via a Lua script-language channel program.
.El .El
.Ss Jails
.Bl -tag -width ""
.It Xr zfs-jail 8
Attaches a filesystem to a jail.
.It Xr zfs-unjail 8
Detaches a filesystem from a jail.
.El
.Sh EXIT STATUS .Sh EXIT STATUS
The The
.Nm .Nm

View File

@ -22,10 +22,17 @@
.\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved. .\" Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
.\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org> .\" Copyright 2011 Joshua M. Clulow <josh@sysmgr.org>
.\" Copyright (c) 2011, 2019 by Delphix. All rights reserved. .\" Copyright (c) 2011, 2019 by Delphix. All rights reserved.
.\" Copyright (c) 2011, Pawel Jakub Dawidek <pjd@FreeBSD.org>
.\" Copyright (c) 2012, Glen Barber <gjb@FreeBSD.org>
.\" Copyright (c) 2012, Bryan Drewery <bdrewery@FreeBSD.org>
.\" Copyright (c) 2013, Steven Hartland <smh@FreeBSD.org>
.\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved. .\" Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
.\" Copyright (c) 2014, Joyent, Inc. All rights reserved. .\" Copyright (c) 2014, Joyent, Inc. All rights reserved.
.\" Copyright (c) 2014 by Adam Stevko. All rights reserved. .\" Copyright (c) 2014 by Adam Stevko. All rights reserved.
.\" Copyright (c) 2014 Integros [integros.com] .\" Copyright (c) 2014 Integros [integros.com]
.\" Copyright (c) 2016 Nexenta Systems, Inc. All Rights Reserved.
.\" Copyright (c) 2014, Xin LI <delphij@FreeBSD.org>
.\" Copyright (c) 2014-2015, The FreeBSD Foundation, All Rights Reserved.
.\" Copyright 2019 Richard Laager. All rights reserved. .\" Copyright 2019 Richard Laager. All rights reserved.
.\" Copyright 2018 Nexenta Systems, Inc. .\" Copyright 2018 Nexenta Systems, Inc.
.\" Copyright 2019 Joyent, Inc. .\" Copyright 2019 Joyent, Inc.
@ -1709,9 +1716,17 @@ are equivalent to the
and and
.Sy noxattr .Sy noxattr
mount options. mount options.
.It Sy jailed Ns = Ns Cm off | on
Controls whether the dataset is managed from a jail. See the
.Qq Sx Jails
section in
.Xr zfs 8
for more information. Jails are a FreeBSD feature and are not relevant on
other platforms. The default value is
.Cm off .
.It Sy zoned Ns = Ns Sy on Ns | Ns Sy off .It Sy zoned Ns = Ns Sy on Ns | Ns Sy off
Controls whether the dataset is managed from a non-global zone. Zones are a Controls whether the dataset is managed from a non-global zone. Zones are a
Solaris feature and are not relevant on Linux. The default value is Solaris feature and are not relevant on other platforms. The default value is
.Sy off . .Sy off .
.El .El
.Pp .Pp

View File

@ -379,8 +379,13 @@ zfs_prop_init(void)
zprop_register_index(ZFS_PROP_READONLY, "readonly", 0, PROP_INHERIT, zprop_register_index(ZFS_PROP_READONLY, "readonly", 0, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "on | off", "RDONLY", ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "on | off", "RDONLY",
boolean_table); boolean_table);
#ifdef __FreeBSD__
zprop_register_index(ZFS_PROP_ZONED, "jailed", 0, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM, "on | off", "JAILED", boolean_table);
#else
zprop_register_index(ZFS_PROP_ZONED, "zoned", 0, PROP_INHERIT, zprop_register_index(ZFS_PROP_ZONED, "zoned", 0, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM, "on | off", "ZONED", boolean_table); ZFS_TYPE_FILESYSTEM, "on | off", "ZONED", boolean_table);
#endif
zprop_register_index(ZFS_PROP_VSCAN, "vscan", 0, PROP_INHERIT, zprop_register_index(ZFS_PROP_VSCAN, "vscan", 0, PROP_INHERIT,
ZFS_TYPE_FILESYSTEM, "on | off", "VSCAN", boolean_table); ZFS_TYPE_FILESYSTEM, "on | off", "VSCAN", boolean_table);
zprop_register_index(ZFS_PROP_NBMAND, "nbmand", 0, PROP_INHERIT, zprop_register_index(ZFS_PROP_NBMAND, "nbmand", 0, PROP_INHERIT,

View File

@ -743,6 +743,7 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
uint64_t obj; uint64_t obj;
dsl_dataset_t *ds; dsl_dataset_t *ds;
uint64_t zoned; uint64_t zoned;
const char *zonedstr;
ASSERT(prop == ZFS_PROP_FILESYSTEM_LIMIT || ASSERT(prop == ZFS_PROP_FILESYSTEM_LIMIT ||
prop == ZFS_PROP_SNAPSHOT_LIMIT); prop == ZFS_PROP_SNAPSHOT_LIMIT);
@ -763,7 +764,8 @@ dsl_enforce_ds_ss_limits(dsl_dir_t *dd, zfs_prop_t prop, cred_t *cr)
if (dsl_dataset_hold_obj(dd->dd_pool, obj, FTAG, &ds) != 0) if (dsl_dataset_hold_obj(dd->dd_pool, obj, FTAG, &ds) != 0)
return (ENFORCE_ALWAYS); return (ENFORCE_ALWAYS);
if (dsl_prop_get_ds(ds, "zoned", 8, 1, &zoned, NULL) || zoned) { zonedstr = zfs_prop_to_name(ZFS_PROP_ZONED);
if (dsl_prop_get_ds(ds, zonedstr, 8, 1, &zoned, NULL) || zoned) {
/* Only root can access zoned fs's from the GZ */ /* Only root can access zoned fs's from the GZ */
enforce = ENFORCE_ALWAYS; enforce = ENFORCE_ALWAYS;
} else { } else {