#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
-#include <alloca.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include "lxcseccomp.h"
#include "macro.h"
#include "mainloop.h"
+#include "memory_utils.h"
#include "monitor.h"
#include "namespace.h"
#include "network.h"
static void print_top_failing_dir(const char *path)
{
+ __do_free char *copy;
int ret;
- size_t len;
- char *copy, *e, *p, saved;
-
- len = strlen(path);
- copy = alloca(len + 1);
- (void)strlcpy(copy, path, len + 1);
+ char *e, *p, saved;
+ copy = must_copy_string(path);
p = copy;
- e = copy + len;
+ e = copy + strlen(path);
while (p < e) {
while (p < e && *p == '/')
fd = lxc_try_preserve_ns(pid, ns_info[i].proc_name);
if (fd < 0) {
- handler->nsfd[i] = -EBADF;
-
/* Do not fail to start container on kernels that do
* not support interacting with namespaces through
* /proc.
return (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO);
}
+#ifdef HAVE_DLOG
+static bool match_dlog_fds(struct dirent *direntp)
+{
+ char path[PATH_MAX] = {0};
+ char link[PATH_MAX] = {0};
+ ssize_t linklen;
+ int ret;
+
+ ret = snprintf(path, PATH_MAX, "/proc/self/fd/%s", direntp->d_name);
+ if (ret < 0 || ret >= PATH_MAX) {
+ ERROR("Failed to create file descriptor name");
+ return false;
+ }
+
+ linklen = readlink(path, link, PATH_MAX);
+ if (linklen < 0) {
+ SYSERROR("Failed to read link path - \"%s\"", path);
+ return false;
+ } else if (linklen >= PATH_MAX) {
+ ERROR("The name of link path is too long - \"%s\"", path);
+ return false;
+ }
+
+ if (strcmp(link, "/dev/log_main") == 0 ||
+ strcmp(link, "/dev/log_system") == 0 ||
+ strcmp(link, "/dev/log_radio") == 0)
+ return true;
+
+ return false;
+}
+#endif
+
int lxc_check_inherited(struct lxc_conf *conf, bool closeall,
int *fds_to_ignore, size_t len_fds)
{
if (match_stdfds(fd))
continue;
+#ifdef HAVE_DLOG
+ if (match_dlog_fds(direntp))
+ continue;
+
+#endif
if (closeall) {
close(fd);
closedir(dir);
static int setup_signal_fd(sigset_t *oldmask)
{
int ret;
- int sig;
sigset_t mask;
const int signals[] = {SIGBUS, SIGILL, SIGSEGV, SIGWINCH};
if (ret < 0)
return -EBADF;
- for (sig = 0; sig < (sizeof(signals) / sizeof(signals[0])); sig++) {
+ for (int sig = 0; sig < (sizeof(signals) / sizeof(signals[0])); sig++) {
ret = sigdelset(&mask, signals[sig]);
if (ret < 0)
return -EBADF;
if (siginfo.ssi_signo == SIGHUP) {
kill(hdlr->pid, SIGTERM);
INFO("Killing %d since terminal hung up", hdlr->pid);
- return hdlr->init_died ? LXC_MAINLOOP_CLOSE : LXC_MAINLOOP_CONTINUE;
+ return hdlr->init_died ? LXC_MAINLOOP_CLOSE
+ : LXC_MAINLOOP_CONTINUE;
}
if (siginfo.ssi_signo != SIGCHLD) {
kill(hdlr->pid, siginfo.ssi_signo);
INFO("Forwarded signal %d to pid %d", siginfo.ssi_signo, hdlr->pid);
- return hdlr->init_died ? LXC_MAINLOOP_CLOSE : LXC_MAINLOOP_CONTINUE;
+ return hdlr->init_died ? LXC_MAINLOOP_CLOSE
+ : LXC_MAINLOOP_CONTINUE;
}
/* More robustness, protect ourself from a SIGCHLD sent
if (siginfo.ssi_pid != hdlr->pid) {
NOTICE("Received %d from pid %d instead of container init %d",
siginfo.ssi_signo, siginfo.ssi_pid, hdlr->pid);
- return hdlr->init_died ? LXC_MAINLOOP_CLOSE : LXC_MAINLOOP_CONTINUE;
+ return hdlr->init_died ? LXC_MAINLOOP_CLOSE
+ : LXC_MAINLOOP_CONTINUE;
}
if (siginfo.ssi_code == CLD_STOPPED) {
INFO("Container init process was stopped");
- return hdlr->init_died ? LXC_MAINLOOP_CLOSE : LXC_MAINLOOP_CONTINUE;
- } else if (siginfo.ssi_code == CLD_CONTINUED) {
+ return hdlr->init_died ? LXC_MAINLOOP_CLOSE
+ : LXC_MAINLOOP_CONTINUE;
+ }
+
+ if (siginfo.ssi_code == CLD_CONTINUED) {
INFO("Container init process was continued");
- return hdlr->init_died ? LXC_MAINLOOP_CLOSE : LXC_MAINLOOP_CONTINUE;
+ return hdlr->init_died ? LXC_MAINLOOP_CLOSE
+ : LXC_MAINLOOP_CONTINUE;
}
DEBUG("Container init process %d exited", hdlr->pid);
+
return LXC_MAINLOOP_CLOSE;
}
if (handler->state_socket_pair[1] >= 0)
close(handler->state_socket_pair[1]);
+ if (handler->cgroup_ops)
+ cgroup_exit(handler->cgroup_ops);
+
handler->conf = NULL;
free(handler);
handler = NULL;
cgroup_ops->payload_destroy(cgroup_ops, handler);
cgroup_ops->monitor_destroy(cgroup_ops, handler);
- cgroup_exit(cgroup_ops);
if (handler->conf->reboot == REBOOT_NONE) {
/* For all new state clients simply close the command socket.
if (handler->ns_clone_flags & CLONE_NEWCGROUP) {
ret = unshare(CLONE_NEWCGROUP);
if (ret < 0) {
- INFO("Failed to unshare CLONE_NEWCGROUP");
- goto out_warn_father;
+ if (errno != EINVAL) {
+ SYSERROR("Failed to unshare CLONE_NEWCGROUP");
+ goto out_warn_father;
+ }
+
+ handler->ns_clone_flags &= ~CLONE_NEWCGROUP;
+ SYSINFO("Kernel does not support CLONE_NEWCGROUP");
+ } else {
+ INFO("Unshared CLONE_NEWCGROUP");
}
- INFO("Unshared CLONE_NEWCGROUP");
}
/* Add the requested environment variables to the current environment to
struct lxc_conf *conf = handler->conf;
for (i = 0; i < LXC_NS_MAX; i++) {
- if (conf->ns_keep != 0) {
+ if (conf->ns_keep > 0) {
if ((conf->ns_keep & ns_info[i].clone_flag) == 0)
handler->ns_clone_flags |= ns_info[i].clone_flag;
- } else if (conf->ns_clone != 0) {
+ } else if (conf->ns_clone > 0) {
if ((conf->ns_clone & ns_info[i].clone_flag) > 0)
handler->ns_clone_flags |= ns_info[i].clone_flag;
} else {
* getpid() in the child would return the parent's pid. This is all fixed in
* newer glibc versions where the getpid() cache is removed and the pid/tid is
* not reset anymore.
- * However, if for whatever reason you - dear commiter - somehow need to get the
+ * However, if for whatever reason you - dear committer - somehow need to get the
* pid of the dummy intermediate process for do_share_ns() you need to call
* lxc_raw_getpid(). The next lxc_raw_clone() call does not employ CLONE_VM and
* will be fine.
return 0;
}
-static int lxc_setup_shmount(struct lxc_conf *conf)
-{
- size_t len_cont;
- char *full_cont_path;
- int ret = -1;
-
- /* Construct the shmount path under the container root. */
- len_cont = strlen(conf->rootfs.mount) + 1 + strlen(conf->shmount.path_cont);
- /* +1 for the terminating '\0' */
- full_cont_path = malloc(len_cont + 1);
- if (!full_cont_path) {
- SYSERROR("Not enough memory");
- return -ENOMEM;
- }
-
- ret = snprintf(full_cont_path, len_cont + 1, "%s/%s",
- conf->rootfs.mount, conf->shmount.path_cont);
- if (ret < 0 || ret >= len_cont + 1) {
- SYSERROR("Failed to create filename");
- free(full_cont_path);
- return -1;
- }
-
- /* Check if shmount point is already set up. */
- if (is_shared_mountpoint(conf->shmount.path_host)) {
- INFO("Path \"%s\" is already MS_SHARED. Reusing",
- conf->shmount.path_host);
- free(full_cont_path);
- return 0;
- }
-
- /* Create host and cont mount paths */
- ret = mkdir_p(conf->shmount.path_host, 0711);
- if (ret < 0 && errno != EEXIST) {
- SYSERROR("Failed to create directory \"%s\"",
- conf->shmount.path_host);
- free(full_cont_path);
- return ret;
- }
-
- ret = mkdir_p(full_cont_path, 0711);
- if (ret < 0 && errno != EEXIST) {
- SYSERROR("Failed to create directory \"%s\"", full_cont_path);
- free(full_cont_path);
- return ret;
- }
-
- /* Prepare host mountpoint */
- ret = mount("tmpfs", conf->shmount.path_host, "tmpfs", 0,
- "size=100k,mode=0711");
- if (ret < 0) {
- SYSERROR("Failed to mount \"%s\"", conf->shmount.path_host);
- free(full_cont_path);
- return ret;
- }
-
- ret = mount(conf->shmount.path_host, conf->shmount.path_host, "none",
- MS_REC | MS_SHARED, "");
- if (ret < 0) {
- SYSERROR("Failed to make shared \"%s\"", conf->shmount.path_host);
- free(full_cont_path);
- return ret;
- }
-
- INFO("Setup shared mount point \"%s\"", conf->shmount.path_host);
- free(full_cont_path);
- return 0;
-}
-
/* lxc_spawn() performs crucial setup tasks and clone()s the new process which
* exec()s the requested container binary.
* Note that lxc_spawn() runs in the parent namespaces. Any operations performed
if (ret < 0)
goto out_sync_fini;
- if (conf->shmount.path_host) {
- if (!conf->shmount.path_cont)
- goto out_sync_fini;
-
- ret = lxc_setup_shmount(conf);
- if (ret < 0) {
- ERROR("Failed to setup shared mount point");
- goto out_sync_fini;
- }
- }
-
if (handler->ns_clone_flags & CLONE_NEWNET) {
if (!lxc_list_empty(&conf->network)) {
ret = lxc_netns_set_nsid(handler->nsfd[LXC_NS_NET]);
if (ret < 0)
- SYSERROR("Failed to allocate new network namespace id");
+ SYSWARN("Failed to allocate new network namespace id");
else
TRACE("Allocated new network namespace id");
}
}
/* Now all networks are created, network devices are moved into place,
- * and the correct names and ifindeces in the respective namespaces have
+ * and the correct names and ifindices in the respective namespaces have
* been recorded. The corresponding structs have now all been filled. So
* log them for debugging purposes.
*/
if (!attach_block_device(handler->conf)) {
ERROR("Failed to attach block device");
+ ret = -1;
goto out_fini_nonet;
}
if (!cgroup_ops->monitor_create(cgroup_ops, handler)) {
ERROR("Failed to create monitor cgroup");
+ ret = -1;
goto out_fini_nonet;
}
if (!cgroup_ops->monitor_enter(cgroup_ops, handler->monitor_pid)) {
ERROR("Failed to enter monitor cgroup");
+ ret = -1;
goto out_fini_nonet;
}
if (!handler->init_died && handler->pid > 0) {
ERROR("Child process is not killed");
+ ret = -1;
goto out_abort;
}