2008-04-10 07:30:52 +00:00
|
|
|
/*
|
2016-04-26 14:27:08 -04:00
|
|
|
* Copyright (C) 2008-2016 Red Hat, Inc.
|
2010-03-12 10:47:26 -07:00
|
|
|
* Copyright (C) 2008 IBM Corp.
|
2015-01-14 16:15:57 +01:00
|
|
|
* Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
2018-04-02 08:55:00 +01:00
|
|
|
* lxc_container.c: Performs container setup tasks
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 16:30:55 -06:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 18:06:23 +08:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-04-10 07:30:52 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/mount.h>
|
2010-01-22 13:21:16 +00:00
|
|
|
#include <sys/stat.h>
|
2008-04-10 07:30:52 +00:00
|
|
|
#include <unistd.h>
|
2008-08-28 22:40:50 +00:00
|
|
|
#include <mntent.h>
|
2012-07-20 22:16:19 +01:00
|
|
|
#include <sys/reboot.h>
|
|
|
|
#include <linux/reboot.h>
|
2008-08-28 22:40:50 +00:00
|
|
|
/* Yes, we want linux private one, for _syscall2() macro */
|
|
|
|
#include <linux/unistd.h>
|
|
|
|
|
|
|
|
/* For MS_MOVE */
|
|
|
|
#include <linux/fs.h>
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2012-09-20 15:17:56 +01:00
|
|
|
#if WITH_CAPNG
|
2010-03-09 19:22:22 +01:00
|
|
|
# include <cap-ng.h>
|
2009-06-29 17:09:42 +00:00
|
|
|
#endif
|
2009-05-11 14:05:27 +00:00
|
|
|
|
2012-09-20 15:43:12 +01:00
|
|
|
#if WITH_BLKID
|
2017-03-03 21:12:09 +05:30
|
|
|
# include <blkid.h>
|
2011-11-01 14:59:51 +00:00
|
|
|
#endif
|
|
|
|
|
2013-05-17 10:59:25 +01:00
|
|
|
#if WITH_SELINUX
|
|
|
|
# include <selinux/selinux.h>
|
|
|
|
#endif
|
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2008-04-10 07:30:52 +00:00
|
|
|
#include "lxc_container.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2011-11-02 16:03:09 +00:00
|
|
|
#include "virnetdevveth.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2011-07-19 12:32:58 -06:00
|
|
|
#include "virfile.h"
|
2012-12-12 17:04:51 +00:00
|
|
|
#include "virusb.h"
|
2012-12-12 16:27:01 +00:00
|
|
|
#include "vircommand.h"
|
2016-06-13 17:01:27 -04:00
|
|
|
#include "virnetdevip.h"
|
2012-09-24 18:10:37 +01:00
|
|
|
#include "virprocess.h"
|
2013-04-03 12:36:23 +02:00
|
|
|
#include "virstring.h"
|
2020-02-16 22:59:28 +01:00
|
|
|
#include "virutil.h"
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_LXC
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("lxc.lxc_container");
|
|
|
|
|
2008-08-13 10:25:34 +00:00
|
|
|
|
|
|
|
/* messages between parent and container */
|
|
|
|
typedef char lxc_message_t;
|
|
|
|
#define LXC_CONTINUE_MSG 'c'
|
|
|
|
|
|
|
|
typedef struct __lxc_child_argv lxc_child_argv_t;
|
|
|
|
struct __lxc_child_argv {
|
2008-08-13 12:50:55 +00:00
|
|
|
virDomainDefPtr config;
|
2012-01-25 14:12:53 +00:00
|
|
|
virSecurityManagerPtr securityDriver;
|
2012-07-03 12:06:38 +01:00
|
|
|
size_t nveths;
|
2008-08-13 10:52:15 +00:00
|
|
|
char **veths;
|
2008-08-13 10:25:34 +00:00
|
|
|
int monitor;
|
2013-07-09 18:15:45 +01:00
|
|
|
size_t npassFDs;
|
|
|
|
int *passFDs;
|
2011-10-20 09:44:31 +01:00
|
|
|
size_t nttyPaths;
|
2013-07-09 18:15:45 +01:00
|
|
|
char **ttyPaths;
|
2011-06-02 11:52:32 -04:00
|
|
|
int handshakefd;
|
2015-08-20 19:16:17 +05:30
|
|
|
int *nsInheritFDs;
|
2008-08-13 10:25:34 +00:00
|
|
|
};
|
|
|
|
|
2013-03-22 14:09:41 +00:00
|
|
|
static int lxcContainerMountFSBlock(virDomainFSDefPtr fs,
|
2013-11-29 12:19:37 +00:00
|
|
|
const char *srcprefix,
|
|
|
|
const char *sec_mount_options);
|
2013-03-22 14:09:41 +00:00
|
|
|
|
2008-08-13 10:25:34 +00:00
|
|
|
|
2012-07-20 22:16:19 +01:00
|
|
|
/*
|
|
|
|
* reboot(LINUX_REBOOT_CMD_CAD_ON) will return -EINVAL
|
|
|
|
* in a child pid namespace if container reboot support exists.
|
|
|
|
* Otherwise, it will either succeed or return -EPERM.
|
|
|
|
*/
|
2019-10-14 14:07:39 +02:00
|
|
|
G_GNUC_NORETURN static int
|
2012-07-20 22:16:19 +01:00
|
|
|
lxcContainerRebootChild(void *argv)
|
|
|
|
{
|
|
|
|
int *cmd = argv;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = reboot(*cmd);
|
|
|
|
if (ret == -1 && errno == EINVAL)
|
|
|
|
_exit(1);
|
|
|
|
_exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
int lxcContainerHasReboot(void)
|
|
|
|
{
|
|
|
|
int flags = CLONE_NEWPID|CLONE_NEWNS|CLONE_NEWUTS|
|
|
|
|
CLONE_NEWIPC|SIGCHLD;
|
|
|
|
int cpid;
|
|
|
|
char *childStack;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *stack = NULL;
|
|
|
|
g_autofree char *buf = NULL;
|
2012-07-20 22:16:19 +01:00
|
|
|
int cmd, v;
|
|
|
|
int status;
|
|
|
|
char *tmp;
|
2013-11-25 15:06:29 +08:00
|
|
|
int stacksize = getpagesize() * 4;
|
2012-07-20 22:16:19 +01:00
|
|
|
|
|
|
|
if (virFileReadAll("/proc/sys/kernel/ctrl-alt-del", 10, &buf) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if ((tmp = strchr(buf, '\n')))
|
|
|
|
*tmp = '\0';
|
|
|
|
|
|
|
|
if (virStrToLong_i(buf, NULL, 10, &v) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Malformed ctrl-alt-del setting '%s'"), buf);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
cmd = v ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF;
|
|
|
|
|
2020-05-12 18:31:16 +01:00
|
|
|
stack = g_new0(char, stacksize);
|
2012-07-20 22:16:19 +01:00
|
|
|
|
2013-11-25 15:06:29 +08:00
|
|
|
childStack = stack + stacksize;
|
2012-07-20 22:16:19 +01:00
|
|
|
|
|
|
|
cpid = clone(lxcContainerRebootChild, childStack, flags, &cmd);
|
|
|
|
if (cpid < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to clone to check reboot support"));
|
|
|
|
return -1;
|
2014-02-19 20:23:44 -07:00
|
|
|
} else if (virProcessWait(cpid, &status, false) < 0) {
|
2012-07-20 22:16:19 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-02-19 20:23:44 -07:00
|
|
|
if (status != 1) {
|
2012-07-20 22:16:19 +01:00
|
|
|
VIR_DEBUG("Containerized reboot support is missing "
|
|
|
|
"(kernel probably too old < 3.4)");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_DEBUG("Containerized reboot support is available");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
/**
|
2011-05-06 10:50:00 -04:00
|
|
|
* lxcContainerBuildInitCmd:
|
2009-11-05 13:35:13 +01:00
|
|
|
* @vmDef: pointer to vm definition structure
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
2011-05-06 10:50:00 -04:00
|
|
|
* Build a virCommandPtr for launching the container 'init' process
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
2011-05-06 10:50:00 -04:00
|
|
|
* Returns a virCommandPtr
|
2008-04-10 07:30:52 +00:00
|
|
|
*/
|
2013-12-13 16:50:28 +00:00
|
|
|
static virCommandPtr lxcContainerBuildInitCmd(virDomainDefPtr vmDef,
|
|
|
|
char **ttyPaths,
|
|
|
|
size_t nttyPaths)
|
2008-04-10 07:30:52 +00:00
|
|
|
{
|
2011-02-22 13:09:19 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2011-05-05 17:38:09 -04:00
|
|
|
virCommandPtr cmd;
|
2020-07-02 18:23:25 -04:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2013-12-13 16:50:28 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
/* 'container_ptys' must exclude the PTY associated with
|
|
|
|
* the /dev/console device, hence start at 1 not 0
|
|
|
|
*/
|
|
|
|
for (i = 1; i < nttyPaths; i++) {
|
|
|
|
if (!STRPREFIX(ttyPaths[i], "/dev/")) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Expected a /dev path for '%s'"),
|
|
|
|
ttyPaths[i]);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
virBufferAdd(&buf, ttyPaths[i] + 5, -1);
|
|
|
|
virBufferAddChar(&buf, ' ');
|
|
|
|
}
|
2020-02-02 20:17:20 +01:00
|
|
|
virBufferTrimLen(&buf, 1);
|
2013-12-13 16:50:28 +00:00
|
|
|
|
2011-02-22 13:09:19 +00:00
|
|
|
virUUIDFormat(vmDef->uuid, uuidstr);
|
|
|
|
|
2011-05-05 17:38:09 -04:00
|
|
|
cmd = virCommandNew(vmDef->os.init);
|
|
|
|
|
2012-03-26 18:09:31 +01:00
|
|
|
if (vmDef->os.initargv && vmDef->os.initargv[0])
|
|
|
|
virCommandAddArgSet(cmd, (const char **)vmDef->os.initargv);
|
|
|
|
|
2011-05-05 17:38:09 -04:00
|
|
|
virCommandAddEnvString(cmd, "PATH=/bin:/sbin");
|
|
|
|
virCommandAddEnvString(cmd, "TERM=linux");
|
2012-01-24 11:51:01 -07:00
|
|
|
virCommandAddEnvString(cmd, "container=lxc-libvirt");
|
2014-07-25 14:39:55 +08:00
|
|
|
virCommandAddEnvString(cmd, "HOME=/");
|
2012-03-14 12:52:58 +00:00
|
|
|
virCommandAddEnvPair(cmd, "container_uuid", uuidstr);
|
2013-12-13 16:50:28 +00:00
|
|
|
if (nttyPaths > 1)
|
|
|
|
virCommandAddEnvPair(cmd, "container_ttys", virBufferCurrentContent(&buf));
|
2011-05-05 17:38:09 -04:00
|
|
|
virCommandAddEnvPair(cmd, "LIBVIRT_LXC_UUID", uuidstr);
|
|
|
|
virCommandAddEnvPair(cmd, "LIBVIRT_LXC_NAME", vmDef->name);
|
2011-10-03 18:37:47 +01:00
|
|
|
if (vmDef->os.cmdline)
|
|
|
|
virCommandAddEnvPair(cmd, "LIBVIRT_LXC_CMDLINE", vmDef->os.cmdline);
|
2017-05-31 15:32:11 +02:00
|
|
|
if (vmDef->os.initdir)
|
|
|
|
virCommandSetWorkingDirectory(cmd, vmDef->os.initdir);
|
2011-05-05 17:38:09 -04:00
|
|
|
|
2017-05-30 17:03:58 +02:00
|
|
|
for (i = 0; vmDef->os.initenv[i]; i++) {
|
|
|
|
virCommandAddEnvPair(cmd, vmDef->os.initenv[i]->name,
|
|
|
|
vmDef->os.initenv[i]->value);
|
|
|
|
}
|
|
|
|
|
2011-05-06 10:50:00 -04:00
|
|
|
return cmd;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-07-09 18:15:45 +01:00
|
|
|
* lxcContainerSetupFDs:
|
2009-11-05 13:35:13 +01:00
|
|
|
* @control: control FD from parent
|
|
|
|
* @ttyfd: FD of tty to set as the container console
|
2013-07-09 18:15:45 +01:00
|
|
|
* @npassFDs: number of extra FDs
|
|
|
|
* @passFDs: list of extra FDs
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
2013-07-09 18:15:45 +01:00
|
|
|
* Setup file descriptors in the container. @ttyfd is set to be
|
|
|
|
* the container's stdin, stdout & stderr. Any FDs included in
|
|
|
|
* @passFDs, will be dup()'d such that they start from stderr+1
|
|
|
|
* with no gaps.
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
2013-07-09 18:15:45 +01:00
|
|
|
static int lxcContainerSetupFDs(int *ttyfd,
|
|
|
|
size_t npassFDs, int *passFDs)
|
2008-04-10 07:30:52 +00:00
|
|
|
{
|
|
|
|
int rc = -1;
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 15:09:33 +01:00
|
|
|
int open_max;
|
|
|
|
int fd;
|
2013-07-09 18:15:45 +01:00
|
|
|
int last_fd;
|
|
|
|
size_t i;
|
|
|
|
size_t j;
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2015-01-16 17:20:48 +00:00
|
|
|
VIR_DEBUG("Logging from the container init will now cease "
|
|
|
|
"as the FDs are about to be closed for exec of "
|
|
|
|
"the container init process");
|
|
|
|
|
2013-07-09 18:15:45 +01:00
|
|
|
if (dup2(*ttyfd, STDIN_FILENO) < 0) {
|
2013-07-11 07:22:20 -04:00
|
|
|
virReportSystemError(errno, "%s",
|
2013-07-09 18:15:45 +01:00
|
|
|
_("dup2(stdin) failed"));
|
2013-07-11 07:22:20 -04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2013-07-09 18:15:45 +01:00
|
|
|
if (dup2(*ttyfd, STDOUT_FILENO) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno, "%s",
|
2013-07-09 18:15:45 +01:00
|
|
|
_("dup2(stdout) failed"));
|
2008-04-10 07:30:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-09 18:15:45 +01:00
|
|
|
if (dup2(*ttyfd, STDERR_FILENO) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno, "%s",
|
2013-07-09 18:15:45 +01:00
|
|
|
_("dup2(stderr) failed"));
|
2008-04-10 07:30:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-09 18:15:45 +01:00
|
|
|
VIR_FORCE_CLOSE(*ttyfd);
|
|
|
|
|
|
|
|
/* Any FDs in @passFDs need to be moved around so that
|
|
|
|
* they are numbered, without gaps, starting from
|
|
|
|
* STDERR_FILENO + 1
|
|
|
|
*/
|
|
|
|
for (i = 0; i < npassFDs; i++) {
|
|
|
|
int wantfd;
|
|
|
|
|
|
|
|
wantfd = STDERR_FILENO + i + 1;
|
|
|
|
VIR_DEBUG("Pass %d onto %d", passFDs[i], wantfd);
|
|
|
|
|
|
|
|
/* If we already have desired FD number, life
|
|
|
|
* is easy. Nothing needs renumbering */
|
|
|
|
if (passFDs[i] == wantfd)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Lets check to see if any later FDs are occupying
|
|
|
|
* our desired FD number. If so, we must move them
|
|
|
|
* out of the way
|
|
|
|
*/
|
|
|
|
for (j = i + 1; j < npassFDs; j++) {
|
|
|
|
if (passFDs[j] == wantfd) {
|
|
|
|
int newfd = dup(passFDs[j]);
|
2020-08-03 17:28:06 +02:00
|
|
|
|
|
|
|
VIR_DEBUG("Clash %zu", j);
|
|
|
|
|
2013-07-09 18:15:45 +01:00
|
|
|
if (newfd < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot move fd %d out of the way"),
|
|
|
|
passFDs[j]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* We're intentionally not closing the
|
|
|
|
* old value of passFDs[j], because we
|
|
|
|
* don't want later iterations of the
|
|
|
|
* loop to take it back. dup2() will
|
|
|
|
* cause it to be closed shortly anyway
|
|
|
|
*/
|
|
|
|
VIR_DEBUG("Moved clash onto %d", newfd);
|
|
|
|
passFDs[j] = newfd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finally we can move into our desired FD number */
|
|
|
|
if (dup2(passFDs[i], wantfd) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Cannot duplicate fd %d onto fd %d"),
|
|
|
|
passFDs[i], wantfd);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FORCE_CLOSE(passFDs[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
last_fd = STDERR_FILENO + npassFDs;
|
|
|
|
|
|
|
|
/* Just in case someone forget to set FD_CLOEXEC, explicitly
|
|
|
|
* close all remaining FDs before executing the container */
|
|
|
|
open_max = sysconf(_SC_OPEN_MAX);
|
|
|
|
if (open_max < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno, "%s",
|
2013-07-09 18:15:45 +01:00
|
|
|
_("sysconf(_SC_OPEN_MAX) failed"));
|
2008-04-10 07:30:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-07-09 18:15:45 +01:00
|
|
|
for (fd = last_fd + 1; fd < open_max; fd++) {
|
|
|
|
int tmpfd = fd;
|
|
|
|
VIR_MASS_CLOSE(tmpfd);
|
|
|
|
}
|
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
rc = 0;
|
|
|
|
|
2014-03-25 07:49:26 +01:00
|
|
|
cleanup:
|
2011-07-22 12:11:12 +01:00
|
|
|
VIR_DEBUG("rc=%d", rc);
|
2008-04-10 07:30:52 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2008-08-13 10:25:34 +00:00
|
|
|
* lxcContainerSendContinue:
|
2009-11-05 13:35:13 +01:00
|
|
|
* @control: control FD to child
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
2008-08-13 10:25:34 +00:00
|
|
|
* Sends the continue message via the socket pair stored in the vm
|
|
|
|
* structure.
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
2008-08-13 10:52:15 +00:00
|
|
|
int lxcContainerSendContinue(int control)
|
2008-04-10 07:30:52 +00:00
|
|
|
{
|
2008-08-13 10:25:34 +00:00
|
|
|
lxc_message_t msg = LXC_CONTINUE_MSG;
|
|
|
|
int writeCount = 0;
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2013-07-01 17:42:25 +01:00
|
|
|
VIR_DEBUG("Send continue on fd %d", control);
|
2008-08-13 10:25:34 +00:00
|
|
|
writeCount = safewrite(control, &msg, sizeof(msg));
|
2014-11-13 15:27:11 +01:00
|
|
|
if (writeCount != sizeof(msg))
|
2020-01-06 18:57:36 -03:00
|
|
|
return -1;
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2020-01-06 18:57:36 -03:00
|
|
|
return 0;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
|
|
|
|
2008-06-26 16:09:48 +00:00
|
|
|
/**
|
2008-08-13 10:25:34 +00:00
|
|
|
* lxcContainerWaitForContinue:
|
2009-11-05 13:35:13 +01:00
|
|
|
* @control: Control FD from parent
|
2008-06-26 16:09:48 +00:00
|
|
|
*
|
|
|
|
* This function will wait for the container continue message from the
|
|
|
|
* parent process. It will send this message on the socket pair stored in
|
|
|
|
* the vm structure once it has completed the post clone container setup.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
2011-06-01 18:17:00 -04:00
|
|
|
int lxcContainerWaitForContinue(int control)
|
2008-06-26 16:09:48 +00:00
|
|
|
{
|
|
|
|
lxc_message_t msg;
|
|
|
|
int readLen;
|
|
|
|
|
2013-07-01 17:42:25 +01:00
|
|
|
VIR_DEBUG("Wait continue on fd %d", control);
|
2008-08-13 10:25:34 +00:00
|
|
|
readLen = saferead(control, &msg, sizeof(msg));
|
2013-07-01 17:42:25 +01:00
|
|
|
VIR_DEBUG("Got continue on fd %d %d", control, readLen);
|
2011-11-01 12:28:26 +00:00
|
|
|
if (readLen != sizeof(msg)) {
|
|
|
|
if (readLen >= 0)
|
|
|
|
errno = EIO;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (msg != LXC_CONTINUE_MSG) {
|
|
|
|
errno = EINVAL;
|
2008-08-13 10:14:47 +00:00
|
|
|
return -1;
|
2008-06-26 16:09:48 +00:00
|
|
|
}
|
|
|
|
|
2008-08-13 10:14:47 +00:00
|
|
|
return 0;
|
2008-06-26 16:09:48 +00:00
|
|
|
}
|
|
|
|
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2013-06-07 15:12:21 +08:00
|
|
|
/**
|
|
|
|
* lxcContainerSetID:
|
|
|
|
*
|
|
|
|
* This function calls setuid and setgid to create proper
|
|
|
|
* cred for tasks running in container.
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
|
|
|
static int lxcContainerSetID(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
/* Only call virSetUIDGID when user namespace is enabled
|
|
|
|
* for this container. And user namespace is only enabled
|
|
|
|
* when nuidmap&ngidmap is not zero */
|
|
|
|
|
2013-10-28 11:18:26 +00:00
|
|
|
if (!def->idmap.nuidmap)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
VIR_DEBUG("Setting UID/GID to 0/0");
|
|
|
|
if (virSetUIDGID(0, 0, NULL, 0) < 0) {
|
2013-06-07 15:12:21 +08:00
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("setuid or setgid failed"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-27 10:41:22 +02:00
|
|
|
static virDomainNetDefPtr
|
|
|
|
lxcContainerGetNetDef(virDomainDefPtr vmDef, const char *devName)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
virDomainNetDefPtr netDef;
|
|
|
|
|
|
|
|
for (i = 0; i < vmDef->nnets; i++) {
|
|
|
|
netDef = vmDef->nets[i];
|
2015-01-11 13:51:29 +01:00
|
|
|
if (STREQ_NULLABLE(netDef->ifname_guest_actual, devName))
|
2014-06-27 10:41:22 +02:00
|
|
|
return netDef;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-06-26 16:09:48 +00:00
|
|
|
/**
|
2009-11-05 14:11:30 +01:00
|
|
|
* lxcContainerRenameAndEnableInterfaces:
|
2009-11-05 13:35:13 +01:00
|
|
|
* @nveths: number of interfaces
|
|
|
|
* @veths: interface names
|
2008-06-26 16:09:48 +00:00
|
|
|
*
|
2009-11-05 14:11:30 +01:00
|
|
|
* This function will rename the interfaces to ethN
|
|
|
|
* with id ascending order from zero and enable the
|
|
|
|
* renamed interfaces for this container.
|
2008-06-26 16:09:48 +00:00
|
|
|
*
|
|
|
|
* Returns 0 on success or nonzero in case of error
|
|
|
|
*/
|
2016-06-15 15:27:47 -04:00
|
|
|
static int
|
|
|
|
lxcContainerRenameAndEnableInterfaces(virDomainDefPtr vmDef,
|
|
|
|
size_t nveths,
|
|
|
|
char **veths)
|
2008-06-26 16:09:48 +00:00
|
|
|
{
|
2016-06-16 12:22:07 -04:00
|
|
|
size_t i;
|
2016-06-15 15:17:53 -04:00
|
|
|
const char *newname;
|
2014-06-27 10:41:22 +02:00
|
|
|
virDomainNetDefPtr netDef;
|
|
|
|
bool privNet = vmDef->features[VIR_DOMAIN_FEATURE_PRIVNET] ==
|
2014-06-27 17:18:53 +02:00
|
|
|
VIR_TRISTATE_SWITCH_ON;
|
2008-06-26 16:09:48 +00:00
|
|
|
|
2013-05-21 16:03:33 +08:00
|
|
|
for (i = 0; i < nveths; i++) {
|
2014-06-27 10:41:22 +02:00
|
|
|
if (!(netDef = lxcContainerGetNetDef(vmDef, veths[i])))
|
2019-10-21 15:18:55 -03:00
|
|
|
return -1;
|
2014-06-27 10:41:22 +02:00
|
|
|
|
|
|
|
newname = netDef->ifname_guest;
|
|
|
|
if (!newname) {
|
2016-06-15 15:27:47 -04:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Missing device name for container-side veth"));
|
2019-10-21 15:18:55 -03:00
|
|
|
return -1;
|
2010-07-24 02:25:56 +09:00
|
|
|
}
|
2009-11-05 14:11:30 +01:00
|
|
|
|
2011-02-16 16:37:57 -07:00
|
|
|
VIR_DEBUG("Renaming %s to %s", veths[i], newname);
|
2016-06-15 15:27:47 -04:00
|
|
|
if (virNetDevSetName(veths[i], newname) < 0)
|
2019-10-21 15:18:55 -03:00
|
|
|
return -1;
|
2014-07-22 13:35:48 +02:00
|
|
|
|
2016-06-16 12:22:07 -04:00
|
|
|
/* Only enable this device if there is a reason to do so (either
|
|
|
|
* at least one IP was specified, or link state was set to up in
|
|
|
|
* the config)
|
|
|
|
*/
|
2016-06-07 11:39:34 -04:00
|
|
|
if (netDef->guestIP.nips ||
|
2015-04-24 15:52:56 +02:00
|
|
|
netDef->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP) {
|
2014-07-25 15:24:29 +02:00
|
|
|
VIR_DEBUG("Enabling %s", newname);
|
2016-06-15 15:27:47 -04:00
|
|
|
if (virNetDevSetOnline(newname, true) < 0)
|
2019-10-21 15:18:55 -03:00
|
|
|
return -1;
|
2016-06-27 11:56:17 +02:00
|
|
|
}
|
2016-06-16 12:22:07 -04:00
|
|
|
|
|
|
|
/* set IP addresses and routes */
|
|
|
|
if (virNetDevIPInfoAddToDev(newname, &netDef->guestIP) < 0)
|
2019-10-21 15:18:55 -03:00
|
|
|
return -1;
|
2008-06-26 16:09:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* enable lo device only if there were other net devices */
|
2016-06-15 15:27:47 -04:00
|
|
|
if ((veths || privNet) &&
|
|
|
|
virNetDevSetOnline("lo", true) < 0)
|
2019-10-21 15:18:55 -03:00
|
|
|
return -1;
|
2008-06-26 16:09:48 +00:00
|
|
|
|
2019-10-21 15:18:55 -03:00
|
|
|
return 0;
|
2008-06-26 16:09:48 +00:00
|
|
|
}
|
|
|
|
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2011-01-28 22:38:06 +01:00
|
|
|
/*_syscall2(int, pivot_root, char *, newroot, const char *, oldroot)*/
|
2013-11-19 16:04:25 -07:00
|
|
|
extern int pivot_root(const char * new_root, const char * put_old);
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2013-04-08 16:10:16 +01:00
|
|
|
static int lxcContainerUnmountSubtree(const char *prefix,
|
|
|
|
bool isOldRootFS)
|
|
|
|
{
|
|
|
|
char **mounts = NULL;
|
|
|
|
size_t nmounts = 0;
|
|
|
|
size_t i;
|
|
|
|
int saveErrno;
|
|
|
|
const char *failedUmount = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
|
2018-04-15 16:30:10 +01:00
|
|
|
VIR_DEBUG("Unmount subtree from %s", prefix);
|
2013-04-08 16:10:16 +01:00
|
|
|
|
2013-11-27 15:19:49 +00:00
|
|
|
if (virFileGetMountReverseSubtree("/proc/mounts", prefix,
|
|
|
|
&mounts, &nmounts) < 0)
|
2013-04-08 16:10:16 +01:00
|
|
|
goto cleanup;
|
2013-05-21 16:03:33 +08:00
|
|
|
for (i = 0; i < nmounts; i++) {
|
2013-04-08 16:10:16 +01:00
|
|
|
VIR_DEBUG("Umount %s", mounts[i]);
|
|
|
|
if (umount(mounts[i]) < 0) {
|
|
|
|
failedUmount = mounts[i];
|
|
|
|
saveErrno = errno;
|
|
|
|
VIR_WARN("Failed to unmount '%s', trying to detach subtree '%s': %s",
|
|
|
|
failedUmount, mounts[nmounts-1],
|
2020-02-26 18:57:34 +01:00
|
|
|
g_strerror(errno));
|
2013-04-08 16:10:16 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (failedUmount) {
|
|
|
|
/* This detaches the subtree */
|
|
|
|
if (umount2(mounts[nmounts-1], MNT_DETACH) < 0) {
|
|
|
|
virReportSystemError(saveErrno,
|
|
|
|
_("Failed to unmount '%s' and could not detach subtree '%s'"),
|
|
|
|
failedUmount, mounts[nmounts-1]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* This unmounts the tmpfs on which the old root filesystem was hosted */
|
|
|
|
if (isOldRootFS &&
|
|
|
|
umount(mounts[nmounts-1]) < 0) {
|
|
|
|
virReportSystemError(saveErrno,
|
|
|
|
_("Failed to unmount '%s' and could not unmount old root '%s'"),
|
|
|
|
failedUmount, mounts[nmounts-1]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 07:49:26 +01:00
|
|
|
cleanup:
|
2020-08-02 19:36:03 +02:00
|
|
|
g_strfreev(mounts);
|
2013-04-08 16:10:16 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-21 17:45:55 +01:00
|
|
|
static int lxcContainerResolveSymlinks(virDomainFSDefPtr fs, bool gentle)
|
|
|
|
{
|
|
|
|
char *newroot;
|
|
|
|
|
2016-08-11 14:02:48 +01:00
|
|
|
if (!fs->src || !fs->src->path || fs->symlinksResolved)
|
2014-11-21 17:45:55 +01:00
|
|
|
return 0;
|
|
|
|
|
2016-07-14 16:52:38 +03:00
|
|
|
if (access(fs->src->path, F_OK)) {
|
2014-11-21 17:45:55 +01:00
|
|
|
if (gentle) {
|
|
|
|
/* Just ignore the error for the while, we'll try again later */
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("Skipped unaccessible '%s'", fs->src->path);
|
2014-11-21 17:45:55 +01:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
virReportSystemError(errno,
|
2016-07-14 16:52:38 +03:00
|
|
|
_("Failed to access '%s'"), fs->src->path);
|
2014-11-21 17:45:55 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("Resolving '%s'", fs->src->path);
|
|
|
|
if (virFileResolveAllLinks(fs->src->path, &newroot) < 0) {
|
2014-11-21 17:45:55 +01:00
|
|
|
if (gentle) {
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("Skipped non-resolvable '%s'", fs->src->path);
|
2014-11-21 17:45:55 +01:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to resolve symlink at %s"),
|
2016-07-14 16:52:38 +03:00
|
|
|
fs->src->path);
|
2014-11-21 17:45:55 +01:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mark it resolved to skip it the next time */
|
|
|
|
fs->symlinksResolved = true;
|
|
|
|
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("Resolved '%s' to %s", fs->src->path, newroot);
|
2014-11-21 17:45:55 +01:00
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
g_free(fs->src->path);
|
2016-07-14 16:52:38 +03:00
|
|
|
fs->src->path = newroot;
|
2014-11-21 17:45:55 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2013-04-08 16:10:16 +01:00
|
|
|
|
2013-03-22 14:09:41 +00:00
|
|
|
static int lxcContainerPrepareRoot(virDomainDefPtr def,
|
2013-11-29 12:19:37 +00:00
|
|
|
virDomainFSDefPtr root,
|
|
|
|
const char *sec_mount_options)
|
2013-03-22 14:09:41 +00:00
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *dst = NULL;
|
2013-03-22 14:09:41 +00:00
|
|
|
char *tmp;
|
|
|
|
|
2013-07-09 14:24:10 +01:00
|
|
|
VIR_DEBUG("Prepare root %d", root->type);
|
|
|
|
|
2013-03-22 14:09:41 +00:00
|
|
|
if (root->type == VIR_DOMAIN_FS_TYPE_MOUNT)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (root->type == VIR_DOMAIN_FS_TYPE_FILE) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Unexpected root filesystem without loop device"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (root->type != VIR_DOMAIN_FS_TYPE_BLOCK) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Unsupported root filesystem type %s"),
|
|
|
|
virDomainFSTypeToString(root->type));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-11-21 17:45:55 +01:00
|
|
|
if (lxcContainerResolveSymlinks(root, false) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
dst = g_strdup_printf("%s/%s.root", LXC_STATE_DIR, def->name);
|
2013-03-22 14:09:41 +00:00
|
|
|
|
|
|
|
tmp = root->dst;
|
|
|
|
root->dst = dst;
|
|
|
|
|
2013-11-29 12:19:37 +00:00
|
|
|
if (lxcContainerMountFSBlock(root, "", sec_mount_options) < 0) {
|
2013-03-22 14:09:41 +00:00
|
|
|
root->dst = tmp;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
root->dst = tmp;
|
|
|
|
root->type = VIR_DOMAIN_FS_TYPE_MOUNT;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_free(root->src->path);
|
|
|
|
root->src->path = g_steal_pointer(&dst);
|
2013-03-22 14:09:41 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-28 22:40:50 +00:00
|
|
|
static int lxcContainerPivotRoot(virDomainFSDefPtr root)
|
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *oldroot = NULL;
|
|
|
|
g_autofree char *newroot = NULL;
|
2009-04-16 13:08:03 +00:00
|
|
|
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("Pivot via %s", root->src->path);
|
2012-05-08 17:50:48 +01:00
|
|
|
|
2009-04-14 17:51:12 +00:00
|
|
|
/* root->parent must be private, so make / private. */
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount("", "/", "none", MS_PRIVATE|MS_REC, NULL) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno, "%s",
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Failed to make root private"));
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
}
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
oldroot = g_strdup_printf("%s/.oldroot", root->src->path);
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents(oldroot, 0777) < 0) {
|
2011-07-05 23:02:53 +02:00
|
|
|
virReportSystemError(errno,
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Failed to create %s"),
|
2009-01-20 17:13:33 +00:00
|
|
|
oldroot);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2009-04-14 17:51:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Create a tmpfs root since old and new roots must be
|
|
|
|
* on separate filesystems */
|
2009-04-22 14:26:50 +00:00
|
|
|
if (mount("tmprootfs", oldroot, "tmpfs", 0, NULL) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Failed to mount empty tmpfs at %s"),
|
2009-04-14 17:51:12 +00:00
|
|
|
oldroot);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2009-04-14 17:51:12 +00:00
|
|
|
}
|
2009-04-16 13:08:03 +00:00
|
|
|
|
2009-04-14 17:51:12 +00:00
|
|
|
/* Create a directory called 'new' in tmpfs */
|
2019-10-22 15:26:14 +02:00
|
|
|
newroot = g_strdup_printf("%s/new", oldroot);
|
2009-04-14 17:51:12 +00:00
|
|
|
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents(newroot, 0777) < 0) {
|
2011-07-05 23:02:53 +02:00
|
|
|
virReportSystemError(errno,
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Failed to create %s"),
|
2009-04-14 17:51:12 +00:00
|
|
|
newroot);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2009-04-14 17:51:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ... and mount our root onto it */
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(root->src->path, newroot, "none", MS_BIND|MS_REC, NULL) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2013-11-22 15:11:07 +08:00
|
|
|
_("Failed to bind %s to new root %s"),
|
2016-07-14 16:52:38 +03:00
|
|
|
root->src->path, newroot);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2009-04-14 17:51:12 +00:00
|
|
|
}
|
|
|
|
|
2011-07-22 13:08:20 +01:00
|
|
|
if (root->readonly) {
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(root->src->path, newroot, "none", MS_BIND|MS_REC|MS_RDONLY|MS_REMOUNT, NULL) < 0) {
|
2011-07-22 13:08:20 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to make new root %s readonly"),
|
2016-07-14 16:52:38 +03:00
|
|
|
root->src->path);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2011-07-22 13:08:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-14 08:57:55 +02:00
|
|
|
/* Now we chdir into the tmpfs, then pivot into the
|
2009-04-14 17:51:12 +00:00
|
|
|
* root->src bind-mounted onto '/new' */
|
2009-04-22 14:26:50 +00:00
|
|
|
if (chdir(newroot) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2013-06-14 08:57:55 +02:00
|
|
|
_("Failed to chdir into %s"), newroot);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The old root directory will live at /.oldroot after
|
|
|
|
* this and will soon be unmounted completely */
|
2009-04-14 17:51:12 +00:00
|
|
|
if (pivot_root(".", ".oldroot") < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno, "%s",
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Failed to pivot root"));
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* CWD is undefined after pivot_root, so go to / */
|
2009-04-14 17:51:12 +00:00
|
|
|
if (chdir("/") < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2009-04-14 17:51:12 +00:00
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2008-08-28 22:40:50 +00:00
|
|
|
}
|
|
|
|
|
2009-04-22 14:26:50 +00:00
|
|
|
|
2013-09-10 13:35:12 +01:00
|
|
|
typedef struct {
|
|
|
|
const char *src;
|
|
|
|
const char *dst;
|
|
|
|
const char *type;
|
|
|
|
int mflags;
|
2013-10-07 13:03:51 +01:00
|
|
|
bool skipUserNS;
|
2013-10-07 13:12:15 +01:00
|
|
|
bool skipUnmounted;
|
2014-12-10 10:22:28 +01:00
|
|
|
bool skipNoNetns;
|
2013-09-10 13:35:12 +01:00
|
|
|
} virLXCBasicMountInfo;
|
|
|
|
|
|
|
|
static const virLXCBasicMountInfo lxcBasicMounts[] = {
|
2014-12-10 10:22:28 +01:00
|
|
|
{ "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
|
2018-06-27 12:06:25 -03:00
|
|
|
{ "/proc/sys", "/proc/sys", "none", MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
|
|
|
|
{ "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", "none", MS_BIND, false, false, true },
|
|
|
|
{ "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", "none", MS_BIND, false, false, true },
|
2014-12-10 10:22:28 +01:00
|
|
|
{ "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
|
|
|
|
{ "securityfs", "/sys/kernel/security", "securityfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },
|
2012-09-20 13:17:58 +01:00
|
|
|
#if WITH_SELINUX
|
2014-12-10 10:22:28 +01:00
|
|
|
{ SELINUX_MOUNT, SELINUX_MOUNT, "selinuxfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true, true, false },
|
2012-03-26 16:39:30 +01:00
|
|
|
#endif
|
2013-09-10 13:35:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-02-05 15:10:02 +01:00
|
|
|
bool lxcIsBasicMountLocation(const char *path)
|
2013-09-09 16:17:19 +01:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2019-10-15 13:55:26 +02:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(lxcBasicMounts); i++) {
|
2013-09-09 16:17:19 +01:00
|
|
|
if (STREQ(path, lxcBasicMounts[i].dst))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcContainerSetReadOnly(void)
|
|
|
|
{
|
|
|
|
FILE *procmnt;
|
|
|
|
struct mntent mntent;
|
|
|
|
char mntbuf[1024];
|
|
|
|
int ret = -1;
|
|
|
|
char **mounts = NULL;
|
|
|
|
size_t nmounts = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
if (!(procmnt = setmntent("/proc/mounts", "r"))) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Failed to read /proc/mounts"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
|
2014-03-07 09:33:31 +01:00
|
|
|
char *tmp;
|
2013-09-09 16:17:19 +01:00
|
|
|
if (STREQ(mntent.mnt_dir, "/") ||
|
|
|
|
STREQ(mntent.mnt_dir, "/.oldroot") ||
|
|
|
|
STRPREFIX(mntent.mnt_dir, "/.oldroot/") ||
|
|
|
|
lxcIsBasicMountLocation(mntent.mnt_dir))
|
|
|
|
continue;
|
|
|
|
|
2019-10-20 13:49:46 +02:00
|
|
|
tmp = g_strdup(mntent.mnt_dir);
|
|
|
|
|
|
|
|
if (VIR_APPEND_ELEMENT(mounts, nmounts, tmp) < 0) {
|
2020-05-12 17:53:07 +01:00
|
|
|
g_free(tmp);
|
2013-09-09 16:17:19 +01:00
|
|
|
goto cleanup;
|
2014-03-07 09:33:31 +01:00
|
|
|
}
|
2013-09-09 16:17:19 +01:00
|
|
|
}
|
|
|
|
|
2018-11-07 18:57:02 -02:00
|
|
|
if (!mounts) {
|
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
qsort(mounts, nmounts, sizeof(mounts[0]),
|
|
|
|
virStringSortRevCompare);
|
2013-09-09 16:17:19 +01:00
|
|
|
|
|
|
|
for (i = 0; i < nmounts; i++) {
|
|
|
|
VIR_DEBUG("Bind readonly %s", mounts[i]);
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(mounts[i], mounts[i], "none", MS_BIND|MS_REC|MS_RDONLY|MS_REMOUNT, NULL) < 0) {
|
2013-09-09 16:17:19 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to make mount %s readonly"),
|
|
|
|
mounts[i]);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 07:49:26 +01:00
|
|
|
cleanup:
|
2018-11-07 18:57:02 -02:00
|
|
|
virStringListFreeCount(mounts, nmounts);
|
2013-09-09 16:17:19 +01:00
|
|
|
endmntent(procmnt);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-14 18:01:51 +08:00
|
|
|
static int lxcContainerMountBasicFS(bool userns_enabled,
|
|
|
|
bool netns_disabled)
|
2013-09-10 13:35:12 +01:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/lxc/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 15:09:33 +01:00
|
|
|
size_t i;
|
2014-07-14 18:01:51 +08:00
|
|
|
int mnt_mflags;
|
2009-04-22 14:26:50 +00:00
|
|
|
|
2013-06-07 15:12:22 +08:00
|
|
|
VIR_DEBUG("Mounting basic filesystems");
|
2011-08-04 17:16:56 +01:00
|
|
|
|
2019-10-15 13:55:26 +02:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(lxcBasicMounts); i++) {
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *mnt_src = NULL;
|
2013-10-07 12:25:00 +01:00
|
|
|
bool bindOverReadonly;
|
2013-09-10 13:35:12 +01:00
|
|
|
virLXCBasicMountInfo const *mnt = &lxcBasicMounts[i];
|
2011-08-04 17:16:56 +01:00
|
|
|
|
2014-07-14 18:01:51 +08:00
|
|
|
/* When enable userns but disable netns, kernel will
|
|
|
|
* forbid us doing a new fresh mount for sysfs.
|
|
|
|
* So we had to do a bind mount for sysfs instead.
|
|
|
|
*/
|
|
|
|
if (userns_enabled && netns_disabled &&
|
|
|
|
STREQ(mnt->src, "sysfs")) {
|
2019-10-20 13:49:46 +02:00
|
|
|
mnt_src = g_strdup("/sys");
|
2014-07-14 18:01:51 +08:00
|
|
|
mnt_mflags = MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY|MS_BIND;
|
|
|
|
} else {
|
2019-10-20 13:49:46 +02:00
|
|
|
mnt_src = g_strdup(mnt->src);
|
2014-07-14 18:01:51 +08:00
|
|
|
mnt_mflags = mnt->mflags;
|
|
|
|
}
|
|
|
|
|
2012-01-25 14:12:54 +00:00
|
|
|
VIR_DEBUG("Processing %s -> %s",
|
2014-07-14 18:01:51 +08:00
|
|
|
mnt_src, mnt->dst);
|
2011-08-04 17:16:56 +01:00
|
|
|
|
2013-10-07 13:12:15 +01:00
|
|
|
if (mnt->skipUnmounted) {
|
|
|
|
int ret;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *hostdir = g_strdup_printf("/.oldroot%s",
|
|
|
|
mnt->dst);
|
2013-10-07 13:12:15 +01:00
|
|
|
|
|
|
|
ret = virFileIsMountPoint(hostdir);
|
|
|
|
if (ret < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-10-07 13:12:15 +01:00
|
|
|
|
|
|
|
if (ret == 0) {
|
|
|
|
VIR_DEBUG("Skipping '%s' which isn't mounted in host",
|
|
|
|
mnt->dst);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2013-05-15 16:26:59 +01:00
|
|
|
|
2013-10-07 13:03:51 +01:00
|
|
|
if (mnt->skipUserNS && userns_enabled) {
|
|
|
|
VIR_DEBUG("Skipping due to user ns enablement");
|
2013-09-05 11:50:40 +01:00
|
|
|
continue;
|
2013-10-07 13:03:51 +01:00
|
|
|
}
|
2013-09-05 11:50:40 +01:00
|
|
|
|
2014-12-10 10:22:28 +01:00
|
|
|
/* Skip mounts with missing source without shouting: it may be a
|
|
|
|
* missing folder in /proc due to the absence of a kernel feature */
|
|
|
|
if (STRPREFIX(mnt_src, "/") && !virFileExists(mnt_src)) {
|
|
|
|
VIR_DEBUG("Skipping due to missing source: %s", mnt_src);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mnt->skipNoNetns && netns_disabled) {
|
|
|
|
VIR_DEBUG("Skipping due to absence of network namespace");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents(mnt->dst, 0777) < 0) {
|
2013-01-09 19:20:59 +08:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to mkdir %s"),
|
2014-12-10 10:22:28 +01:00
|
|
|
mnt->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-01-09 19:20:59 +08:00
|
|
|
}
|
|
|
|
|
2013-10-07 12:25:00 +01:00
|
|
|
/*
|
|
|
|
* We can't immediately set the MS_RDONLY flag when mounting filesystems
|
|
|
|
* because (in at least some kernel versions) this will propagate back
|
|
|
|
* to the original mount in the host OS, turning it readonly too. Thus
|
|
|
|
* we mount the filesystem in read-write mode initially, and then do a
|
|
|
|
* separate read-only bind mount on top of that.
|
|
|
|
*/
|
2014-07-14 18:01:51 +08:00
|
|
|
bindOverReadonly = !!(mnt_mflags & MS_RDONLY);
|
2013-10-07 12:25:00 +01:00
|
|
|
|
2017-09-25 11:43:33 +01:00
|
|
|
VIR_DEBUG("Mount %s on %s type=%s flags=0x%x",
|
2014-07-14 18:01:51 +08:00
|
|
|
mnt_src, mnt->dst, mnt->type, mnt_mflags & ~MS_RDONLY);
|
|
|
|
if (mount(mnt_src, mnt->dst, mnt->type, mnt_mflags & ~MS_RDONLY, NULL) < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2017-09-25 11:43:33 +01:00
|
|
|
_("Failed to mount %s on %s type %s flags=0x%x"),
|
2014-07-14 18:01:51 +08:00
|
|
|
mnt_src, mnt->dst, NULLSTR(mnt->type),
|
|
|
|
mnt_mflags & ~MS_RDONLY);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-10-07 12:25:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (bindOverReadonly &&
|
2018-06-27 12:06:25 -03:00
|
|
|
mount(mnt_src, mnt->dst, "none",
|
2015-06-16 14:44:36 +01:00
|
|
|
MS_BIND|MS_REMOUNT|mnt_mflags|MS_RDONLY, NULL) < 0) {
|
2013-10-07 12:25:00 +01:00
|
|
|
virReportSystemError(errno,
|
2017-09-25 11:43:33 +01:00
|
|
|
_("Failed to re-mount %s on %s flags=0x%x"),
|
2014-07-14 18:01:51 +08:00
|
|
|
mnt_src, mnt->dst,
|
2013-10-07 12:25:00 +01:00
|
|
|
MS_BIND|MS_REMOUNT|MS_RDONLY);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2009-04-22 14:26:50 +00:00
|
|
|
}
|
2011-07-22 13:02:05 +01:00
|
|
|
}
|
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2011-07-22 13:02:05 +01:00
|
|
|
}
|
|
|
|
|
2013-01-08 21:04:35 +00:00
|
|
|
#if WITH_FUSE
|
2013-05-15 10:49:20 +01:00
|
|
|
static int lxcContainerMountProcFuse(virDomainDefPtr def,
|
|
|
|
const char *stateDir)
|
2012-11-12 15:02:28 +08:00
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *meminfo_path = NULL;
|
2012-11-12 15:02:28 +08:00
|
|
|
|
2013-05-15 10:49:20 +01:00
|
|
|
VIR_DEBUG("Mount /proc/meminfo stateDir=%s", stateDir);
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
meminfo_path = g_strdup_printf("/.oldroot/%s/%s.fuse/meminfo",
|
|
|
|
stateDir,
|
|
|
|
def->name);
|
2012-11-12 15:02:28 +08:00
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
if (mount(meminfo_path, "/proc/meminfo",
|
|
|
|
NULL, MS_BIND, NULL) < 0) {
|
2012-11-12 15:02:28 +08:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to mount %s on /proc/meminfo"),
|
|
|
|
meminfo_path);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-11-12 15:02:28 +08:00
|
|
|
}
|
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2012-11-12 15:02:28 +08:00
|
|
|
}
|
|
|
|
#else
|
2019-10-14 14:45:33 +02:00
|
|
|
static int lxcContainerMountProcFuse(virDomainDefPtr def G_GNUC_UNUSED,
|
|
|
|
const char *stateDir G_GNUC_UNUSED)
|
2012-11-12 15:02:28 +08:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
2011-07-22 13:02:05 +01:00
|
|
|
|
2013-06-07 15:12:22 +08:00
|
|
|
static int lxcContainerMountFSDev(virDomainDefPtr def,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *path = NULL;
|
2013-11-20 10:11:08 +08:00
|
|
|
int flags = def->idmap.nuidmap ? MS_BIND : MS_MOVE;
|
2013-06-07 15:12:22 +08:00
|
|
|
|
|
|
|
VIR_DEBUG("Mount /dev/ stateDir=%s", stateDir);
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
path = g_strdup_printf("/.oldroot/%s/%s.dev", stateDir, def->name);
|
2013-06-07 15:12:22 +08:00
|
|
|
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents("/dev", 0777) < 0) {
|
2013-08-13 14:58:45 +01:00
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Cannot create /dev"));
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-08-13 14:58:45 +01:00
|
|
|
}
|
|
|
|
|
2013-11-20 10:11:08 +08:00
|
|
|
VIR_DEBUG("Trying to %s %s to /dev", def->idmap.nuidmap ?
|
|
|
|
"bind" : "move", path);
|
2013-06-07 15:12:22 +08:00
|
|
|
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(path, "/dev", "none", flags, NULL) < 0) {
|
2013-06-07 15:12:22 +08:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to mount %s on /dev"),
|
|
|
|
path);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-06-07 15:12:22 +08:00
|
|
|
}
|
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2013-06-07 15:12:22 +08:00
|
|
|
}
|
|
|
|
|
2013-05-15 10:49:20 +01:00
|
|
|
static int lxcContainerMountFSDevPTS(virDomainDefPtr def,
|
|
|
|
const char *stateDir)
|
2011-07-22 13:02:05 +01:00
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *path = NULL;
|
2013-11-20 10:11:08 +08:00
|
|
|
int flags = def->idmap.nuidmap ? MS_BIND : MS_MOVE;
|
2011-07-22 13:02:05 +01:00
|
|
|
|
2013-05-15 10:49:20 +01:00
|
|
|
VIR_DEBUG("Mount /dev/pts stateDir=%s", stateDir);
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
path = g_strdup_printf("/.oldroot/%s/%s.devpts", stateDir, def->name);
|
2009-04-22 14:26:50 +00:00
|
|
|
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents("/dev/pts", 0777) < 0) {
|
2011-07-05 23:02:53 +02:00
|
|
|
virReportSystemError(errno, "%s",
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Cannot create /dev/pts"));
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2009-01-20 17:13:33 +00:00
|
|
|
}
|
2009-04-22 14:26:50 +00:00
|
|
|
|
2013-11-20 10:11:08 +08:00
|
|
|
VIR_DEBUG("Trying to %s %s to /dev/pts", def->idmap.nuidmap ?
|
|
|
|
"bind" : "move", path);
|
2013-03-22 13:54:12 +00:00
|
|
|
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(path, "/dev/pts", "none", flags, NULL) < 0) {
|
2013-03-22 13:54:12 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to mount %s on /dev/pts"),
|
|
|
|
path);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
}
|
2009-09-04 16:12:35 +02:00
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2009-04-22 14:26:50 +00:00
|
|
|
}
|
|
|
|
|
2013-06-07 15:12:22 +08:00
|
|
|
static int lxcContainerSetupDevices(char **ttyPaths, size_t nttyPaths)
|
2009-04-22 14:26:50 +00:00
|
|
|
{
|
2011-10-20 09:44:31 +01:00
|
|
|
size_t i;
|
2012-02-08 14:21:28 +00:00
|
|
|
const struct {
|
|
|
|
const char *src;
|
|
|
|
const char *dst;
|
|
|
|
} links[] = {
|
|
|
|
{ "/proc/self/fd/0", "/dev/stdin" },
|
|
|
|
{ "/proc/self/fd/1", "/dev/stdout" },
|
|
|
|
{ "/proc/self/fd/2", "/dev/stderr" },
|
|
|
|
{ "/proc/self/fd", "/dev/fd" },
|
|
|
|
};
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2019-10-15 13:55:26 +02:00
|
|
|
for (i = 0; i < G_N_ELEMENTS(links); i++) {
|
2012-02-08 14:21:28 +00:00
|
|
|
if (symlink(links[i].src, links[i].dst) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to symlink device %s to %s"),
|
|
|
|
links[i].dst, links[i].src);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-04 14:40:57 +01:00
|
|
|
/* We have private devpts capability, so bind that */
|
2016-11-10 16:17:48 +01:00
|
|
|
if (virFileBindMountDevice("/dev/pts/ptmx", "/dev/ptmx") < 0)
|
2013-06-04 14:40:57 +01:00
|
|
|
return -1;
|
2012-01-11 09:59:37 +00:00
|
|
|
|
2013-05-21 16:03:33 +08:00
|
|
|
for (i = 0; i < nttyPaths; i++) {
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *tty = g_strdup_printf("/dev/tty%zu", i + 1);
|
2015-06-23 16:38:57 +02:00
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
if (virFileBindMountDevice(ttyPaths[i], tty) < 0)
|
2017-05-25 19:28:14 -03:00
|
|
|
return -1;
|
2015-06-23 16:38:57 +02:00
|
|
|
|
2011-10-20 09:44:31 +01:00
|
|
|
if (i == 0 &&
|
2016-11-10 16:17:48 +01:00
|
|
|
virFileBindMountDevice(ttyPaths[i], "/dev/console") < 0)
|
2011-10-20 09:44:31 +01:00
|
|
|
return -1;
|
2010-11-05 13:27:34 +00:00
|
|
|
}
|
2008-08-28 22:40:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-22 12:11:12 +01:00
|
|
|
static int lxcContainerMountFSBind(virDomainFSDefPtr fs,
|
|
|
|
const char *srcprefix)
|
2008-08-28 22:40:50 +00:00
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *src = NULL;
|
2012-06-25 10:53:39 +01:00
|
|
|
struct stat st;
|
2011-07-22 12:11:12 +01:00
|
|
|
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("src=%s dst=%s", fs->src->path, fs->dst);
|
2013-09-09 16:17:19 +01:00
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
src = g_strdup_printf("%s%s", srcprefix, fs->src->path);
|
2011-07-22 12:11:12 +01:00
|
|
|
|
2012-06-25 10:53:39 +01:00
|
|
|
if (stat(fs->dst, &st) < 0) {
|
|
|
|
if (errno != ENOENT) {
|
|
|
|
virReportSystemError(errno, _("Unable to stat bind target %s"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-06-25 10:53:39 +01:00
|
|
|
}
|
|
|
|
/* ENOENT => create the target dir or file */
|
|
|
|
if (stat(src, &st) < 0) {
|
|
|
|
virReportSystemError(errno, _("Unable to stat bind source %s"),
|
|
|
|
src);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-06-25 10:53:39 +01:00
|
|
|
}
|
|
|
|
if (S_ISDIR(st.st_mode)) {
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents(fs->dst, 0777) < 0) {
|
2012-06-25 10:53:39 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to create %s"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-06-25 10:53:39 +01:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Create Empty file for target mount point */
|
|
|
|
int fd = open(fs->dst, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666);
|
|
|
|
if (fd < 0) {
|
|
|
|
if (errno != EEXIST) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to create bind target %s"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-06-25 10:53:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (VIR_CLOSE(fd) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to close bind target %s"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-06-25 10:53:39 +01:00
|
|
|
}
|
|
|
|
}
|
2011-07-22 12:11:12 +01:00
|
|
|
}
|
|
|
|
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(src, fs->dst, "none", MS_BIND, NULL) < 0) {
|
2011-07-22 12:11:12 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to bind mount directory %s to %s"),
|
|
|
|
src, fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2011-07-22 12:11:12 +01:00
|
|
|
}
|
|
|
|
|
2011-07-22 13:08:20 +01:00
|
|
|
if (fs->readonly) {
|
|
|
|
VIR_DEBUG("Binding %s readonly", fs->dst);
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(src, fs->dst, "none", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
|
2011-07-22 13:08:20 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to make directory %s readonly"),
|
|
|
|
fs->dst);
|
2011-07-22 13:02:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2011-07-22 13:02:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-20 15:43:12 +01:00
|
|
|
#ifdef WITH_BLKID
|
2011-11-01 14:59:51 +00:00
|
|
|
static int
|
|
|
|
lxcContainerMountDetectFilesystem(const char *src, char **type)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int ret = -1;
|
|
|
|
int rc;
|
|
|
|
const char *data = NULL;
|
|
|
|
blkid_probe blkid = NULL;
|
|
|
|
|
|
|
|
*type = NULL;
|
|
|
|
|
|
|
|
if ((fd = open(src, O_RDONLY)) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to open filesystem %s"), src);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(blkid = blkid_new_probe())) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to create blkid library handle"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (blkid_probe_set_device(blkid, fd, 0, 0) < 0) {
|
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Unable to associate device %s with blkid library"),
|
|
|
|
src);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
blkid_probe_enable_superblocks(blkid, 1);
|
|
|
|
|
|
|
|
blkid_probe_set_superblocks_flags(blkid, BLKID_SUBLKS_TYPE);
|
|
|
|
|
|
|
|
rc = blkid_do_safeprobe(blkid);
|
|
|
|
if (rc != 0) {
|
|
|
|
if (rc == 1) /* Nothing found, return success with *type == NULL */
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (rc == -2) {
|
|
|
|
virReportSystemError(EINVAL,
|
|
|
|
_("Too many filesystems detected for %s"),
|
|
|
|
src);
|
|
|
|
} else {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to detect filesystem for %s"),
|
|
|
|
src);
|
|
|
|
}
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (blkid_probe_lookup_value(blkid, "TYPE", &data, NULL) < 0) {
|
|
|
|
virReportSystemError(ENOENT,
|
|
|
|
_("Unable to find filesystem type for %s"),
|
|
|
|
src);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-10-20 13:49:46 +02:00
|
|
|
*type = g_strdup(data);
|
2011-11-01 14:59:51 +00:00
|
|
|
|
2014-03-25 07:49:26 +01:00
|
|
|
done:
|
2011-11-01 14:59:51 +00:00
|
|
|
ret = 0;
|
2014-03-25 07:49:26 +01:00
|
|
|
cleanup:
|
2011-11-01 14:59:51 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
if (blkid)
|
|
|
|
blkid_free_probe(blkid);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-09-20 15:43:12 +01:00
|
|
|
#else /* ! WITH_BLKID */
|
2011-11-01 14:59:51 +00:00
|
|
|
static int
|
2019-10-14 14:45:33 +02:00
|
|
|
lxcContainerMountDetectFilesystem(const char *src G_GNUC_UNUSED,
|
2011-11-01 14:59:51 +00:00
|
|
|
char **type)
|
|
|
|
{
|
|
|
|
/* No libblkid, so just return success with no detected type */
|
|
|
|
*type = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-20 15:43:12 +01:00
|
|
|
#endif /* ! WITH_BLKID */
|
2011-07-22 13:02:51 +01:00
|
|
|
|
|
|
|
/*
|
2013-09-06 12:14:00 +01:00
|
|
|
* This function attempts to do automatic detection of filesystem
|
2011-07-22 13:02:51 +01:00
|
|
|
* type following the same rules as the util-linux 'mount' binary.
|
|
|
|
*
|
|
|
|
* The main difference is that we don't (currently) try to use
|
|
|
|
* libblkid to detect the format first. We go straight to using
|
|
|
|
* /etc/filesystems, and then /proc/filesystems
|
|
|
|
*/
|
|
|
|
static int lxcContainerMountFSBlockAuto(virDomainFSDefPtr fs,
|
|
|
|
int fsflags,
|
2013-08-13 13:25:56 +01:00
|
|
|
const char *src,
|
2013-11-29 12:19:37 +00:00
|
|
|
const char *srcprefix,
|
|
|
|
const char *sec_mount_options)
|
2011-07-22 13:02:51 +01:00
|
|
|
{
|
|
|
|
FILE *fp = NULL;
|
|
|
|
int ret = -1;
|
|
|
|
bool tryProc = false;
|
|
|
|
bool gotStar = false;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *fslist = NULL;
|
2011-07-22 13:02:51 +01:00
|
|
|
const char *type;
|
|
|
|
|
2013-08-13 13:25:56 +01:00
|
|
|
VIR_DEBUG("src=%s dst=%s srcprefix=%s", src, fs->dst, srcprefix);
|
2011-07-22 13:02:51 +01:00
|
|
|
|
|
|
|
/* First time around we use /etc/filesystems */
|
2014-03-25 07:49:26 +01:00
|
|
|
retry:
|
2020-05-12 17:53:07 +01:00
|
|
|
g_free(fslist);
|
2019-10-22 15:26:14 +02:00
|
|
|
fslist = g_strdup_printf("%s%s", srcprefix,
|
|
|
|
tryProc ? "/proc/filesystems" : "/etc/filesystems");
|
2011-07-22 13:02:51 +01:00
|
|
|
|
|
|
|
VIR_DEBUG("Open fslist %s", fslist);
|
|
|
|
if (!(fp = fopen(fslist, "r"))) {
|
|
|
|
/* If /etc/filesystems does not exist, then we need to retry
|
|
|
|
* with /proc/filesystems next
|
|
|
|
*/
|
|
|
|
if (errno == ENOENT &&
|
|
|
|
!tryProc) {
|
|
|
|
tryProc = true;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Unable to read %s"),
|
|
|
|
fslist);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!feof(fp)) {
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *line = NULL;
|
2011-07-22 13:02:51 +01:00
|
|
|
size_t n;
|
|
|
|
if (getline(&line, &n, fp) <= 0) {
|
|
|
|
if (feof(fp))
|
|
|
|
break;
|
|
|
|
|
2011-07-22 13:08:20 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-07-22 13:02:51 +01:00
|
|
|
if (strstr(line, "nodev"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
type = strchr(line, '\n');
|
|
|
|
if (type)
|
|
|
|
line[type-line] = '\0';
|
|
|
|
|
|
|
|
type = line;
|
|
|
|
virSkipSpaces(&type);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* /etc/filesystems is only allowed to contain '*' on the last line
|
|
|
|
*/
|
2011-11-01 12:29:25 +00:00
|
|
|
if (gotStar && !tryProc) {
|
2012-07-13 13:59:51 +01:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("%s has unexpected '*' before last line"),
|
|
|
|
fslist);
|
2011-07-22 13:02:51 +01:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* An '*' on the last line in /etc/filesystems
|
|
|
|
* means try /proc/filesystems next. We don't
|
|
|
|
* jump immediately though, since we need to see
|
|
|
|
* if any more lines follow
|
|
|
|
*/
|
|
|
|
if (!tryProc &&
|
|
|
|
STREQ(type, "*"))
|
|
|
|
gotStar = true;
|
|
|
|
|
2013-11-29 12:19:37 +00:00
|
|
|
VIR_DEBUG("Trying mount '%s' on '%s' with '%s' opts '%s'",
|
|
|
|
src, fs->dst, type, sec_mount_options);
|
|
|
|
if (mount(src, fs->dst, type, fsflags, sec_mount_options) < 0) {
|
2011-07-22 13:02:51 +01:00
|
|
|
/* These errnos indicate a bogus filesystem type for
|
|
|
|
* the image we have, so skip to the next type
|
|
|
|
*/
|
|
|
|
if (errno == EINVAL || errno == ENODEV)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
virReportSystemError(errno,
|
2011-11-01 14:34:02 +00:00
|
|
|
_("Failed to mount device %s to %s"),
|
2011-07-22 13:02:51 +01:00
|
|
|
src, fs->dst);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
break;
|
2011-07-22 13:08:20 +01:00
|
|
|
}
|
|
|
|
|
2011-07-22 13:02:51 +01:00
|
|
|
/* We've got to the end of /etc/filesystems and saw
|
|
|
|
* a '*', so we must try /proc/filesystems next
|
|
|
|
*/
|
|
|
|
if (ret != 0 &&
|
|
|
|
!tryProc &&
|
|
|
|
gotStar) {
|
|
|
|
tryProc = true;
|
|
|
|
VIR_FORCE_FCLOSE(fp);
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
2011-11-01 14:34:02 +00:00
|
|
|
if (ret != 0) {
|
|
|
|
virReportSystemError(ENODEV,
|
|
|
|
_("Failed to mount device %s to %s, unable to detect filesystem"),
|
|
|
|
src, fs->dst);
|
|
|
|
}
|
|
|
|
|
2011-07-22 13:02:51 +01:00
|
|
|
VIR_DEBUG("Done mounting filesystem ret=%d tryProc=%d", ret, tryProc);
|
|
|
|
|
2014-03-25 07:49:26 +01:00
|
|
|
cleanup:
|
2011-07-22 13:02:51 +01:00
|
|
|
VIR_FORCE_FCLOSE(fp);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mount a block device 'src' on fs->dst, automatically
|
|
|
|
* probing for filesystem type
|
|
|
|
*/
|
|
|
|
static int lxcContainerMountFSBlockHelper(virDomainFSDefPtr fs,
|
2013-08-13 13:25:56 +01:00
|
|
|
const char *src,
|
2013-11-29 12:19:37 +00:00
|
|
|
const char *srcprefix,
|
|
|
|
const char *sec_mount_options)
|
2011-07-22 13:02:51 +01:00
|
|
|
{
|
|
|
|
int fsflags = 0;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *format = NULL;
|
2011-11-01 14:59:51 +00:00
|
|
|
|
2011-07-22 13:02:51 +01:00
|
|
|
if (fs->readonly)
|
|
|
|
fsflags |= MS_RDONLY;
|
|
|
|
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents(fs->dst, 0777) < 0) {
|
2011-07-22 13:02:51 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to create %s"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2011-07-22 13:02:51 +01:00
|
|
|
}
|
|
|
|
|
2011-11-01 14:59:51 +00:00
|
|
|
if (lxcContainerMountDetectFilesystem(src, &format) < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2011-11-01 14:59:51 +00:00
|
|
|
|
|
|
|
if (format) {
|
2013-11-29 12:19:37 +00:00
|
|
|
VIR_DEBUG("Mount '%s' on '%s' with detected format '%s' opts '%s'",
|
|
|
|
src, fs->dst, format, sec_mount_options);
|
|
|
|
if (mount(src, fs->dst, format, fsflags, sec_mount_options) < 0) {
|
2011-11-01 14:59:51 +00:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to mount device %s to %s as %s"),
|
|
|
|
src, fs->dst, format);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2011-11-01 14:59:51 +00:00
|
|
|
}
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2011-11-01 14:59:51 +00:00
|
|
|
} else {
|
2020-05-12 17:53:07 +01:00
|
|
|
return lxcContainerMountFSBlockAuto(fs, fsflags, src, srcprefix, sec_mount_options);
|
2011-11-01 14:59:51 +00:00
|
|
|
}
|
2011-07-22 13:02:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcContainerMountFSBlock(virDomainFSDefPtr fs,
|
2013-11-29 12:19:37 +00:00
|
|
|
const char *srcprefix,
|
|
|
|
const char *sec_mount_options)
|
2011-07-22 13:02:51 +01:00
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *src = NULL;
|
2011-07-22 13:02:51 +01:00
|
|
|
int ret = -1;
|
|
|
|
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("src=%s dst=%s", fs->src->path, fs->dst);
|
2013-09-09 16:17:19 +01:00
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
src = g_strdup_printf("%s%s", srcprefix, fs->src->path);
|
2011-07-22 13:02:51 +01:00
|
|
|
|
2013-11-29 12:19:37 +00:00
|
|
|
ret = lxcContainerMountFSBlockHelper(fs, src, srcprefix, sec_mount_options);
|
2011-07-22 12:11:12 +01:00
|
|
|
|
|
|
|
VIR_DEBUG("Done mounting filesystem ret=%d", ret);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-18 19:44:47 +01:00
|
|
|
static int lxcContainerMountFSTmpfs(virDomainFSDefPtr fs,
|
|
|
|
char *sec_mount_options)
|
2012-05-08 17:50:48 +01:00
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *data = NULL;
|
2012-05-08 17:50:48 +01:00
|
|
|
|
2013-09-09 16:17:19 +01:00
|
|
|
VIR_DEBUG("usage=%lld sec=%s", fs->usage, sec_mount_options);
|
|
|
|
|
2019-10-22 15:26:14 +02:00
|
|
|
data = g_strdup_printf("size=%lld%s", fs->usage, sec_mount_options);
|
2012-05-08 17:50:48 +01:00
|
|
|
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents(fs->dst, 0777) < 0) {
|
2012-05-08 17:50:48 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to create %s"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-05-08 17:50:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mount("tmpfs", fs->dst, "tmpfs", MS_NOSUID|MS_NODEV, data) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to mount directory %s as tmpfs"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-05-08 17:50:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fs->readonly) {
|
|
|
|
VIR_DEBUG("Binding %s readonly", fs->dst);
|
2018-06-27 12:06:25 -03:00
|
|
|
if (mount(fs->dst, fs->dst, "none", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
|
2012-05-08 17:50:48 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to make directory %s readonly"),
|
|
|
|
fs->dst);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2012-05-08 17:50:48 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2012-05-08 17:50:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-22 12:11:12 +01:00
|
|
|
static int lxcContainerMountFS(virDomainFSDefPtr fs,
|
2012-07-18 19:44:47 +01:00
|
|
|
char *sec_mount_options)
|
2011-07-22 12:11:12 +01:00
|
|
|
{
|
|
|
|
switch (fs->type) {
|
|
|
|
case VIR_DOMAIN_FS_TYPE_MOUNT:
|
2013-05-15 10:53:14 +01:00
|
|
|
if (lxcContainerMountFSBind(fs, "/.oldroot") < 0)
|
2011-07-22 12:11:12 +01:00
|
|
|
return -1;
|
|
|
|
break;
|
2011-07-22 13:02:51 +01:00
|
|
|
case VIR_DOMAIN_FS_TYPE_BLOCK:
|
2013-11-29 12:19:37 +00:00
|
|
|
if (lxcContainerMountFSBlock(fs, "/.oldroot", sec_mount_options) < 0)
|
2011-07-22 13:02:51 +01:00
|
|
|
return -1;
|
|
|
|
break;
|
2012-05-08 17:50:48 +01:00
|
|
|
case VIR_DOMAIN_FS_TYPE_RAM:
|
2012-07-18 19:44:47 +01:00
|
|
|
if (lxcContainerMountFSTmpfs(fs, sec_mount_options) < 0)
|
2012-05-08 17:50:48 +01:00
|
|
|
return -1;
|
|
|
|
break;
|
2012-06-20 15:03:30 +01:00
|
|
|
case VIR_DOMAIN_FS_TYPE_BIND:
|
|
|
|
if (lxcContainerMountFSBind(fs, "") < 0)
|
|
|
|
return -1;
|
|
|
|
break;
|
2011-08-04 10:13:02 +01:00
|
|
|
case VIR_DOMAIN_FS_TYPE_FILE:
|
2012-06-20 15:03:30 +01:00
|
|
|
/* We do actually support this, but the lxc controller
|
|
|
|
* should have associated the file with a loopback
|
|
|
|
* device and changed this to TYPE_BLOCK for us */
|
2012-07-13 13:59:51 +01:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unexpected filesystem type %s"),
|
|
|
|
virDomainFSTypeToString(fs->type));
|
2013-07-09 14:24:10 +01:00
|
|
|
return -1;
|
2011-07-22 12:11:12 +01:00
|
|
|
default:
|
2012-07-13 13:59:51 +01:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("Cannot mount filesystem type %s"),
|
|
|
|
virDomainFSTypeToString(fs->type));
|
2013-07-09 14:24:10 +01:00
|
|
|
return -1;
|
2011-07-22 12:11:12 +01:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int lxcContainerMountAllFS(virDomainDefPtr vmDef,
|
2012-07-18 19:44:47 +01:00
|
|
|
char *sec_mount_options)
|
2011-07-22 12:11:12 +01:00
|
|
|
{
|
|
|
|
size_t i;
|
2013-05-15 10:53:15 +01:00
|
|
|
VIR_DEBUG("Mounting all non-root filesystems");
|
2008-08-28 22:40:50 +00:00
|
|
|
|
|
|
|
/* Pull in rest of container's mounts */
|
2013-05-21 16:03:33 +08:00
|
|
|
for (i = 0; i < vmDef->nfss; i++) {
|
2013-05-15 10:53:15 +01:00
|
|
|
if (STREQ(vmDef->fss[i]->dst, "/"))
|
2008-08-28 22:40:50 +00:00
|
|
|
continue;
|
|
|
|
|
2016-07-14 16:52:38 +03:00
|
|
|
VIR_DEBUG("Mounting '%s' -> '%s'", vmDef->fss[i]->src->path, vmDef->fss[i]->dst);
|
2014-11-24 15:10:19 +01:00
|
|
|
|
2014-11-21 17:45:55 +01:00
|
|
|
if (lxcContainerResolveSymlinks(vmDef->fss[i], false) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2016-08-11 14:02:48 +01:00
|
|
|
if (!(vmDef->fss[i]->src && vmDef->fss[i]->src->path &&
|
2016-07-14 16:52:38 +03:00
|
|
|
STRPREFIX(vmDef->fss[i]->src->path, vmDef->fss[i]->dst)) &&
|
2014-11-24 15:10:19 +01:00
|
|
|
lxcContainerUnmountSubtree(vmDef->fss[i]->dst, false) < 0)
|
2013-04-08 16:10:16 +01:00
|
|
|
return -1;
|
|
|
|
|
2013-05-15 10:53:14 +01:00
|
|
|
if (lxcContainerMountFS(vmDef->fss[i], sec_mount_options) < 0)
|
2008-08-28 22:40:50 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-05-15 10:53:15 +01:00
|
|
|
VIR_DEBUG("Mounted all non-root filesystems");
|
2008-08-28 22:40:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-09 11:15:11 +01:00
|
|
|
int lxcContainerSetupHostdevCapsMakePath(const char *dev)
|
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *dir = NULL;
|
|
|
|
char *tmp;
|
2013-07-09 11:15:11 +01:00
|
|
|
|
2019-10-20 13:49:46 +02:00
|
|
|
dir = g_strdup(dev);
|
2013-07-09 11:15:11 +01:00
|
|
|
|
|
|
|
if ((tmp = strrchr(dir, '/'))) {
|
|
|
|
*tmp = '\0';
|
2021-02-26 09:37:10 +01:00
|
|
|
if (g_mkdir_with_parents(dir, 0777) < 0) {
|
2013-07-09 11:15:11 +01:00
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to create directory for '%s' dev '%s'"),
|
|
|
|
dir, dev);
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-07-09 11:15:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2013-07-09 11:15:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-11 16:07:54 +08:00
|
|
|
static int lxcContainerUnmountForSharedRoot(const char *stateDir,
|
|
|
|
const char *domain)
|
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *tmp = NULL;
|
2013-09-11 16:07:54 +08:00
|
|
|
|
|
|
|
#if WITH_SELINUX
|
|
|
|
/* Some versions of Linux kernel don't let you overmount
|
|
|
|
* the selinux filesystem, so make sure we kill it first
|
|
|
|
*/
|
|
|
|
if (lxcContainerUnmountSubtree(SELINUX_MOUNT, false) < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-09-11 16:07:54 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* These filesystems are created by libvirt temporarily, they
|
|
|
|
* shouldn't appear in container. */
|
2019-10-22 15:26:14 +02:00
|
|
|
tmp = g_strdup_printf("%s/%s.dev", stateDir, domain);
|
|
|
|
|
|
|
|
if (lxcContainerUnmountSubtree(tmp, false) < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-09-11 16:07:54 +08:00
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
g_free(tmp);
|
2019-10-22 15:26:14 +02:00
|
|
|
tmp = g_strdup_printf("%s/%s.devpts", stateDir, domain);
|
|
|
|
|
|
|
|
if (lxcContainerUnmountSubtree(tmp, false) < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-09-11 16:07:54 +08:00
|
|
|
|
|
|
|
#if WITH_FUSE
|
2020-05-12 17:53:07 +01:00
|
|
|
g_free(tmp);
|
2019-10-22 15:26:14 +02:00
|
|
|
tmp = g_strdup_printf("%s/%s.fuse", stateDir, domain);
|
|
|
|
|
|
|
|
if (lxcContainerUnmountSubtree(tmp, false) < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-09-11 16:07:54 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* If we have the root source being '/', then we need to
|
|
|
|
* get rid of any existing stuff under /proc, /sys & /tmp.
|
|
|
|
* We need new namespace aware versions of those. We must
|
|
|
|
* do /proc last otherwise we won't find /proc/mounts :-) */
|
|
|
|
if (lxcContainerUnmountSubtree("/sys", false) < 0 ||
|
|
|
|
lxcContainerUnmountSubtree("/dev", false) < 0 ||
|
|
|
|
lxcContainerUnmountSubtree("/proc", false) < 0)
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2013-09-11 16:07:54 +08:00
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2013-09-11 16:07:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-12-10 10:22:28 +01:00
|
|
|
static bool
|
|
|
|
lxcNeedNetworkNamespace(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
if (def->nets != NULL)
|
|
|
|
return true;
|
|
|
|
if (def->features[VIR_DOMAIN_FEATURE_PRIVNET] == VIR_TRISTATE_SWITCH_ON)
|
|
|
|
return true;
|
|
|
|
for (i = 0; i < def->nhostdevs; i++) {
|
|
|
|
if (def->hostdevs[i]->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES &&
|
|
|
|
def->hostdevs[i]->source.caps.type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-28 22:40:50 +00:00
|
|
|
/* Got a FS mapped to /, we're going the pivot_root
|
|
|
|
* approach to do a better-chroot-than-chroot
|
2020-08-26 00:44:00 +02:00
|
|
|
* this is based on this thread https://lkml.org/lkml/2008/3/5/29
|
2008-08-28 22:40:50 +00:00
|
|
|
*/
|
|
|
|
static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
|
2011-10-20 09:44:31 +01:00
|
|
|
virDomainFSDefPtr root,
|
|
|
|
char **ttyPaths,
|
2012-05-11 11:02:50 +01:00
|
|
|
size_t nttyPaths,
|
2012-11-22 14:23:49 +00:00
|
|
|
virSecurityManagerPtr securityDriver)
|
2008-08-28 22:40:50 +00:00
|
|
|
{
|
2020-09-22 12:49:58 +02:00
|
|
|
g_autoptr(virCgroup) cgroup = NULL;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *sec_mount_options = NULL;
|
|
|
|
g_autofree char *stateDir = NULL;
|
2012-11-22 14:23:49 +00:00
|
|
|
|
2013-07-12 11:04:55 +01:00
|
|
|
VIR_DEBUG("Setup pivot root");
|
|
|
|
|
2012-11-22 14:23:49 +00:00
|
|
|
if (!(sec_mount_options = virSecurityManagerGetMountOptions(securityDriver, vmDef)))
|
|
|
|
return -1;
|
2012-05-11 17:26:48 +01:00
|
|
|
|
|
|
|
/* Before pivoting we need to identify any
|
|
|
|
* cgroups controllers that are mounted */
|
2013-07-04 16:49:24 +01:00
|
|
|
if (virCgroupNewSelf(&cgroup) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2012-05-11 17:26:48 +01:00
|
|
|
|
2013-05-15 10:49:20 +01:00
|
|
|
if (virFileResolveAllLinks(LXC_STATE_DIR, &stateDir) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2013-05-15 10:49:20 +01:00
|
|
|
|
2013-03-22 14:09:41 +00:00
|
|
|
/* Ensure the root filesystem is mounted */
|
2013-11-29 12:19:37 +00:00
|
|
|
if (lxcContainerPrepareRoot(vmDef, root, sec_mount_options) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2013-03-22 14:09:41 +00:00
|
|
|
|
2009-04-22 14:26:50 +00:00
|
|
|
/* Gives us a private root, leaving all parent OS mounts on /.oldroot */
|
2008-08-28 22:40:50 +00:00
|
|
|
if (lxcContainerPivotRoot(root) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2013-11-20 10:11:09 +08:00
|
|
|
/* FIXME: we should find a way to unmount these mounts for container
|
|
|
|
* even user namespace is enabled. */
|
2016-07-14 16:52:38 +03:00
|
|
|
if (STREQ(root->src->path, "/") && (!vmDef->idmap.nuidmap) &&
|
2013-09-11 16:07:54 +08:00
|
|
|
lxcContainerUnmountForSharedRoot(stateDir, vmDef->name) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2012-06-12 16:26:37 -04:00
|
|
|
|
2011-07-22 13:02:05 +01:00
|
|
|
/* Mounts the core /proc, /sys, etc filesystems */
|
2014-07-14 18:01:51 +08:00
|
|
|
if (lxcContainerMountBasicFS(vmDef->idmap.nuidmap,
|
2014-12-10 10:22:28 +01:00
|
|
|
!lxcNeedNetworkNamespace(vmDef)) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2012-05-11 17:26:48 +01:00
|
|
|
|
2013-09-09 16:17:19 +01:00
|
|
|
/* Ensure entire root filesystem (except /.oldroot) is readonly */
|
|
|
|
if (root->readonly &&
|
|
|
|
lxcContainerSetReadOnly() < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2013-09-09 16:17:19 +01:00
|
|
|
|
2012-11-12 15:02:28 +08:00
|
|
|
/* Mounts /proc/meminfo etc sysinfo */
|
2013-05-15 10:49:20 +01:00
|
|
|
if (lxcContainerMountProcFuse(vmDef, stateDir) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2012-11-12 15:02:28 +08:00
|
|
|
|
2012-05-11 17:26:48 +01:00
|
|
|
/* Now we can re-mount the cgroups controllers in the
|
|
|
|
* same configuration as before */
|
2016-01-22 16:07:18 +00:00
|
|
|
if (virCgroupBindMount(cgroup, "/.oldroot/", sec_mount_options) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2011-07-22 13:02:05 +01:00
|
|
|
|
2013-06-07 15:12:22 +08:00
|
|
|
/* Mounts /dev */
|
|
|
|
if (lxcContainerMountFSDev(vmDef, stateDir) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2013-06-07 15:12:22 +08:00
|
|
|
|
2012-01-25 14:12:54 +00:00
|
|
|
/* Mounts /dev/pts */
|
2013-05-15 10:49:20 +01:00
|
|
|
if (lxcContainerMountFSDevPTS(vmDef, stateDir) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2013-06-07 15:12:22 +08:00
|
|
|
/* Setup device nodes in /dev/ */
|
|
|
|
if (lxcContainerSetupDevices(ttyPaths, nttyPaths) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2009-04-22 14:26:50 +00:00
|
|
|
/* Sets up any non-root mounts from guest config */
|
2013-05-15 10:53:15 +01:00
|
|
|
if (lxcContainerMountAllFS(vmDef, sec_mount_options) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2008-08-28 22:40:50 +00:00
|
|
|
|
2012-11-23 14:46:18 +00:00
|
|
|
/* Gets rid of all remaining mounts from host OS, including /.oldroot itself */
|
2012-05-11 11:35:28 +01:00
|
|
|
if (lxcContainerUnmountSubtree("/.oldroot", true) < 0)
|
2020-09-22 12:49:58 +02:00
|
|
|
return -1;
|
2012-05-11 17:26:48 +01:00
|
|
|
|
2020-09-22 12:49:58 +02:00
|
|
|
return 0;
|
2008-08-28 22:40:50 +00:00
|
|
|
}
|
|
|
|
|
2014-11-21 17:45:55 +01:00
|
|
|
static int lxcContainerResolveAllSymlinks(virDomainDefPtr vmDef)
|
2012-01-17 21:33:02 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
|
2013-07-12 11:04:55 +01:00
|
|
|
VIR_DEBUG("Resolving symlinks");
|
|
|
|
|
2013-05-21 16:03:33 +08:00
|
|
|
for (i = 0; i < vmDef->nfss; i++) {
|
2012-01-17 21:33:02 +00:00
|
|
|
virDomainFSDefPtr fs = vmDef->fss[i];
|
2014-11-21 17:45:55 +01:00
|
|
|
/* In the first pass, be gentle as some files may
|
|
|
|
depend on other filesystems to be mounted */
|
|
|
|
if (lxcContainerResolveSymlinks(fs, true) < 0)
|
2013-09-23 11:22:17 +01:00
|
|
|
return -1;
|
2012-01-17 21:33:02 +00:00
|
|
|
}
|
2013-07-09 14:24:10 +01:00
|
|
|
VIR_DEBUG("Resolved all filesystem symlinks");
|
2012-01-17 21:33:02 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-06-29 17:09:42 +00:00
|
|
|
/*
|
2013-09-06 12:14:00 +01:00
|
|
|
* This is running as the 'init' process inside the container.
|
2009-06-29 17:09:42 +00:00
|
|
|
* It removes some capabilities that could be dangerous to
|
|
|
|
* host system, since they are not currently "containerized"
|
|
|
|
*/
|
2012-09-20 15:17:56 +01:00
|
|
|
#if WITH_CAPNG
|
2014-07-18 10:02:29 +02:00
|
|
|
|
|
|
|
static int lxcContainerDropCapabilities(virDomainDefPtr def,
|
|
|
|
bool keepReboot)
|
2013-07-11 14:05:20 +08:00
|
|
|
{
|
2009-06-29 17:09:42 +00:00
|
|
|
int ret;
|
2014-07-18 10:02:29 +02:00
|
|
|
size_t i;
|
|
|
|
int policy = def->features[VIR_DOMAIN_FEATURE_CAPABILITIES];
|
|
|
|
|
2019-10-25 14:50:15 +02:00
|
|
|
/* Maps virDomainProcessCapsFeature to CAPS_* */
|
2014-07-23 10:19:20 +02:00
|
|
|
static int capsMapping[] = {CAP_AUDIT_CONTROL,
|
|
|
|
CAP_AUDIT_WRITE,
|
|
|
|
CAP_BLOCK_SUSPEND,
|
|
|
|
CAP_CHOWN,
|
|
|
|
CAP_DAC_OVERRIDE,
|
|
|
|
CAP_DAC_READ_SEARCH,
|
|
|
|
CAP_FOWNER,
|
|
|
|
CAP_FSETID,
|
|
|
|
CAP_IPC_LOCK,
|
|
|
|
CAP_IPC_OWNER,
|
|
|
|
CAP_KILL,
|
|
|
|
CAP_LEASE,
|
|
|
|
CAP_LINUX_IMMUTABLE,
|
|
|
|
CAP_MAC_ADMIN,
|
|
|
|
CAP_MAC_OVERRIDE,
|
|
|
|
CAP_MKNOD,
|
|
|
|
CAP_NET_ADMIN,
|
|
|
|
CAP_NET_BIND_SERVICE,
|
|
|
|
CAP_NET_BROADCAST,
|
|
|
|
CAP_NET_RAW,
|
|
|
|
CAP_SETGID,
|
|
|
|
CAP_SETFCAP,
|
|
|
|
CAP_SETPCAP,
|
|
|
|
CAP_SETUID,
|
|
|
|
CAP_SYS_ADMIN,
|
|
|
|
CAP_SYS_BOOT,
|
|
|
|
CAP_SYS_CHROOT,
|
|
|
|
CAP_SYS_MODULE,
|
|
|
|
CAP_SYS_NICE,
|
|
|
|
CAP_SYS_PACCT,
|
|
|
|
CAP_SYS_PTRACE,
|
|
|
|
CAP_SYS_RAWIO,
|
|
|
|
CAP_SYS_RESOURCE,
|
|
|
|
CAP_SYS_TIME,
|
|
|
|
CAP_SYS_TTY_CONFIG,
|
|
|
|
CAP_SYSLOG,
|
|
|
|
CAP_WAKE_ALARM};
|
2009-06-29 17:09:42 +00:00
|
|
|
|
|
|
|
capng_get_caps_process();
|
|
|
|
|
2014-07-18 10:02:29 +02:00
|
|
|
/* Make sure we drop everything if required by the user */
|
|
|
|
if (policy == VIR_DOMAIN_CAPABILITIES_POLICY_DENY)
|
|
|
|
capng_clear(CAPNG_SELECT_BOTH);
|
|
|
|
|
|
|
|
/* Apply all single capabilities changes */
|
2019-10-25 14:50:15 +02:00
|
|
|
for (i = 0; i < VIR_DOMAIN_PROCES_CAPS_FEATURE_LAST; i++) {
|
2014-07-18 10:02:29 +02:00
|
|
|
bool toDrop = false;
|
|
|
|
int state = def->caps_features[i];
|
|
|
|
|
|
|
|
if (!cap_valid(capsMapping[i]))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch ((virDomainCapabilitiesPolicy) policy) {
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CAPABILITIES_POLICY_DENY:
|
2014-06-27 17:18:53 +02:00
|
|
|
if (state == VIR_TRISTATE_SWITCH_ON &&
|
2014-07-18 10:02:29 +02:00
|
|
|
(ret = capng_update(CAPNG_ADD,
|
|
|
|
CAPNG_EFFECTIVE | CAPNG_PERMITTED |
|
|
|
|
CAPNG_INHERITABLE | CAPNG_BOUNDING_SET,
|
|
|
|
capsMapping[i])) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to add capability %s: %d"),
|
2019-10-25 14:50:15 +02:00
|
|
|
virDomainProcessCapsFeatureTypeToString(i), ret);
|
2014-07-18 10:02:29 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_DOMAIN_CAPABILITIES_POLICY_DEFAULT:
|
2018-02-14 09:43:59 +00:00
|
|
|
switch (i) {
|
2019-10-25 14:50:15 +02:00
|
|
|
case VIR_DOMAIN_PROCES_CAPS_FEATURE_SYS_BOOT: /* No use of reboot */
|
2014-06-27 17:18:53 +02:00
|
|
|
toDrop = !keepReboot && (state != VIR_TRISTATE_SWITCH_ON);
|
2014-07-18 10:02:29 +02:00
|
|
|
break;
|
2019-10-25 14:50:15 +02:00
|
|
|
case VIR_DOMAIN_PROCES_CAPS_FEATURE_SYS_MODULE: /* No kernel module loading */
|
|
|
|
case VIR_DOMAIN_PROCES_CAPS_FEATURE_SYS_TIME: /* No changing the clock */
|
|
|
|
case VIR_DOMAIN_PROCES_CAPS_FEATURE_MKNOD: /* No creating device nodes */
|
|
|
|
case VIR_DOMAIN_PROCES_CAPS_FEATURE_AUDIT_CONTROL: /* No messing with auditing status */
|
|
|
|
case VIR_DOMAIN_PROCES_CAPS_FEATURE_MAC_ADMIN: /* No messing with LSM config */
|
2014-06-27 17:18:53 +02:00
|
|
|
toDrop = (state != VIR_TRISTATE_SWITCH_ON);
|
2014-07-18 10:02:29 +02:00
|
|
|
break;
|
|
|
|
default: /* User specified capabilities to drop */
|
2014-06-27 17:18:53 +02:00
|
|
|
toDrop = (state == VIR_TRISTATE_SWITCH_OFF);
|
2014-07-18 10:02:29 +02:00
|
|
|
}
|
2019-10-15 13:38:21 +02:00
|
|
|
G_GNUC_FALLTHROUGH;
|
2014-07-18 10:02:29 +02:00
|
|
|
|
|
|
|
case VIR_DOMAIN_CAPABILITIES_POLICY_ALLOW:
|
|
|
|
if (policy == VIR_DOMAIN_CAPABILITIES_POLICY_ALLOW)
|
2014-06-27 17:18:53 +02:00
|
|
|
toDrop = state == VIR_TRISTATE_SWITCH_OFF;
|
2014-07-18 10:02:29 +02:00
|
|
|
|
|
|
|
if (toDrop && (ret = capng_update(CAPNG_DROP,
|
|
|
|
CAPNG_EFFECTIVE | CAPNG_PERMITTED |
|
|
|
|
CAPNG_INHERITABLE | CAPNG_BOUNDING_SET,
|
|
|
|
capsMapping[i])) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to remove capability %s: %d"),
|
2019-10-25 14:50:15 +02:00
|
|
|
virDomainProcessCapsFeatureTypeToString(i), ret);
|
2014-07-18 10:02:29 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
case VIR_DOMAIN_CAPABILITIES_POLICY_LAST:
|
2014-07-18 10:02:29 +02:00
|
|
|
default:
|
2018-02-14 09:43:59 +00:00
|
|
|
virReportEnumRangeError(virDomainCapabilitiesPolicy, policy);
|
|
|
|
return -1;
|
2014-07-18 10:02:29 +02:00
|
|
|
}
|
2009-06-29 17:09:42 +00:00
|
|
|
}
|
2009-05-11 14:05:27 +00:00
|
|
|
|
2009-06-29 17:09:42 +00:00
|
|
|
if ((ret = capng_apply(CAPNG_SELECT_BOTH)) < 0) {
|
2012-07-13 13:59:51 +01:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Failed to apply capabilities: %d"), ret);
|
2009-06-29 17:09:42 +00:00
|
|
|
return -1;
|
2009-05-11 14:05:27 +00:00
|
|
|
}
|
2009-06-29 17:09:42 +00:00
|
|
|
|
2009-11-12 11:03:23 +00:00
|
|
|
/* We do not need to call capng_lock() in this case. The bounding
|
|
|
|
* set restriction will prevent them reacquiring sys_boot/module/time,
|
|
|
|
* etc which is all that matters for the container. Once inside the
|
|
|
|
* container it is fine for SECURE_NOROOT / SECURE_NO_SETUID_FIXUP to
|
|
|
|
* be unmasked - they can never escape the bounding set. */
|
2009-06-29 17:09:42 +00:00
|
|
|
|
2013-07-11 14:05:20 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2009-06-29 17:09:42 +00:00
|
|
|
#else
|
2019-10-14 14:45:33 +02:00
|
|
|
static int lxcContainerDropCapabilities(virDomainDefPtr def G_GNUC_UNUSED,
|
|
|
|
bool keepReboot G_GNUC_UNUSED)
|
2013-07-11 14:05:20 +08:00
|
|
|
{
|
2011-05-09 17:24:09 +08:00
|
|
|
VIR_WARN("libcap-ng support not compiled in, unable to clear capabilities");
|
2009-05-11 14:05:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-07-11 14:05:20 +08:00
|
|
|
#endif
|
2009-05-11 14:05:27 +00:00
|
|
|
|
|
|
|
|
2015-08-20 19:16:17 +05:30
|
|
|
/**
|
|
|
|
* lxcAttach_ns:
|
|
|
|
* @ns_fd: array of namespaces to attach
|
|
|
|
*/
|
|
|
|
static int lxcAttachNS(int *ns_fd)
|
|
|
|
{
|
2015-08-27 02:59:29 +02:00
|
|
|
if (ns_fd &&
|
2015-09-01 07:08:47 -04:00
|
|
|
virProcessSetNamespaces((size_t)VIR_LXC_DOMAIN_NAMESPACE_LAST,
|
|
|
|
ns_fd) < 0)
|
2015-08-27 02:59:29 +02:00
|
|
|
return -1;
|
2015-08-20 19:16:17 +05:30
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-06-06 10:54:16 +02:00
|
|
|
/**
|
|
|
|
* lxcContainerSetUserGroup:
|
|
|
|
* @cmd: command to update
|
|
|
|
* @vmDef: domain definition for the container
|
|
|
|
* @ttyPath: guest path to the tty
|
|
|
|
*
|
|
|
|
* Set the command UID and GID. As this function attempts at
|
|
|
|
* converting the user/group name into uid/gid, it needs to
|
|
|
|
* be called after the pivot root is done.
|
|
|
|
*
|
|
|
|
* The owner of the tty is also changed to the given user.
|
|
|
|
*/
|
|
|
|
static int lxcContainerSetUserGroup(virCommandPtr cmd,
|
|
|
|
virDomainDefPtr vmDef,
|
|
|
|
const char *ttyPath)
|
|
|
|
{
|
|
|
|
uid_t uid;
|
|
|
|
gid_t gid;
|
|
|
|
|
|
|
|
if (vmDef->os.inituser) {
|
|
|
|
if (virGetUserID(vmDef->os.inituser, &uid) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, _("User %s doesn't exist"),
|
|
|
|
vmDef->os.inituser);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virCommandSetUID(cmd, uid);
|
|
|
|
|
|
|
|
/* Change the newly created tty owner to the inituid for
|
|
|
|
* shells to have job control. */
|
|
|
|
if (chown(ttyPath, uid, -1) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to change ownership of tty %s"),
|
|
|
|
ttyPath);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vmDef->os.initgroup) {
|
|
|
|
if (virGetGroupID(vmDef->os.initgroup, &gid) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, _("Group %s doesn't exist"),
|
|
|
|
vmDef->os.initgroup);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
virCommandSetGID(cmd, gid);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-12-18 15:48:33 +01:00
|
|
|
static const char hostname_validchars[] =
|
|
|
|
"abcdefghijklmnopqrstuvwxyz"
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
"0123456789-";
|
|
|
|
|
|
|
|
static int lxcContainerSetHostname(virDomainDefPtr def)
|
|
|
|
{
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *name = NULL;
|
|
|
|
const char *hostname = NULL;
|
2017-12-18 15:48:33 +01:00
|
|
|
|
|
|
|
/* Filter the VM name to get a valid hostname */
|
2019-10-20 13:49:46 +02:00
|
|
|
name = g_strdup(def->name);
|
2017-12-18 15:48:33 +01:00
|
|
|
|
|
|
|
/* RFC 1123 allows 0-9 digits as a first character in hostname */
|
|
|
|
virStringFilterChars(name, hostname_validchars);
|
|
|
|
hostname = name;
|
|
|
|
if (strlen(name) > 0 && name[0] == '-')
|
|
|
|
hostname = name + 1;
|
|
|
|
|
|
|
|
if (sethostname(hostname, strlen(hostname)) < 0) {
|
|
|
|
virReportSystemError(errno, "%s", _("Failed to set hostname"));
|
2020-05-12 17:53:07 +01:00
|
|
|
return -1;
|
2017-12-18 15:48:33 +01:00
|
|
|
}
|
|
|
|
|
2020-05-12 17:53:07 +01:00
|
|
|
return 0;
|
2017-12-18 15:48:33 +01:00
|
|
|
}
|
2015-08-20 19:16:17 +05:30
|
|
|
|
2008-04-10 07:30:52 +00:00
|
|
|
/**
|
2009-11-05 13:35:13 +01:00
|
|
|
* lxcContainerChild:
|
|
|
|
* @data: pointer to container arguments
|
2008-04-10 07:30:52 +00:00
|
|
|
*
|
|
|
|
* This function is run in the process clone()'d in lxcStartContainer.
|
|
|
|
* Perform a number of container setup tasks:
|
|
|
|
* Setup container file system
|
2017-10-09 21:14:57 +02:00
|
|
|
* mount container /proc
|
2008-04-10 07:30:52 +00:00
|
|
|
* Then exec's the container init
|
|
|
|
*
|
|
|
|
* Returns 0 on success or -1 in case of error
|
|
|
|
*/
|
2012-10-17 10:23:12 +01:00
|
|
|
static int lxcContainerChild(void *data)
|
2008-04-10 07:30:52 +00:00
|
|
|
{
|
2008-08-13 10:14:47 +00:00
|
|
|
lxc_child_argv_t *argv = data;
|
2008-08-13 12:50:55 +00:00
|
|
|
virDomainDefPtr vmDef = argv->config;
|
2011-06-02 11:01:36 -04:00
|
|
|
int ttyfd = -1;
|
2011-05-06 10:50:00 -04:00
|
|
|
int ret = -1;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *ttyPath = NULL;
|
2009-04-22 14:26:50 +00:00
|
|
|
virDomainFSDefPtr root;
|
2011-05-06 10:50:00 -04:00
|
|
|
virCommandPtr cmd = NULL;
|
2012-07-20 22:16:19 +01:00
|
|
|
int hasReboot;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree gid_t *groups = NULL;
|
2017-10-09 21:14:56 +02:00
|
|
|
int ngroups;
|
2008-04-10 07:30:52 +00:00
|
|
|
|
|
|
|
if (NULL == vmDef) {
|
2012-07-13 13:59:51 +01:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"%s", _("lxcChild() passed invalid vm definition"));
|
2011-05-06 10:50:00 -04:00
|
|
|
goto cleanup;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
|
|
|
|
2015-08-20 19:16:17 +05:30
|
|
|
if (lxcAttachNS(argv->nsInheritFDs) < 0) {
|
|
|
|
virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
|
|
|
|
_("failed to attach the namespace"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-06-07 15:12:21 +08:00
|
|
|
/* Wait for controller to finish setup tasks, including
|
|
|
|
* things like move of network interfaces, uid/gid mapping
|
|
|
|
*/
|
|
|
|
if (lxcContainerWaitForContinue(argv->monitor) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Failed to read the container continue message"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Received container continue message");
|
|
|
|
|
2012-07-20 22:16:19 +01:00
|
|
|
if ((hasReboot = lxcContainerHasReboot()) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-12-13 16:50:28 +00:00
|
|
|
cmd = lxcContainerBuildInitCmd(vmDef,
|
|
|
|
argv->ttyPaths,
|
|
|
|
argv->nttyPaths);
|
2011-05-06 10:50:00 -04:00
|
|
|
virCommandWriteArgLog(cmd, 1);
|
|
|
|
|
2013-06-07 15:12:21 +08:00
|
|
|
if (lxcContainerSetID(vmDef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-11-12 11:57:56 +00:00
|
|
|
root = virDomainGetFilesystemForTarget(vmDef, "/");
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2011-10-20 09:44:31 +01:00
|
|
|
if (argv->nttyPaths) {
|
2013-05-20 18:12:17 +08:00
|
|
|
const char *tty = argv->ttyPaths[0];
|
|
|
|
if (STRPREFIX(tty, "/dev/pts/"))
|
|
|
|
tty += strlen("/dev/pts/");
|
2019-10-22 15:26:14 +02:00
|
|
|
ttyPath = g_strdup_printf("%s/%s.devpts/%s", LXC_STATE_DIR, vmDef->name,
|
|
|
|
tty);
|
2014-10-31 09:51:23 +01:00
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("At least one tty is required"));
|
|
|
|
goto cleanup;
|
2009-04-22 14:26:50 +00:00
|
|
|
}
|
2011-10-20 09:44:31 +01:00
|
|
|
|
2011-05-06 10:50:00 -04:00
|
|
|
VIR_DEBUG("Container TTY path: %s", ttyPath);
|
2009-04-22 14:26:50 +00:00
|
|
|
|
2015-06-23 15:18:53 +02:00
|
|
|
ttyfd = open(ttyPath, O_RDWR);
|
2008-08-28 22:40:50 +00:00
|
|
|
if (ttyfd < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno,
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Failed to open tty %s"),
|
2009-04-22 14:26:50 +00:00
|
|
|
ttyPath);
|
2011-05-06 10:50:00 -04:00
|
|
|
goto cleanup;
|
2008-04-10 07:30:52 +00:00
|
|
|
}
|
2008-08-13 10:25:34 +00:00
|
|
|
|
2014-11-21 17:45:55 +01:00
|
|
|
if (lxcContainerResolveAllSymlinks(vmDef) < 0)
|
2013-04-03 16:19:24 +01:00
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-09 14:24:10 +01:00
|
|
|
VIR_DEBUG("Setting up pivot");
|
2013-04-03 16:19:24 +01:00
|
|
|
if (lxcContainerSetupPivotRoot(vmDef, root,
|
|
|
|
argv->ttyPaths, argv->nttyPaths,
|
|
|
|
argv->securityDriver) < 0)
|
2011-05-06 10:50:00 -04:00
|
|
|
goto cleanup;
|
2009-04-22 14:26:50 +00:00
|
|
|
|
2011-06-02 15:25:21 -04:00
|
|
|
if (!virFileExists(vmDef->os.init)) {
|
|
|
|
virReportSystemError(errno,
|
2017-10-09 21:14:58 +02:00
|
|
|
_("cannot find init path '%s' relative to container root"),
|
|
|
|
vmDef->os.init);
|
2011-06-02 15:25:21 -04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-06-06 10:54:16 +02:00
|
|
|
if (lxcContainerSetUserGroup(cmd, vmDef, argv->ttyPaths[0]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-11-05 14:11:30 +01:00
|
|
|
/* rename and enable interfaces */
|
2014-06-27 10:41:22 +02:00
|
|
|
if (lxcContainerRenameAndEnableInterfaces(vmDef,
|
2012-01-18 11:38:49 +00:00
|
|
|
argv->nveths,
|
2011-06-02 11:01:36 -04:00
|
|
|
argv->veths) < 0) {
|
2011-05-06 10:50:00 -04:00
|
|
|
goto cleanup;
|
2011-06-02 11:01:36 -04:00
|
|
|
}
|
2008-06-26 16:09:48 +00:00
|
|
|
|
2017-12-18 15:48:33 +01:00
|
|
|
if (lxcContainerSetHostname(vmDef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
2009-05-11 14:05:27 +00:00
|
|
|
/* drop a set of root capabilities */
|
2014-07-18 10:02:29 +02:00
|
|
|
if (lxcContainerDropCapabilities(vmDef, !!hasReboot) < 0)
|
2011-05-06 10:50:00 -04:00
|
|
|
goto cleanup;
|
2009-05-11 14:05:27 +00:00
|
|
|
|
2011-06-02 11:52:32 -04:00
|
|
|
if (lxcContainerSendContinue(argv->handshakefd) < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
2017-10-09 21:14:58 +02:00
|
|
|
_("Failed to send continue signal to controller"));
|
2011-06-02 11:52:32 -04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-01-25 14:12:53 +00:00
|
|
|
VIR_DEBUG("Setting up security labeling");
|
|
|
|
if (virSecurityManagerSetProcessLabel(argv->securityDriver, vmDef) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-01-16 17:20:48 +00:00
|
|
|
VIR_DEBUG("Setting up inherited FDs");
|
2013-07-09 18:15:45 +01:00
|
|
|
VIR_FORCE_CLOSE(argv->handshakefd);
|
|
|
|
VIR_FORCE_CLOSE(argv->monitor);
|
|
|
|
if (lxcContainerSetupFDs(&ttyfd,
|
|
|
|
argv->npassFDs, argv->passFDs) < 0)
|
2012-05-01 10:48:52 +01:00
|
|
|
goto cleanup;
|
|
|
|
|
2016-07-21 15:37:24 +00:00
|
|
|
/* Make init process of the container the leader of the new session.
|
|
|
|
* That is needed when checkpointing container.
|
|
|
|
*/
|
|
|
|
if (setsid() < 0) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
_("Unable to become session leader"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-10-09 21:14:56 +02:00
|
|
|
/* TODO is it safe to call it here or should this call be moved in
|
|
|
|
* front of the clone() as otherwise there might be a risk for a
|
|
|
|
* deadlock */
|
|
|
|
if ((ngroups = virGetGroupList(virCommandGetUID(cmd), virCommandGetGID(cmd),
|
|
|
|
&groups)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2011-06-02 11:01:36 -04:00
|
|
|
ret = 0;
|
2014-03-25 07:49:26 +01:00
|
|
|
cleanup:
|
2011-06-02 11:01:36 -04:00
|
|
|
VIR_FORCE_CLOSE(ttyfd);
|
2011-06-02 11:18:14 -04:00
|
|
|
VIR_FORCE_CLOSE(argv->monitor);
|
2011-06-02 11:52:32 -04:00
|
|
|
VIR_FORCE_CLOSE(argv->handshakefd);
|
2011-06-02 11:01:36 -04:00
|
|
|
|
|
|
|
if (ret == 0) {
|
2015-01-16 17:20:48 +00:00
|
|
|
VIR_DEBUG("Executing init binary");
|
2011-10-10 14:02:06 -06:00
|
|
|
/* this function will only return if an error occurred */
|
2017-10-09 21:14:56 +02:00
|
|
|
ret = virCommandExec(cmd, groups, ngroups);
|
2011-06-02 11:01:36 -04:00
|
|
|
}
|
2013-10-14 13:04:50 +01:00
|
|
|
|
|
|
|
if (ret != 0) {
|
2015-01-16 17:20:48 +00:00
|
|
|
VIR_DEBUG("Tearing down container");
|
2016-05-19 21:10:19 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
_("Failure in libvirt_lxc startup: %s\n"),
|
|
|
|
virGetLastErrorMessage());
|
2013-10-14 13:04:50 +01:00
|
|
|
}
|
2011-06-02 11:01:36 -04:00
|
|
|
|
2011-05-06 10:50:00 -04:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
2008-08-13 10:25:34 +00:00
|
|
|
}
|
2008-04-10 07:30:52 +00:00
|
|
|
|
2013-06-07 15:12:19 +08:00
|
|
|
static int userns_required(virDomainDefPtr def)
|
|
|
|
{
|
|
|
|
return def->idmap.uidmap && def->idmap.gidmap;
|
2009-04-20 12:27:12 +00:00
|
|
|
}
|
|
|
|
|
2012-12-10 22:28:09 +00:00
|
|
|
virArch lxcContainerGetAlt32bitArch(virArch arch)
|
2011-02-23 17:17:53 +00:00
|
|
|
{
|
|
|
|
/* Any Linux 64bit arch which has a 32bit
|
|
|
|
* personality available should be listed here */
|
2012-12-10 22:28:09 +00:00
|
|
|
if (arch == VIR_ARCH_X86_64)
|
|
|
|
return VIR_ARCH_I686;
|
|
|
|
if (arch == VIR_ARCH_S390X)
|
|
|
|
return VIR_ARCH_S390;
|
|
|
|
if (arch == VIR_ARCH_PPC64)
|
|
|
|
return VIR_ARCH_PPC;
|
|
|
|
if (arch == VIR_ARCH_PARISC64)
|
|
|
|
return VIR_ARCH_PARISC;
|
|
|
|
if (arch == VIR_ARCH_SPARC64)
|
|
|
|
return VIR_ARCH_SPARC;
|
|
|
|
if (arch == VIR_ARCH_MIPS64)
|
|
|
|
return VIR_ARCH_MIPS;
|
|
|
|
if (arch == VIR_ARCH_MIPS64EL)
|
|
|
|
return VIR_ARCH_MIPSEL;
|
2017-02-24 17:11:52 +03:00
|
|
|
if (arch == VIR_ARCH_AARCH64)
|
|
|
|
return VIR_ARCH_ARMV7L;
|
2012-12-10 22:28:09 +00:00
|
|
|
|
|
|
|
return VIR_ARCH_NONE;
|
2011-02-23 17:17:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-08-13 10:25:34 +00:00
|
|
|
/**
|
|
|
|
* lxcContainerStart:
|
2009-11-05 13:35:13 +01:00
|
|
|
* @def: pointer to virtual machine structure
|
|
|
|
* @nveths: number of interfaces
|
|
|
|
* @veths: interface names
|
|
|
|
* @control: control FD to the container
|
|
|
|
* @ttyPath: path of tty to set as the container console
|
2008-08-13 10:25:34 +00:00
|
|
|
*
|
|
|
|
* Starts a container process by calling clone() with the namespace flags
|
|
|
|
*
|
|
|
|
* Returns PID of container on success or -1 in case of error
|
|
|
|
*/
|
2008-08-13 12:50:55 +00:00
|
|
|
int lxcContainerStart(virDomainDefPtr def,
|
2012-01-25 14:12:53 +00:00
|
|
|
virSecurityManagerPtr securityDriver,
|
2012-07-03 12:06:38 +01:00
|
|
|
size_t nveths,
|
2008-08-13 10:52:15 +00:00
|
|
|
char **veths,
|
2013-07-09 18:15:45 +01:00
|
|
|
size_t npassFDs,
|
|
|
|
int *passFDs,
|
2008-08-13 10:25:34 +00:00
|
|
|
int control,
|
2011-06-02 11:52:32 -04:00
|
|
|
int handshakefd,
|
2015-08-20 19:16:17 +05:30
|
|
|
int *nsInheritFDs,
|
2013-07-09 18:15:45 +01:00
|
|
|
size_t nttyPaths,
|
|
|
|
char **ttyPaths)
|
2008-08-13 10:25:34 +00:00
|
|
|
{
|
|
|
|
pid_t pid;
|
2011-07-06 16:33:53 -06:00
|
|
|
int cflags;
|
2008-08-13 10:25:34 +00:00
|
|
|
int stacksize = getpagesize() * 4;
|
2020-05-12 17:53:07 +01:00
|
|
|
g_autofree char *stack = NULL;
|
|
|
|
char *stacktop;
|
2013-07-09 18:15:45 +01:00
|
|
|
lxc_child_argv_t args = {
|
|
|
|
.config = def,
|
|
|
|
.securityDriver = securityDriver,
|
|
|
|
.nveths = nveths,
|
|
|
|
.veths = veths,
|
|
|
|
.npassFDs = npassFDs,
|
|
|
|
.passFDs = passFDs,
|
|
|
|
.monitor = control,
|
|
|
|
.nttyPaths = nttyPaths,
|
|
|
|
.ttyPaths = ttyPaths,
|
2015-08-20 19:16:17 +05:30
|
|
|
.handshakefd = handshakefd,
|
|
|
|
.nsInheritFDs = nsInheritFDs,
|
2013-07-09 18:15:45 +01:00
|
|
|
};
|
2008-08-13 10:25:34 +00:00
|
|
|
|
|
|
|
/* allocate a stack for the container */
|
2020-05-12 18:31:16 +01:00
|
|
|
stack = g_new0(char, stacksize);
|
2013-11-25 15:06:29 +08:00
|
|
|
|
2008-08-13 10:25:34 +00:00
|
|
|
stacktop = stack + stacksize;
|
|
|
|
|
2015-08-20 19:16:17 +05:30
|
|
|
cflags = CLONE_NEWPID|CLONE_NEWNS|SIGCHLD;
|
2009-04-20 12:27:12 +00:00
|
|
|
|
2013-06-07 15:12:19 +08:00
|
|
|
if (userns_required(def)) {
|
2017-01-11 10:45:44 +01:00
|
|
|
if (virProcessNamespaceAvailable(VIR_PROCESS_NAMESPACE_USER) < 0) {
|
2014-11-28 09:37:42 +01:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("Kernel doesn't support user namespace"));
|
2013-06-07 15:12:19 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2017-01-11 10:45:44 +01:00
|
|
|
VIR_DEBUG("Enable user namespace");
|
|
|
|
cflags |= CLONE_NEWUSER;
|
2010-03-04 11:23:28 +00:00
|
|
|
}
|
2015-08-20 19:16:17 +05:30
|
|
|
if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHARENET] == -1) {
|
|
|
|
if (lxcNeedNetworkNamespace(def)) {
|
|
|
|
VIR_DEBUG("Enable network namespaces");
|
|
|
|
cflags |= CLONE_NEWNET;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (lxcNeedNetworkNamespace(def)) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
2016-03-07 15:24:51 +02:00
|
|
|
_("Config asks for inherit net namespace "
|
2015-08-20 19:16:17 +05:30
|
|
|
"as well as private network interfaces"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
VIR_DEBUG("Inheriting a net namespace");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHAREIPC] == -1) {
|
|
|
|
cflags |= CLONE_NEWIPC;
|
|
|
|
} else {
|
|
|
|
VIR_DEBUG("Inheriting an IPC namespace");
|
|
|
|
}
|
2008-08-13 10:25:34 +00:00
|
|
|
|
2015-08-20 19:16:17 +05:30
|
|
|
if (!nsInheritFDs || nsInheritFDs[VIR_LXC_DOMAIN_NAMESPACE_SHAREUTS] == -1) {
|
|
|
|
cflags |= CLONE_NEWUTS;
|
|
|
|
} else {
|
|
|
|
VIR_DEBUG("Inheriting a UTS namespace");
|
2010-03-04 11:23:28 +00:00
|
|
|
}
|
2008-08-13 10:25:34 +00:00
|
|
|
|
2015-01-16 17:20:48 +00:00
|
|
|
VIR_DEBUG("Cloning container init process");
|
2011-07-06 16:33:53 -06:00
|
|
|
pid = clone(lxcContainerChild, stacktop, cflags, &args);
|
2011-02-16 16:37:57 -07:00
|
|
|
VIR_DEBUG("clone() completed, new container PID is %d", pid);
|
2008-08-13 10:25:34 +00:00
|
|
|
|
|
|
|
if (pid < 0) {
|
2010-02-04 21:02:58 +01:00
|
|
|
virReportSystemError(errno, "%s",
|
2009-11-05 13:39:09 +01:00
|
|
|
_("Failed to run clone container"));
|
2008-08-13 10:25:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return pid;
|
|
|
|
}
|
|
|
|
|
2013-07-16 10:00:02 +08:00
|
|
|
int lxcContainerChown(virDomainDefPtr def, const char *path)
|
|
|
|
{
|
|
|
|
uid_t uid;
|
|
|
|
gid_t gid;
|
|
|
|
|
|
|
|
if (!def->idmap.uidmap)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uid = def->idmap.uidmap[0].target;
|
|
|
|
gid = def->idmap.gidmap[0].target;
|
|
|
|
|
|
|
|
if (chown(path, uid, gid) < 0) {
|
|
|
|
virReportSystemError(errno,
|
|
|
|
_("Failed to change owner of %s to %u:%u"),
|
|
|
|
path, uid, gid);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|