2018-08-06 03:32:25 +00:00
|
|
|
/*-
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
|
|
*
|
|
|
|
* Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2018-08-07 14:02:41 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2018-08-06 03:32:25 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/jail.h>
|
|
|
|
#include <sys/mount.h>
|
2018-08-23 01:45:18 +00:00
|
|
|
#include <sys/wait.h>
|
2018-08-06 03:32:25 +00:00
|
|
|
#include <err.h>
|
|
|
|
#include <jail.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include <be.h>
|
|
|
|
#include "bectl.h"
|
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
#define MNTTYPE_ZFS 222
|
|
|
|
|
2018-08-06 03:32:25 +00:00
|
|
|
static void jailparam_add(const char *name, const char *val);
|
2018-08-14 18:35:33 +00:00
|
|
|
static int jailparam_del(const char *name);
|
2018-08-06 03:32:25 +00:00
|
|
|
static bool jailparam_addarg(char *arg);
|
2018-08-14 18:35:33 +00:00
|
|
|
static int jailparam_delarg(char *arg);
|
2018-08-06 03:32:25 +00:00
|
|
|
|
|
|
|
static int bectl_search_jail_paths(const char *mnt);
|
|
|
|
static int bectl_locate_jail(const char *ident);
|
2019-03-19 17:38:54 +00:00
|
|
|
static int bectl_jail_cleanup(char *mountpoint, int jid);
|
2018-08-06 03:32:25 +00:00
|
|
|
|
2018-08-16 17:56:03 +00:00
|
|
|
static char mnt_loc[BE_MAXPATHLEN];
|
2019-03-19 17:38:54 +00:00
|
|
|
static nvlist_t *jailparams;
|
2018-08-06 03:32:25 +00:00
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
static const char *disabled_params[] = {
|
|
|
|
"command", "exec.start", "nopersist", "persist", NULL
|
|
|
|
};
|
2018-08-06 03:32:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
jailparam_add(const char *name, const char *val)
|
|
|
|
{
|
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
nvlist_add_string(jailparams, name, val);
|
2018-08-06 03:32:25 +00:00
|
|
|
}
|
|
|
|
|
2018-08-14 18:35:33 +00:00
|
|
|
static int
|
2018-08-06 15:21:46 +00:00
|
|
|
jailparam_del(const char *name)
|
|
|
|
{
|
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
nvlist_remove_all(jailparams, name);
|
2018-08-14 18:35:33 +00:00
|
|
|
return (0);
|
2018-08-06 15:21:46 +00:00
|
|
|
}
|
|
|
|
|
2018-08-06 03:32:25 +00:00
|
|
|
static bool
|
|
|
|
jailparam_addarg(char *arg)
|
|
|
|
{
|
|
|
|
char *name, *val;
|
2019-03-19 17:38:54 +00:00
|
|
|
size_t i, len;
|
2018-08-06 03:32:25 +00:00
|
|
|
|
|
|
|
if (arg == NULL)
|
|
|
|
return (false);
|
|
|
|
name = arg;
|
|
|
|
if ((val = strchr(arg, '=')) == NULL) {
|
|
|
|
fprintf(stderr, "bectl jail: malformed jail option '%s'\n",
|
|
|
|
arg);
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
|
|
|
|
*val++ = '\0';
|
|
|
|
if (strcmp(name, "path") == 0) {
|
2018-08-16 17:56:03 +00:00
|
|
|
if (strlen(val) >= BE_MAXPATHLEN) {
|
2018-08-06 03:32:25 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"bectl jail: skipping too long path assignment '%s' (max length = %d)\n",
|
|
|
|
val, BE_MAXPATHLEN);
|
|
|
|
return (false);
|
|
|
|
}
|
2018-08-16 17:59:49 +00:00
|
|
|
strlcpy(mnt_loc, val, sizeof(mnt_loc));
|
2018-08-06 03:32:25 +00:00
|
|
|
}
|
2019-03-19 17:38:54 +00:00
|
|
|
|
|
|
|
for (i = 0; disabled_params[i] != NULL; i++) {
|
|
|
|
len = strlen(disabled_params[i]);
|
|
|
|
if (strncmp(disabled_params[i], name, len) == 0) {
|
|
|
|
fprintf(stderr, "invalid jail parameter: %s\n", name);
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-06 03:32:25 +00:00
|
|
|
jailparam_add(name, val);
|
|
|
|
return (true);
|
|
|
|
}
|
|
|
|
|
2018-08-14 18:35:33 +00:00
|
|
|
static int
|
2018-08-06 15:21:46 +00:00
|
|
|
jailparam_delarg(char *arg)
|
|
|
|
{
|
|
|
|
char *name, *val;
|
|
|
|
|
|
|
|
if (arg == NULL)
|
2018-08-14 18:35:33 +00:00
|
|
|
return (EINVAL);
|
2018-08-06 15:21:46 +00:00
|
|
|
name = arg;
|
|
|
|
if ((val = strchr(name, '=')) != NULL)
|
|
|
|
*val++ = '\0';
|
|
|
|
|
|
|
|
if (strcmp(name, "path") == 0)
|
|
|
|
*mnt_loc = '\0';
|
2018-08-14 18:35:33 +00:00
|
|
|
return (jailparam_del(name));
|
2018-08-06 15:21:46 +00:00
|
|
|
}
|
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
static int
|
|
|
|
build_jailcmd(char ***argvp, bool interactive, int argc, char *argv[])
|
|
|
|
{
|
2023-04-03 14:49:30 +00:00
|
|
|
char *cmd, **jargv;
|
|
|
|
const char *name, *val;
|
2019-03-19 17:38:54 +00:00
|
|
|
nvpair_t *nvp;
|
|
|
|
size_t i, iarg, nargv;
|
|
|
|
|
|
|
|
cmd = NULL;
|
|
|
|
nvp = NULL;
|
|
|
|
iarg = i = 0;
|
|
|
|
if (nvlist_size(jailparams, &nargv, NV_ENCODE_NATIVE) != 0)
|
|
|
|
return (1);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Number of args + "/usr/sbin/jail", "-c", and ending NULL.
|
|
|
|
* If interactive also include command.
|
|
|
|
*/
|
|
|
|
nargv += 3;
|
|
|
|
if (interactive) {
|
|
|
|
if (argc == 0)
|
|
|
|
nargv++;
|
|
|
|
else
|
|
|
|
nargv += argc;
|
|
|
|
}
|
|
|
|
|
2019-05-28 16:12:16 +00:00
|
|
|
jargv = *argvp = calloc(nargv, sizeof(*jargv));
|
2019-03-19 17:38:54 +00:00
|
|
|
if (jargv == NULL)
|
|
|
|
err(2, "calloc");
|
|
|
|
|
|
|
|
jargv[iarg++] = strdup("/usr/sbin/jail");
|
|
|
|
jargv[iarg++] = strdup("-c");
|
|
|
|
while ((nvp = nvlist_next_nvpair(jailparams, nvp)) != NULL) {
|
|
|
|
name = nvpair_name(nvp);
|
|
|
|
if (nvpair_value_string(nvp, &val) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (asprintf(&jargv[iarg++], "%s=%s", name, val) < 0)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (interactive) {
|
|
|
|
if (argc < 1)
|
|
|
|
cmd = strdup("/bin/sh");
|
|
|
|
else {
|
|
|
|
cmd = argv[0];
|
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (asprintf(&jargv[iarg++], "command=%s", cmd) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
if (argc < 1) {
|
|
|
|
free(cmd);
|
|
|
|
cmd = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; argc > 0; argc--) {
|
|
|
|
if (asprintf(&jargv[iarg++], "%s", argv[0]) < 0)
|
|
|
|
goto error;
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (interactive && argc < 1)
|
|
|
|
free(cmd);
|
|
|
|
for (; i < iarg - 1; i++) {
|
|
|
|
free(jargv[i]);
|
|
|
|
}
|
|
|
|
free(jargv);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove jail and cleanup any non zfs mounts. */
|
|
|
|
static int
|
|
|
|
bectl_jail_cleanup(char *mountpoint, int jid)
|
|
|
|
{
|
|
|
|
struct statfs *mntbuf;
|
|
|
|
size_t i, searchlen, mntsize;
|
|
|
|
|
|
|
|
if (jid >= 0 && jail_remove(jid) != 0) {
|
|
|
|
fprintf(stderr, "unable to remove jail");
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
searchlen = strnlen(mountpoint, MAXPATHLEN);
|
|
|
|
mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
|
|
|
|
for (i = 0; i < mntsize; i++) {
|
|
|
|
if (strncmp(mountpoint, mntbuf[i].f_mntonname, searchlen) == 0 &&
|
|
|
|
mntbuf[i].f_type != MNTTYPE_ZFS) {
|
|
|
|
|
|
|
|
if (unmount(mntbuf[i].f_mntonname, 0) != 0) {
|
|
|
|
fprintf(stderr, "bectl jail: unable to unmount filesystem %s",
|
|
|
|
mntbuf[i].f_mntonname);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2018-08-06 03:32:25 +00:00
|
|
|
int
|
|
|
|
bectl_cmd_jail(int argc, char *argv[])
|
|
|
|
{
|
2019-03-19 17:38:54 +00:00
|
|
|
char *bootenv, **jargv, *mountpoint;
|
|
|
|
int i, jid, mntflags, opt, ret;
|
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
2018-12-25 15:18:41 +00:00
|
|
|
bool default_hostname, interactive, unjail;
|
2018-08-23 01:45:18 +00:00
|
|
|
pid_t pid;
|
2018-08-06 03:32:25 +00:00
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
|
2019-01-10 03:27:20 +00:00
|
|
|
/* XXX TODO: Allow shallow */
|
|
|
|
mntflags = BE_MNT_DEEP;
|
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
2018-12-25 15:18:41 +00:00
|
|
|
default_hostname = interactive = unjail = true;
|
2019-03-19 17:38:54 +00:00
|
|
|
|
|
|
|
if ((nvlist_alloc(&jailparams, NV_UNIQUE_NAME, 0)) != 0) {
|
|
|
|
fprintf(stderr, "nvlist_alloc() failed\n");
|
|
|
|
return (1);
|
|
|
|
}
|
2018-08-06 03:32:25 +00:00
|
|
|
|
|
|
|
jailparam_add("persist", "true");
|
|
|
|
jailparam_add("allow.mount", "true");
|
|
|
|
jailparam_add("allow.mount.devfs", "true");
|
|
|
|
jailparam_add("enforce_statfs", "1");
|
|
|
|
|
2018-08-23 01:45:18 +00:00
|
|
|
while ((opt = getopt(argc, argv, "bo:Uu:")) != -1) {
|
2018-08-06 03:32:25 +00:00
|
|
|
switch (opt) {
|
2018-08-17 01:59:19 +00:00
|
|
|
case 'b':
|
|
|
|
interactive = false;
|
|
|
|
break;
|
2018-08-06 03:32:25 +00:00
|
|
|
case 'o':
|
|
|
|
if (jailparam_addarg(optarg)) {
|
|
|
|
/*
|
|
|
|
* optarg has been modified to null terminate
|
|
|
|
* at the assignment operator.
|
|
|
|
*/
|
|
|
|
if (strcmp(optarg, "host.hostname") == 0)
|
|
|
|
default_hostname = false;
|
2019-03-19 17:38:54 +00:00
|
|
|
} else {
|
|
|
|
return (1);
|
2018-08-06 03:32:25 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-08-23 01:45:18 +00:00
|
|
|
case 'U':
|
|
|
|
unjail = false;
|
|
|
|
break;
|
2018-08-06 15:21:46 +00:00
|
|
|
case 'u':
|
2018-08-14 18:35:33 +00:00
|
|
|
if ((ret = jailparam_delarg(optarg)) == 0) {
|
2018-08-06 15:21:46 +00:00
|
|
|
if (strcmp(optarg, "host.hostname") == 0)
|
|
|
|
default_hostname = true;
|
2018-08-14 18:35:33 +00:00
|
|
|
} else if (ret != ENOENT) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"bectl jail: error unsetting \"%s\"\n",
|
|
|
|
optarg);
|
|
|
|
return (ret);
|
2018-08-06 15:21:46 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-08-06 03:32:25 +00:00
|
|
|
default:
|
|
|
|
fprintf(stderr, "bectl jail: unknown option '-%c'\n",
|
|
|
|
optopt);
|
|
|
|
return (usage(false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
|
|
|
if (argc < 1) {
|
|
|
|
fprintf(stderr, "bectl jail: missing boot environment name\n");
|
|
|
|
return (usage(false));
|
|
|
|
}
|
|
|
|
|
|
|
|
bootenv = argv[0];
|
2019-03-19 17:38:54 +00:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2018-08-06 03:32:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX TODO: if its already mounted, perhaps there should be a flag to
|
|
|
|
* indicate its okay to proceed??
|
|
|
|
*/
|
|
|
|
if (*mnt_loc == '\0')
|
|
|
|
mountpoint = NULL;
|
|
|
|
else
|
|
|
|
mountpoint = mnt_loc;
|
2019-01-10 03:27:20 +00:00
|
|
|
if (be_mount(be, bootenv, mountpoint, mntflags, mnt_loc) != BE_ERR_SUCCESS) {
|
2018-08-06 03:32:25 +00:00
|
|
|
fprintf(stderr, "could not mount bootenv\n");
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (default_hostname)
|
|
|
|
jailparam_add("host.hostname", bootenv);
|
2018-08-17 01:59:19 +00:00
|
|
|
|
2018-08-06 03:32:25 +00:00
|
|
|
/*
|
|
|
|
* This is our indicator that path was not set by the user, so we'll use
|
|
|
|
* the path that libbe generated for us.
|
|
|
|
*/
|
2019-03-19 17:38:54 +00:00
|
|
|
if (mountpoint == NULL) {
|
2018-08-06 03:32:25 +00:00
|
|
|
jailparam_add("path", mnt_loc);
|
2019-03-19 17:38:54 +00:00
|
|
|
mountpoint = mnt_loc;
|
2018-08-06 03:32:25 +00:00
|
|
|
}
|
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
if ((build_jailcmd(&jargv, interactive, argc, argv)) != 0) {
|
|
|
|
fprintf(stderr, "unable to build argument list for jail command\n");
|
|
|
|
return (1);
|
|
|
|
}
|
2018-08-23 01:45:18 +00:00
|
|
|
|
|
|
|
pid = fork();
|
2019-03-19 17:38:54 +00:00
|
|
|
|
|
|
|
switch (pid) {
|
2018-08-23 01:45:18 +00:00
|
|
|
case -1:
|
|
|
|
perror("fork");
|
|
|
|
return (1);
|
|
|
|
case 0:
|
2019-03-19 17:38:54 +00:00
|
|
|
execv("/usr/sbin/jail", jargv);
|
|
|
|
fprintf(stderr, "bectl jail: failed to execute\n");
|
2019-05-28 16:12:16 +00:00
|
|
|
return (1);
|
2018-08-23 01:45:18 +00:00
|
|
|
default:
|
|
|
|
waitpid(pid, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
for (i = 0; jargv[i] != NULL; i++) {
|
|
|
|
free(jargv[i]);
|
|
|
|
}
|
|
|
|
free(jargv);
|
|
|
|
|
2020-12-06 15:58:50 +00:00
|
|
|
/* Non-interactive (-b) mode means the jail sticks around. */
|
|
|
|
if (interactive && unjail) {
|
2019-03-19 17:38:54 +00:00
|
|
|
/*
|
|
|
|
* We're not checking the jail id result here because in the
|
|
|
|
* case of invalid param, or last command in jail was an error
|
|
|
|
* the jail will not exist upon exit. bectl_jail_cleanup will
|
|
|
|
* only jail_remove if the jid is >= 0.
|
|
|
|
*/
|
|
|
|
jid = bectl_locate_jail(bootenv);
|
|
|
|
bectl_jail_cleanup(mountpoint, jid);
|
2019-01-10 03:27:20 +00:00
|
|
|
be_unmount(be, bootenv, 0);
|
2018-08-17 01:59:19 +00:00
|
|
|
}
|
|
|
|
|
2018-08-06 03:32:25 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bectl_search_jail_paths(const char *mnt)
|
|
|
|
{
|
|
|
|
int jid;
|
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
2018-12-25 15:18:41 +00:00
|
|
|
char lastjid[16];
|
|
|
|
char jailpath[MAXPATHLEN];
|
|
|
|
|
|
|
|
/* jail_getv expects name/value strings */
|
|
|
|
snprintf(lastjid, sizeof(lastjid), "%d", 0);
|
2018-08-06 03:32:25 +00:00
|
|
|
|
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
2018-12-25 15:18:41 +00:00
|
|
|
while ((jid = jail_getv(0, "lastjid", lastjid, "path", &jailpath,
|
2018-08-06 03:32:25 +00:00
|
|
|
NULL)) != -1) {
|
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
2018-12-25 15:18:41 +00:00
|
|
|
|
|
|
|
/* the jail we've been looking for */
|
2018-08-06 03:32:25 +00:00
|
|
|
if (strcmp(jailpath, mnt) == 0)
|
|
|
|
return (jid);
|
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
2018-12-25 15:18:41 +00:00
|
|
|
|
|
|
|
/* update lastjid and keep on looking */
|
|
|
|
snprintf(lastjid, sizeof(lastjid), "%d", jid);
|
2018-08-06 03:32:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Locate a jail based on an arbitrary identifier. This may be either a name,
|
|
|
|
* a jid, or a BE name. Returns the jid or -1 on failure.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
bectl_locate_jail(const char *ident)
|
|
|
|
{
|
|
|
|
nvlist_t *belist, *props;
|
2023-04-03 14:49:30 +00:00
|
|
|
const char *mnt;
|
2018-08-06 03:32:25 +00:00
|
|
|
int jid;
|
|
|
|
|
|
|
|
/* Try the easy-match first */
|
|
|
|
jid = jail_getid(ident);
|
2019-06-02 14:05:51 +00:00
|
|
|
/*
|
|
|
|
* jail_getid(0) will always return 0, because this prison does exist.
|
|
|
|
* bectl(8) knows that this is not what it wants, so we should fall
|
|
|
|
* back to mount point search.
|
|
|
|
*/
|
|
|
|
if (jid > 0)
|
2018-08-06 03:32:25 +00:00
|
|
|
return (jid);
|
|
|
|
|
|
|
|
/* Attempt to try it as a BE name, first */
|
|
|
|
if (be_prop_list_alloc(&belist) != 0)
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
if (be_get_bootenv_props(be, belist) != 0)
|
|
|
|
return (-1);
|
|
|
|
|
|
|
|
if (nvlist_lookup_nvlist(belist, ident, &props) == 0) {
|
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
2018-12-25 15:18:41 +00:00
|
|
|
|
|
|
|
/* path where a boot environment is mounted */
|
|
|
|
if (nvlist_lookup_string(props, "mounted", &mnt) == 0) {
|
|
|
|
|
|
|
|
/* looking for a jail that matches our bootenv path */
|
2018-08-06 03:32:25 +00:00
|
|
|
jid = bectl_search_jail_paths(mnt);
|
|
|
|
be_prop_list_free(belist);
|
|
|
|
return (jid);
|
|
|
|
}
|
|
|
|
|
|
|
|
be_prop_list_free(belist);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
bectl_cmd_unjail(int argc, char *argv[])
|
|
|
|
{
|
2018-08-16 17:56:03 +00:00
|
|
|
char path[MAXPATHLEN];
|
2018-08-06 03:32:25 +00:00
|
|
|
char *cmd, *name, *target;
|
|
|
|
int jid;
|
|
|
|
|
|
|
|
/* Store alias used */
|
|
|
|
cmd = argv[0];
|
|
|
|
|
|
|
|
if (argc != 2) {
|
|
|
|
fprintf(stderr, "bectl %s: wrong number of arguments\n", cmd);
|
|
|
|
return (usage(false));
|
|
|
|
}
|
|
|
|
|
|
|
|
target = argv[1];
|
|
|
|
|
|
|
|
/* Locate the jail */
|
|
|
|
if ((jid = bectl_locate_jail(target)) == -1) {
|
|
|
|
fprintf(stderr, "bectl %s: failed to locate BE by '%s'\n", cmd,
|
|
|
|
target);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2018-08-16 17:56:03 +00:00
|
|
|
bzero(&path, MAXPATHLEN);
|
2018-08-06 03:32:25 +00:00
|
|
|
name = jail_getname(jid);
|
|
|
|
if (jail_getv(0, "name", name, "path", path, NULL) != jid) {
|
|
|
|
free(name);
|
|
|
|
fprintf(stderr,
|
|
|
|
"bectl %s: failed to get path for jail requested by '%s'\n",
|
|
|
|
cmd, target);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(name);
|
|
|
|
|
|
|
|
if (be_mounted_at(be, path, NULL) != 0) {
|
|
|
|
fprintf(stderr, "bectl %s: jail requested by '%s' not a BE\n",
|
|
|
|
cmd, target);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2019-03-19 17:38:54 +00:00
|
|
|
bectl_jail_cleanup(path, jid);
|
2019-01-10 03:27:20 +00:00
|
|
|
be_unmount(be, target, 0);
|
2018-08-06 03:32:25 +00:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|