bectl: use jail id as the default jail name for a boot environment

By default, bectl is setting the jail 'name' parameter to the boot
environment name, which causes an error when the boot environment name is
not a valid jail name. With the attached fix, when no name is supplied, the
default jail name will be the jail id - this is is the same behavior as the
jail command.

Additionally, this commit addresses two other bugs that prevented unjailing
in scenarios where the jail name does not match the boot environment name:

1. In 'bectl_locate_jail', 'mountpoint' is used to resolve the boot
  environment path, but really 'mounted' should be used. 'mountpoint' is the
  path where the zfs dataset will be mounted. 'mounted' is the path where
  the dataset is actually mounted.

2. in 'bectl_search_jail_paths', 'jail_getv' would fail after the first
  call. Which is fine, if the boot environment you're unjailing is the next
  one up. According to 'man jail_getv', it's expecting name and value
  strings. 'jail_getv' is being passed an integer for the lastjid, so amend
  that to use a string instead.

Test cases have been amended to reflect the bugs found.

PR:		233637
Submitted by:	Rob <rob.fx907_gmail.com>
MFC after:	3 days
Differential Revision:	https://reviews.freebsd.org/D18607
This commit is contained in:
kevans 2018-12-25 15:18:41 +00:00
parent 04945428e9
commit 5234db7610
3 changed files with 50 additions and 21 deletions

View File

@ -18,7 +18,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 21, 2018
.Dd December 25, 2018
.Dt BECTL 8
.Os
.Sh NAME
@ -52,7 +52,6 @@
.Cm jail
.Brq Fl b | Fl U
.Oo Bro Fl o Ar key Ns = Ns Ar value | Fl u Ar key Brc Oc Ns ...
.Brq Ar jailID | jailName
.Ar bootenv
.Op Ar utility Op Ar argument ...
.Nm
@ -153,7 +152,6 @@ from
.Cm jail
.Brq Fl b | Fl U
.Oo Bro Fl o Ar key Ns = Ns Ar value | Fl u Ar key Brc Oc Ns ...
.Brq Ar jailID | jailName
.Ao Ar bootenv Ac
.Op Ar utility Op Ar argument ...
.Xc
@ -193,10 +191,7 @@ The
.Va host.hostname ,
and
.Va path
may not actually be unset.
Attempts to unset any of these will revert them to the default values specified
below, if they have been overwritten by
.Fl o .
must be set, the default values are specified below.
.Pp
All
.Ar key Ns = Ns Ar value
@ -207,7 +202,7 @@ The following default parameters are provided:
.It Va allow.mount Ta Cm true
.It Va allow.mount.devfs Ta Cm true
.It Va enforce_statfs Ta Cm 1
.It Va name Ta Va bootenv
.It Va name Ta jail id
.It Va host.hostname Ta Va bootenv
.It Va path Ta Set to a path in /tmp generated by
.Xr libbe 3 .

View File

@ -181,10 +181,10 @@ bectl_cmd_jail(int argc, char *argv[])
{
char *bootenv, *mountpoint;
int jid, opt, ret;
bool default_hostname, default_name, interactive, unjail;
bool default_hostname, interactive, unjail;
pid_t pid;
default_hostname = default_name = interactive = unjail = true;
default_hostname = interactive = unjail = true;
jpcnt = INIT_PARAMCOUNT;
jp = malloc(jpcnt * sizeof(*jp));
if (jp == NULL)
@ -206,8 +206,6 @@ bectl_cmd_jail(int argc, char *argv[])
* optarg has been modified to null terminate
* at the assignment operator.
*/
if (strcmp(optarg, "name") == 0)
default_name = false;
if (strcmp(optarg, "host.hostname") == 0)
default_hostname = false;
}
@ -217,8 +215,6 @@ bectl_cmd_jail(int argc, char *argv[])
break;
case 'u':
if ((ret = jailparam_delarg(optarg)) == 0) {
if (strcmp(optarg, "name") == 0)
default_name = true;
if (strcmp(optarg, "host.hostname") == 0)
default_hostname = true;
} else if (ret != ENOENT) {
@ -259,8 +255,6 @@ bectl_cmd_jail(int argc, char *argv[])
return (1);
}
if (default_name)
jailparam_add("name", bootenv);
if (default_hostname)
jailparam_add("host.hostname", bootenv);
@ -316,15 +310,23 @@ bectl_cmd_jail(int argc, char *argv[])
static int
bectl_search_jail_paths(const char *mnt)
{
char jailpath[MAXPATHLEN];
int jid;
char lastjid[16];
char jailpath[MAXPATHLEN];
/* jail_getv expects name/value strings */
snprintf(lastjid, sizeof(lastjid), "%d", 0);
jid = 0;
(void)mnt;
while ((jid = jail_getv(0, "lastjid", &jid, "path", &jailpath,
while ((jid = jail_getv(0, "lastjid", lastjid, "path", &jailpath,
NULL)) != -1) {
/* the jail we've been looking for */
if (strcmp(jailpath, mnt) == 0)
return (jid);
/* update lastjid and keep on looking */
snprintf(lastjid, sizeof(lastjid), "%d", jid);
}
return (-1);
@ -354,8 +356,11 @@ bectl_locate_jail(const char *ident)
return (-1);
if (nvlist_lookup_nvlist(belist, ident, &props) == 0) {
/* We'll attempt to resolve the jid by way of mountpoint */
if (nvlist_lookup_string(props, "mountpoint", &mnt) == 0) {
/* path where a boot environment is mounted */
if (nvlist_lookup_string(props, "mounted", &mnt) == 0) {
/* looking for a jail that matches our bootenv path */
jid = bectl_search_jail_paths(mnt);
be_prop_list_free(belist);
return (jid);

View File

@ -254,6 +254,14 @@ bectl_jail_body()
atf_check cp /rescue/rescue ${root}/rescue/rescue
atf_check bectl -r ${zpool}/ROOT umount default
# Prepare a second boot environment
atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT create -e default target
# When a jail name is not explicit, it should match the jail id.
atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT jail -b -o jid=233637 default
atf_check -o inline:"233637\n" -s exit:0 -x "jls -j 233637 name"
atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail default
# Basic command-mode tests, with and without jail cleanup
atf_check -o inline:"rescue\n" bectl -r ${zpool}/ROOT \
jail default /rescue/rescue ls -1
@ -271,6 +279,11 @@ bectl_jail_body()
atf_check bectl -r ${zpool}/ROOT jail -b default
atf_check bectl -r ${zpool}/ROOT unjail default
atf_check -s not-exit:0 -x "jls | grep -F \"${root}\""
# 'unjail' by BE name. Force bectl to lookup jail id by the BE name.
atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT jail -b default
atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT jail -b -o name=bectl_test target
atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail target
atf_check -o empty -s exit:0 bectl -r ${zpool}/ROOT unjail default
# cannot unjail an unjailed BE (by either command name)
atf_check -e ignore -s not-exit:0 bectl -r ${zpool}/ROOT ujail default
atf_check -e ignore -s not-exit:0 bectl -r ${zpool}/ROOT unjail default
@ -281,8 +294,24 @@ bectl_jail_body()
atf_check -s not-exit:0 -x "mount | grep -F '${root}'"
atf_check bectl -r ${zpool}/ROOT ujail default
}
# If a test has failed, it's possible that the boot environment hasn't
# been 'unjail'ed. We want to remove the jail before 'bectl_cleanup'
# attempts to destroy the zpool.
bectl_jail_cleanup()
{
for bootenv in "default" "target"; do
# mountpoint of the boot environment
mountpoint="$(bectl -r bectl_test/ROOT list -H | grep ${bootenv} | awk '{print $3}')"
# see if any jail paths match the boot environment mountpoint
jailid="$(jls | grep ${mountpoint} | awk '{print $1}')"
if [ -z "$jailid" ]; then
continue;
fi
jail -r ${jailid}
done;
bectl_cleanup bectl_test
}