Commit eb09dc4e by Serge Hallyn Committed by GitHub

Merge pull request #1544 from brauner/2017-05-08/harden_console_handling

harden console handling
parents 9fd8b8a7 467c7ff3
......@@ -6,7 +6,6 @@ lxc.cgroup.devices.allow =
lxc.devttydir =
# Extra bind-mounts for userns
lxc.mount.entry = /dev/console dev/console none bind,create=file 0 0
lxc.mount.entry = /dev/full dev/full none bind,create=file 0 0
lxc.mount.entry = /dev/null dev/null none bind,create=file 0 0
lxc.mount.entry = /dev/random dev/random none bind,create=file 0 0
......
......@@ -668,10 +668,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<listitem>
<para>
Specify a path to a device to which the console will be
attached. The keyword 'none' will simply disable the
console. This is dangerous once if have a rootfs with a
console device file where the application can write, the
messages will fall in the host.
attached. The keyword 'none' will simply disable the
console. Note, when specifying 'none' and creating a device node
for the console in the container at /dev/console or bind-mounting
the hosts's /dev/console into the container at /dev/console the
container will have direct access to the hosts's /dev/console.
This is dangerous when the container has write access to the
device and should thus be used with caution.
</para>
</listitem>
</varlistentry>
......@@ -727,7 +730,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<listitem>
<para>
Specify a directory under <filename>/dev</filename>
under which to create the container console devices.
under which to create the container console devices. Note that LXC
will move any bind-mounts or device nodes for /dev/console into
this directory.
</para>
</listitem>
</varlistentry>
......
......@@ -415,16 +415,17 @@ void lxc_console_free(struct lxc_conf *conf, int fd)
}
}
static void lxc_console_peer_default(struct lxc_console *console)
static int lxc_console_peer_default(struct lxc_console *console)
{
struct lxc_tty_state *ts;
const char *path = console->path;
int fd;
int ret = 0;
/* if no console was given, try current controlling terminal, there
* won't be one if we were started as a daemon (-d)
/* If no console was given, try current controlling terminal, there
* won't be one if we were started as a daemon (-d).
*/
if (!path && !access("/dev/tty", F_OK)) {
int fd;
fd = open("/dev/tty", O_RDWR);
if (fd >= 0) {
close(fd);
......@@ -432,25 +433,29 @@ static void lxc_console_peer_default(struct lxc_console *console)
}
}
if (!path)
goto out;
DEBUG("opening %s for console peer", path);
console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
O_APPEND, 0600));
if (console->peer < 0)
if (!path) {
errno = ENOTTY;
DEBUG("process does not have a controlling terminal");
goto out;
}
DEBUG("using '%s' as console", path);
console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
if (console->peer < 0) {
ERROR("failed to open \"%s\"", path);
return -ENOTTY;
}
DEBUG("using \"%s\" as peer tty device", path);
if (!isatty(console->peer))
goto err1;
if (!isatty(console->peer)) {
ERROR("file descriptor for file \"%s\" does not refer to a tty device", path);
goto on_error1;
}
ts = lxc_console_sigwinch_init(console->peer, console->master);
console->tty_state = ts;
if (!ts) {
WARN("Unable to install SIGWINCH");
goto err1;
WARN("unable to install SIGWINCH handler");
goto on_error1;
}
lxc_console_winsz(console->peer, console->master);
......@@ -458,23 +463,27 @@ static void lxc_console_peer_default(struct lxc_console *console)
console->tios = malloc(sizeof(*console->tios));
if (!console->tios) {
SYSERROR("failed to allocate memory");
goto err1;
ret = -ENOMEM;
goto on_error1;
}
if (lxc_setup_tios(console->peer, console->tios) < 0)
goto err2;
return;
goto on_error2;
else
goto out;
err2:
on_error2:
free(console->tios);
console->tios = NULL;
err1:
ret = -ENOTTY;
on_error1:
close(console->peer);
console->peer = -1;
ret = -ENOTTY;
out:
DEBUG("no console peer");
return;
return ret;
}
void lxc_console_delete(struct lxc_console *console)
......@@ -503,21 +512,24 @@ int lxc_console_create(struct lxc_conf *conf)
int ret;
if (conf->is_execute) {
INFO("no console for lxc-execute.");
INFO("not allocating a console device for lxc-execute.");
return 0;
}
if (!conf->rootfs.path)
if (!conf->rootfs.path) {
INFO("container does not have a rootfs, console device will be shared with the host");
return 0;
}
if (console->path && !strcmp(console->path, "none"))
if (console->path && !strcmp(console->path, "none")) {
INFO("no console requested");
return 0;
}
process_lock();
ret = openpty(&console->master, &console->slave,
console->name, NULL, NULL);
ret = openpty(&console->master, &console->slave, console->name, NULL, NULL);
process_unlock();
if (ret) {
if (ret < 0) {
SYSERROR("failed to allocate a pty");
return -1;
}
......@@ -532,17 +544,19 @@ int lxc_console_create(struct lxc_conf *conf)
goto err;
}
lxc_console_peer_default(console);
ret = lxc_console_peer_default(console);
if (ret < 0) {
ERROR("failed to allocate peer tty device");
goto err;
}
if (console->log_path) {
console->log_fd = lxc_unpriv(open(console->log_path,
O_CLOEXEC | O_RDWR |
O_CREAT | O_APPEND, 0600));
console->log_fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
if (console->log_fd < 0) {
SYSERROR("failed to open '%s'", console->log_path);
SYSERROR("failed to open console log file \"%s\"", console->log_path);
goto err;
}
DEBUG("using '%s' as console log", console->log_path);
DEBUG("using \"%s\" as console log file", console->log_path);
}
return 0;
......
......@@ -2204,3 +2204,29 @@ on_error:
return fd_loop;
}
int lxc_unstack_mountpoint(const char *path, bool lazy)
{
int ret;
int umounts = 0;
pop_stack:
ret = umount2(path, lazy ? MNT_DETACH : 0);
if (ret < 0) {
/* We consider anything else than EINVAL deadly to prevent going
* into an infinite loop. (The other alternative is constantly
* parsing /proc/self/mountinfo which is yucky and probably
* racy.)
*/
if (errno != EINVAL)
return -errno;
} else {
/* We succeeded in umounting. Make sure that there's no other
* mountpoint stacked underneath.
*/
umounts++;
goto pop_stack;
}
return umounts;
}
......@@ -348,4 +348,11 @@ int lxc_setgroups(int size, gid_t list[]);
/* Find an unused loop device and associate it with source. */
int lxc_prepare_loop_dev(const char *source, char *loop_dev, int flags);
/* Clear all mounts on a given node.
* >= 0 successfully cleared. The number returned is the number of umounts
* performed.
* < 0 error umounting. Return -errno.
*/
int lxc_unstack_mountpoint(const char *path, bool lazy);
#endif /* __LXC_UTILS_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment