Commit 9795e880 by Stéphane Graber Committed by GitHub

Merge pull request #1613 from brauner/2017-06-03/af_unix

abstract lxc_abstract_unix_{send,recv}_fd, bugfixes, and improvements
parents 3b011155 a394f952
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
*/ */
#include "config.h" #include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
...@@ -133,49 +135,66 @@ int lxc_abstract_unix_connect(const char *path) ...@@ -133,49 +135,66 @@ int lxc_abstract_unix_connect(const char *path)
return fd; return fd;
} }
int lxc_abstract_unix_send_fd(int fd, int sendfd, void *data, size_t size) int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds,
void *data, size_t size)
{ {
struct msghdr msg = { 0 }; int ret;
struct msghdr msg;
struct iovec iov; struct iovec iov;
struct cmsghdr *cmsg; struct cmsghdr *cmsg = NULL;
char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
char buf[1] = {0}; char buf[1] = {0};
int *val; char *cmsgbuf;
size_t cmsgbufsize = CMSG_SPACE(num_sendfds * sizeof(int));
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
cmsgbuf = malloc(cmsgbufsize);
if (!cmsgbuf)
return -1;
msg.msg_control = cmsgbuf; msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf); msg.msg_controllen = cmsgbufsize;
cmsg = CMSG_FIRSTHDR(&msg); cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_type = SCM_RIGHTS;
val = (int *)(CMSG_DATA(cmsg)); cmsg->cmsg_len = CMSG_LEN(num_sendfds * sizeof(int));
*val = sendfd;
msg.msg_name = NULL; msg.msg_controllen = cmsg->cmsg_len;
msg.msg_namelen = 0;
memcpy(CMSG_DATA(cmsg), sendfds, num_sendfds * sizeof(int));
iov.iov_base = data ? data : buf; iov.iov_base = data ? data : buf;
iov.iov_len = data ? size : sizeof(buf); iov.iov_len = data ? size : sizeof(buf);
msg.msg_iov = &iov; msg.msg_iov = &iov;
msg.msg_iovlen = 1; msg.msg_iovlen = 1;
return sendmsg(fd, &msg, MSG_NOSIGNAL); ret = sendmsg(fd, &msg, MSG_NOSIGNAL);
free(cmsgbuf);
return ret;
} }
int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size) int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
void *data, size_t size)
{ {
struct msghdr msg = { 0 }; int ret;
struct msghdr msg;
struct iovec iov; struct iovec iov;
struct cmsghdr *cmsg; struct cmsghdr *cmsg = NULL;
int ret, *val;
char cmsgbuf[CMSG_SPACE(sizeof(int))] = {0};
char buf[1] = {0}; char buf[1] = {0};
char *cmsgbuf;
size_t cmsgbufsize = CMSG_SPACE(num_recvfds * sizeof(int));
memset(&msg, 0, sizeof(msg));
memset(&iov, 0, sizeof(iov));
cmsgbuf = malloc(cmsgbufsize);
if (!cmsgbuf)
return -1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = cmsgbuf; msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf); msg.msg_controllen = cmsgbufsize;
iov.iov_base = data ? data : buf; iov.iov_base = data ? data : buf;
iov.iov_len = data ? size : sizeof(buf); iov.iov_len = data ? size : sizeof(buf);
...@@ -188,17 +207,14 @@ int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size) ...@@ -188,17 +207,14 @@ int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size)
cmsg = CMSG_FIRSTHDR(&msg); cmsg = CMSG_FIRSTHDR(&msg);
/* if the message is wrong the variable will not be memset(recvfds, -1, num_recvfds * sizeof(int));
* filled and the peer will notified about a problem */ if (cmsg && cmsg->cmsg_len == CMSG_LEN(num_recvfds * sizeof(int)) &&
*recvfd = -1; cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
memcpy(recvfds, CMSG_DATA(cmsg), num_recvfds * sizeof(int));
if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int)) &&
cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
val = (int *) CMSG_DATA(cmsg);
*recvfd = *val;
} }
out: out:
free(cmsgbuf);
return ret; return ret;
} }
......
...@@ -24,13 +24,17 @@ ...@@ -24,13 +24,17 @@
#ifndef __LXC_AF_UNIX_H #ifndef __LXC_AF_UNIX_H
#define __LXC_AF_UNIX_H #define __LXC_AF_UNIX_H
#include <stdio.h>
/* does not enforce \0-termination */ /* does not enforce \0-termination */
extern int lxc_abstract_unix_open(const char *path, int type, int flags); extern int lxc_abstract_unix_open(const char *path, int type, int flags);
extern int lxc_abstract_unix_close(int fd); extern int lxc_abstract_unix_close(int fd);
/* does not enforce \0-termination */ /* does not enforce \0-termination */
extern int lxc_abstract_unix_connect(const char *path); extern int lxc_abstract_unix_connect(const char *path);
extern int lxc_abstract_unix_send_fd(int fd, int sendfd, void *data, size_t size); extern int lxc_abstract_unix_send_fds(int fd, int *sendfds, int num_sendfds,
extern int lxc_abstract_unix_recv_fd(int fd, int *recvfd, void *data, size_t size); void *data, size_t size);
extern int lxc_abstract_unix_recv_fds(int fd, int *recvfds, int num_recvfds,
void *data, size_t size);
extern int lxc_abstract_unix_send_credential(int fd, void *data, size_t size); extern int lxc_abstract_unix_send_credential(int fd, void *data, size_t size);
extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size); extern int lxc_abstract_unix_rcv_credential(int fd, void *data, size_t size);
......
...@@ -986,7 +986,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun ...@@ -986,7 +986,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
goto on_error; goto on_error;
/* Send child fd of the LSM security module to write to. */ /* Send child fd of the LSM security module to write to. */
ret = lxc_abstract_unix_send_fd(ipc_sockets[0], labelfd, NULL, 0); ret = lxc_abstract_unix_send_fds(ipc_sockets[0], &labelfd, 1, NULL, 0);
saved_errno = errno; saved_errno = errno;
close(labelfd); close(labelfd);
if (ret <= 0) { if (ret <= 0) {
...@@ -1273,7 +1273,7 @@ static int attach_child_main(void* data) ...@@ -1273,7 +1273,7 @@ static int attach_child_main(void* data)
if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) { if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
int on_exec; int on_exec;
/* Receive fd for LSM security module. */ /* Receive fd for LSM security module. */
ret = lxc_abstract_unix_recv_fd(ipc_socket, &lsm_labelfd, NULL, 0); ret = lxc_abstract_unix_recv_fds(ipc_socket, &lsm_labelfd, 1, NULL, 0);
if (ret <= 0) { if (ret <= 0) {
ERROR("Expected to receive file descriptor: %s.", strerror(errno)); ERROR("Expected to receive file descriptor: %s.", strerror(errno));
shutdown(ipc_socket, SHUT_RDWR); shutdown(ipc_socket, SHUT_RDWR);
......
...@@ -23,17 +23,13 @@ ...@@ -23,17 +23,13 @@
#ifndef __LXC_BDEV_H #ifndef __LXC_BDEV_H
#define __LXC_BDEV_H #define __LXC_BDEV_H
/* blockdev operations for:
* aufs, dir, raw, btrfs, overlayfs, aufs, lvm, loop, zfs, nbd (qcow2, raw, vdi, qed)
*/
#include <lxc/lxccontainer.h> #include "config.h"
#include <stdint.h> #include <stdint.h>
#include <sys/mount.h> #include <sys/mount.h>
#include "config.h" #include <lxc/lxccontainer.h>
/* define constants if the kernel/glibc headers don't define them */
#ifndef MS_DIRSYNC #ifndef MS_DIRSYNC
#define MS_DIRSYNC 128 #define MS_DIRSYNC 128
#endif #endif
...@@ -73,18 +69,19 @@ struct bdev_ops { ...@@ -73,18 +69,19 @@ struct bdev_ops {
int (*create)(struct bdev *bdev, const char *dest, const char *n, int (*create)(struct bdev *bdev, const char *dest, const char *n,
struct bdev_specs *specs); struct bdev_specs *specs);
/* given original mount, rename the paths for cloned container */ /* given original mount, rename the paths for cloned container */
int (*clone_paths)(struct bdev *orig, struct bdev *new, const char *oldname, int (*clone_paths)(struct bdev *orig, struct bdev *new,
const char *cname, const char *oldpath, const char *lxcpath, const char *oldname, const char *cname,
int snap, uint64_t newsize, struct lxc_conf *conf); const char *oldpath, const char *lxcpath, int snap,
uint64_t newsize, struct lxc_conf *conf);
bool can_snapshot; bool can_snapshot;
bool can_backup; bool can_backup;
}; };
/* /*
* When lxc-start (conf.c) is mounting a rootfs, then src will be the * When lxc-start is mounting a rootfs, then src will be the "lxc.rootfs" value,
* 'lxc.rootfs' value, dest will be mount dir (i.e. $libdir/lxc) When clone * dest will be mount dir (i.e. $libdir/lxc) When clone or create is doing so,
* or create is doing so, then dest will be $lxcpath/$lxcname/rootfs, since * then dest will be $lxcpath/$lxcname/rootfs, since we may need to rsync from
* we may need to rsync from one to the other. * one to the other.
* data is so far unused. * data is so far unused.
*/ */
struct bdev { struct bdev {
...@@ -93,10 +90,10 @@ struct bdev { ...@@ -93,10 +90,10 @@ struct bdev {
char *src; char *src;
char *dest; char *dest;
char *mntopts; char *mntopts;
// turn the following into a union if need be /* Turn the following into a union if need be. */
// lofd is the open fd for the mounted loopback file /* lofd is the open fd for the mounted loopback file. */
int lofd; int lofd;
// index for the connected nbd device /* index for the connected nbd device. */
int nbd_idx; int nbd_idx;
}; };
...@@ -104,9 +101,9 @@ bool bdev_is_dir(struct lxc_conf *conf, const char *path); ...@@ -104,9 +101,9 @@ bool bdev_is_dir(struct lxc_conf *conf, const char *path);
bool bdev_can_backup(struct lxc_conf *conf); bool bdev_can_backup(struct lxc_conf *conf);
/* /*
* Instantiate a bdev object. The src is used to determine which blockdev * Instantiate a bdev object. The src is used to determine which blockdev type
* type this should be. The dst and data are optional, and will be used * this should be. The dst and data are optional, and will be used in case of
* in case of mount/umount. * mount/umount.
* *
* Optionally, src can be 'dir:/var/lib/lxc/c1' or 'lvm:/dev/lxc/c1'. For * Optionally, src can be 'dir:/var/lib/lxc/c1' or 'lvm:/dev/lxc/c1'. For
* other backing stores, this will allow additional options. In particular, * other backing stores, this will allow additional options. In particular,
...@@ -118,13 +115,13 @@ struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst, ...@@ -118,13 +115,13 @@ struct bdev *bdev_init(struct lxc_conf *conf, const char *src, const char *dst,
const char *data); const char *data);
struct bdev *bdev_copy(struct lxc_container *c0, const char *cname, struct bdev *bdev_copy(struct lxc_container *c0, const char *cname,
const char *lxcpath, const char *bdevtype, const char *lxcpath, const char *bdevtype, int flags,
int flags, const char *bdevdata, uint64_t newsize, const char *bdevdata, uint64_t newsize, int *needs_rdep);
int *needs_rdep); struct bdev *bdev_create(const char *dest, const char *type, const char *cname,
struct bdev *bdev_create(const char *dest, const char *type, struct bdev_specs *specs);
const char *cname, struct bdev_specs *specs);
void bdev_put(struct bdev *bdev); void bdev_put(struct bdev *bdev);
bool bdev_destroy(struct lxc_conf *conf); bool bdev_destroy(struct lxc_conf *conf);
/* callback function to be used with userns_exec_1() */ /* callback function to be used with userns_exec_1() */
int bdev_destroy_wrapper(void *data); int bdev_destroy_wrapper(void *data);
...@@ -134,11 +131,12 @@ int bdev_destroy_wrapper(void *data); ...@@ -134,11 +131,12 @@ int bdev_destroy_wrapper(void *data);
*/ */
int blk_getsize(struct bdev *bdev, uint64_t *size); int blk_getsize(struct bdev *bdev, uint64_t *size);
int detect_fs(struct bdev *bdev, char *type, int len); int detect_fs(struct bdev *bdev, char *type, int len);
int do_mkfs(const char *path, const char *fstype); int do_mkfs_exec_wrapper(void *args);
int is_blktype(struct bdev *b); int is_blktype(struct bdev *b);
int mount_unknown_fs(const char *rootfs, const char *target, int mount_unknown_fs(const char *rootfs, const char *target,
const char *options); const char *options);
bool rootfs_is_blockdev(struct lxc_conf *conf); bool rootfs_is_blockdev(struct lxc_conf *conf);
/* /*
* these are really for qemu-nbd support, as container shutdown * these are really for qemu-nbd support, as container shutdown
* must explicitly request device detach. * must explicitly request device detach.
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <linux/loop.h> #include <linux/loop.h>
#include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include "bdev.h" #include "bdev.h"
...@@ -157,8 +158,19 @@ int loop_destroy(struct bdev *orig) ...@@ -157,8 +158,19 @@ int loop_destroy(struct bdev *orig)
int loop_detect(const char *path) int loop_detect(const char *path)
{ {
int ret;
struct stat s;
if (strncmp(path, "loop:", 5) == 0) if (strncmp(path, "loop:", 5) == 0)
return 1; return 1;
ret = stat(path, &s);
if (ret < 0)
return 0;
if (__S_ISTYPE(s.st_mode, S_IFREG))
return 1;
return 0; return 0;
} }
...@@ -166,15 +178,23 @@ int loop_mount(struct bdev *bdev) ...@@ -166,15 +178,23 @@ int loop_mount(struct bdev *bdev)
{ {
int ret, loopfd; int ret, loopfd;
char loname[MAXPATHLEN]; char loname[MAXPATHLEN];
char *src = bdev->src;
if (strcmp(bdev->type, "loop")) if (strcmp(bdev->type, "loop"))
return -22; return -22;
if (!bdev->src || !bdev->dest) if (!bdev->src || !bdev->dest)
return -22; return -22;
loopfd = lxc_prepare_loop_dev(bdev->src + 5, loname, LO_FLAGS_AUTOCLEAR); /* skip prefix */
if (loopfd < 0) if (!strncmp(bdev->src, "loop:", 5))
src += 5;
loopfd = lxc_prepare_loop_dev(src, loname, LO_FLAGS_AUTOCLEAR);
if (loopfd < 0) {
ERROR("failed to prepare loop device for loop file \"%s\"", src);
return -1; return -1;
}
DEBUG("prepared loop device \"%s\"", loname); DEBUG("prepared loop device \"%s\"", loname);
ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts); ret = mount_unknown_fs(loname, bdev->dest, bdev->mntopts);
...@@ -206,6 +226,9 @@ int loop_umount(struct bdev *bdev) ...@@ -206,6 +226,9 @@ int loop_umount(struct bdev *bdev)
static int do_loop_create(const char *path, uint64_t size, const char *fstype) static int do_loop_create(const char *path, uint64_t size, const char *fstype)
{ {
int fd, ret; int fd, ret;
const char *cmd_args[2] = {fstype, path};
char cmd_output[MAXPATHLEN];
// create the new loopback file. // create the new loopback file.
fd = creat(path, S_IRUSR|S_IWUSR); fd = creat(path, S_IRUSR|S_IWUSR);
if (fd < 0) if (fd < 0)
...@@ -227,11 +250,10 @@ static int do_loop_create(const char *path, uint64_t size, const char *fstype) ...@@ -227,11 +250,10 @@ static int do_loop_create(const char *path, uint64_t size, const char *fstype)
} }
// create an fs in the loopback file // create an fs in the loopback file
if (do_mkfs(path, fstype) < 0) { ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
ERROR("Error creating filesystem type %s on %s", fstype, (void *)cmd_args);
path); if (ret < 0)
return -1; return -1;
}
return 0; return 0;
} }
...@@ -282,6 +282,8 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -282,6 +282,8 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
char fstype[100]; char fstype[100];
uint64_t size = newsize; uint64_t size = newsize;
int len, ret; int len, ret;
const char *cmd_args[2];
char cmd_output[MAXPATHLEN];
if (!orig->src || !orig->dest) if (!orig->src || !orig->dest)
return -1; return -1;
...@@ -348,12 +350,15 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname, ...@@ -348,12 +350,15 @@ int lvm_clonepaths(struct bdev *orig, struct bdev *new, const char *oldname,
ERROR("Error creating new lvm blockdev"); ERROR("Error creating new lvm blockdev");
return -1; return -1;
} }
if (do_mkfs(new->src, fstype) < 0) {
ERROR("Error creating filesystem type %s on %s", fstype, cmd_args[0] = fstype;
new->src); cmd_args[1] = new->src;
// create an fs in the loopback file
ret = run_command(cmd_output, sizeof(cmd_output),
do_mkfs_exec_wrapper, (void *)cmd_args);
if (ret < 0)
return -1; return -1;
} }
}
return 0; return 0;
} }
...@@ -378,6 +383,8 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -378,6 +383,8 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n,
const char *vg, *thinpool, *fstype, *lv = n; const char *vg, *thinpool, *fstype, *lv = n;
uint64_t sz; uint64_t sz;
int ret, len; int ret, len;
const char *cmd_args[2];
char cmd_output[MAXPATHLEN];
if (!specs) if (!specs)
return -1; return -1;
...@@ -416,11 +423,14 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -416,11 +423,14 @@ int lvm_create(struct bdev *bdev, const char *dest, const char *n,
fstype = specs->fstype; fstype = specs->fstype;
if (!fstype) if (!fstype)
fstype = DEFAULT_FSTYPE; fstype = DEFAULT_FSTYPE;
if (do_mkfs(bdev->src, fstype) < 0) {
ERROR("Error creating filesystem type %s on %s", fstype, cmd_args[0] = fstype;
bdev->src); cmd_args[1] = bdev->src;
ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
(void *)cmd_args);
if (ret < 0)
return -1; return -1;
}
if (!(bdev->dest = strdup(dest))) if (!(bdev->dest = strdup(dest)))
return -1; return -1;
......
...@@ -51,6 +51,8 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -51,6 +51,8 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n,
int ret, len; int ret, len;
char sz[24]; char sz[24];
pid_t pid; pid_t pid;
const char *cmd_args[2];
char cmd_output[MAXPATHLEN];
if (!specs) if (!specs)
return -1; return -1;
...@@ -104,11 +106,13 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n, ...@@ -104,11 +106,13 @@ int rbd_create(struct bdev *bdev, const char *dest, const char *n,
if (!fstype) if (!fstype)
fstype = DEFAULT_FSTYPE; fstype = DEFAULT_FSTYPE;
if (do_mkfs(bdev->src, fstype) < 0) { cmd_args[0] = fstype;
ERROR("Error creating filesystem type %s on %s", fstype, cmd_args[1] = bdev->src;
bdev->src); ret = run_command(cmd_output, sizeof(cmd_output), do_mkfs_exec_wrapper,
(void *)cmd_args);
if (ret < 0)
return -1; return -1;
}
if (!(bdev->dest = strdup(dest))) if (!(bdev->dest = strdup(dest)))
return -1; return -1;
......
...@@ -171,7 +171,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd) ...@@ -171,7 +171,7 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
int ret,rspfd; int ret,rspfd;
struct lxc_cmd_rsp *rsp = &cmd->rsp; struct lxc_cmd_rsp *rsp = &cmd->rsp;
ret = lxc_abstract_unix_recv_fd(sock, &rspfd, rsp, sizeof(*rsp)); ret = lxc_abstract_unix_recv_fds(sock, &rspfd, 1, rsp, sizeof(*rsp));
if (ret < 0) { if (ret < 0) {
WARN("Command %s failed to receive response: %s.", WARN("Command %s failed to receive response: %s.",
lxc_cmd_str(cmd->req.cmd), strerror(errno)); lxc_cmd_str(cmd->req.cmd), strerror(errno));
...@@ -756,7 +756,7 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req, ...@@ -756,7 +756,7 @@ static int lxc_cmd_console_callback(int fd, struct lxc_cmd_req *req,
memset(&rsp, 0, sizeof(rsp)); memset(&rsp, 0, sizeof(rsp));
rsp.data = INT_TO_PTR(ttynum); rsp.data = INT_TO_PTR(ttynum);
if (lxc_abstract_unix_send_fd(fd, masterfd, &rsp, sizeof(rsp)) < 0) { if (lxc_abstract_unix_send_fds(fd, &masterfd, 1, &rsp, sizeof(rsp)) < 0) {
ERROR("Failed to send tty to client."); ERROR("Failed to send tty to client.");
lxc_console_free(handler->conf, fd); lxc_console_free(handler->conf, fd);
goto out_close; goto out_close;
......
...@@ -172,11 +172,6 @@ static int sethostname(const char * name, size_t len) ...@@ -172,11 +172,6 @@ static int sethostname(const char * name, size_t len)
} }
#endif #endif
/* Define __S_ISTYPE if missing from the C library */
#ifndef __S_ISTYPE
#define __S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
#endif
#ifndef MS_PRIVATE #ifndef MS_PRIVATE
#define MS_PRIVATE (1<<18) #define MS_PRIVATE (1<<18)
#endif #endif
...@@ -585,49 +580,6 @@ static int run_script(const char *name, const char *section, const char *script, ...@@ -585,49 +580,6 @@ static int run_script(const char *name, const char *section, const char *script,
return run_buffer(buffer); return run_buffer(buffer);
} }
static int mount_rootfs_dir(const char *rootfs, const char *target,
const char *options)
{
unsigned long mntflags;
char *mntdata;
int ret;
if (parse_mntopts(options, &mntflags, &mntdata) < 0) {
free(mntdata);
return -1;
}
ret = mount(rootfs, target, "none", MS_BIND | MS_REC | mntflags, mntdata);
free(mntdata);
return ret;
}
static int lxc_mount_rootfs_file(const char *rootfs, const char *target,
const char *options)
{
int ret, loopfd;
char path[MAXPATHLEN];
loopfd = lxc_prepare_loop_dev(rootfs, path, LO_FLAGS_AUTOCLEAR);
if (loopfd < 0)
return -1;
DEBUG("prepared loop device \"%s\"", path);
ret = mount_unknown_fs(path, target, options);
close(loopfd);
DEBUG("mounted rootfs \"%s\" on loop device \"%s\" via loop device \"%s\"", rootfs, target, path);
return ret;
}
static int mount_rootfs_block(const char *rootfs, const char *target,
const char *options)
{
return mount_unknown_fs(rootfs, target, options);
}
/* /*
* pin_rootfs * pin_rootfs
* if rootfs is a directory, then open ${rootfs}/lxc.hold for writing for * if rootfs is a directory, then open ${rootfs}/lxc.hold for writing for
...@@ -836,49 +788,6 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha ...@@ -836,49 +788,6 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct lxc_ha
return 0; return 0;
} }
static int mount_rootfs(const char *rootfs, const char *target, const char *options)
{
char absrootfs[MAXPATHLEN];
struct stat s;
int i;
typedef int (*rootfs_cb)(const char *, const char *, const char *);
struct rootfs_type {
int type;
rootfs_cb cb;
} rtfs_type[] = {
{ S_IFDIR, mount_rootfs_dir },
{ S_IFBLK, mount_rootfs_block },
{ S_IFREG, lxc_mount_rootfs_file },
};
if (!realpath(rootfs, absrootfs)) {
SYSERROR("Failed to get real path for \"%s\".", rootfs);
return -1;
}
if (access(absrootfs, F_OK)) {
SYSERROR("The rootfs \"%s\" is not accessible.", absrootfs);
return -1;
}
if (stat(absrootfs, &s)) {
SYSERROR("Failed to stat the rootfs \"%s\".", absrootfs);
return -1;
}
for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
continue;
return rtfs_type[i].cb(absrootfs, target, options);
}
ERROR("Unsupported rootfs type for rootfs \"%s\".", absrootfs);
return -1;
}
static int setup_utsname(struct utsname *utsname) static int setup_utsname(struct utsname *utsname)
{ {
if (!utsname) if (!utsname)
...@@ -1258,8 +1167,9 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs) ...@@ -1258,8 +1167,9 @@ static int lxc_fill_autodev(const struct lxc_rootfs *rootfs)
return 0; return 0;
} }
static int setup_rootfs(struct lxc_conf *conf) static int lxc_setup_rootfs(struct lxc_conf *conf)
{ {
int ret;
struct bdev *bdev; struct bdev *bdev;
const struct lxc_rootfs *rootfs; const struct lxc_rootfs *rootfs;
...@@ -1278,18 +1188,17 @@ static int setup_rootfs(struct lxc_conf *conf) ...@@ -1278,18 +1188,17 @@ static int setup_rootfs(struct lxc_conf *conf)
return -1; return -1;
} }
/* First try mounting rootfs using a bdev. */
bdev = bdev_init(conf, rootfs->path, rootfs->mount, rootfs->options); bdev = bdev_init(conf, rootfs->path, rootfs->mount, rootfs->options);
if (bdev && !bdev->ops->mount(bdev)) { if (!bdev) {
bdev_put(bdev); ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".",
DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".",
rootfs->path, rootfs->mount, rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)"); rootfs->options ? rootfs->options : "(null)");
return 0; return -1;
} }
if (bdev)
ret = bdev->ops->mount(bdev);
bdev_put(bdev); bdev_put(bdev);
if (mount_rootfs(rootfs->path, rootfs->mount, rootfs->options)) { if (ret < 0) {
ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".", ERROR("Failed to mount rootfs \"%s\" onto \"%s\" with options \"%s\".",
rootfs->path, rootfs->mount, rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)"); rootfs->options ? rootfs->options : "(null)");
...@@ -1299,6 +1208,7 @@ static int setup_rootfs(struct lxc_conf *conf) ...@@ -1299,6 +1208,7 @@ static int setup_rootfs(struct lxc_conf *conf)
DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".", DEBUG("Mounted rootfs \"%s\" onto \"%s\" with options \"%s\".",
rootfs->path, rootfs->mount, rootfs->path, rootfs->mount,
rootfs->options ? rootfs->options : "(null)"); rootfs->options ? rootfs->options : "(null)");
return 0; return 0;
} }
...@@ -3418,7 +3328,14 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf, ...@@ -3418,7 +3328,14 @@ static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
return 0; return 0;
} }
/* Check whether a binary exist and has either CAP_SETUID, CAP_SETGID or both. */ /* Check whether a binary exist and has either CAP_SETUID, CAP_SETGID or both.
*
* @return 1 if functional binary was found
* @return 0 if binary exists but is lacking privilege
* @return -ENOENT if binary does not exist
* @return -EINVAL if cap to check is neither CAP_SETUID nor CAP_SETGID
*
*/
static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap) static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
{ {
char *path; char *path;
...@@ -3426,6 +3343,9 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap) ...@@ -3426,6 +3343,9 @@ static int idmaptool_on_path_and_privileged(const char *binary, cap_value_t cap)
struct stat st; struct stat st;
int fret = 0; int fret = 0;
if (cap != CAP_SETUID && cap != CAP_SETGID)
return -EINVAL;
path = on_path(binary, NULL); path = on_path(binary, NULL);
if (!path) if (!path)
return -ENOENT; return -ENOENT;
...@@ -3514,7 +3434,17 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid) ...@@ -3514,7 +3434,17 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
* range by shadow. * range by shadow.
*/ */
uidmap = idmaptool_on_path_and_privileged("newuidmap", CAP_SETUID); uidmap = idmaptool_on_path_and_privileged("newuidmap", CAP_SETUID);
if (uidmap == -ENOENT)
WARN("newuidmap binary is missing");
else if (!uidmap)
WARN("newuidmap is lacking necessary privileges");
gidmap = idmaptool_on_path_and_privileged("newgidmap", CAP_SETGID); gidmap = idmaptool_on_path_and_privileged("newgidmap", CAP_SETGID);
if (gidmap == -ENOENT)
WARN("newgidmap binary is missing");
else if (!gidmap)
WARN("newgidmap is lacking necessary privileges");
if (uidmap > 0 && gidmap > 0) { if (uidmap > 0 && gidmap > 0) {
DEBUG("Functional newuidmap and newgidmap binary found."); DEBUG("Functional newuidmap and newgidmap binary found.");
use_shadow = true; use_shadow = true;
...@@ -3916,16 +3846,21 @@ int chown_mapped_root(char *path, struct lxc_conf *conf) ...@@ -3916,16 +3846,21 @@ int chown_mapped_root(char *path, struct lxc_conf *conf)
return ret; return ret;
} }
int ttys_shift_ids(struct lxc_conf *c) int lxc_ttys_shift_ids(struct lxc_conf *c)
{ {
if (lxc_list_empty(&c->id_map)) if (lxc_list_empty(&c->id_map))
return 0; return 0;
if (strcmp(c->console.name, "") !=0 && chown_mapped_root(c->console.name, c) < 0) { if (!strcmp(c->console.name, ""))
ERROR("Failed to chown %s", c->console.name); return 0;
if (chown_mapped_root(c->console.name, c) < 0) {
ERROR("failed to chown console \"%s\"", c->console.name);
return -1; return -1;
} }
TRACE("chowned console \"%s\"", c->console.name);
return 0; return 0;
} }
...@@ -4059,7 +3994,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath ...@@ -4059,7 +3994,7 @@ int do_rootfs_setup(struct lxc_conf *conf, const char *name, const char *lxcpath
return -1; return -1;
} }
if (setup_rootfs(conf)) { if (lxc_setup_rootfs(conf)) {
ERROR("failed to setup rootfs for '%s'", name); ERROR("failed to setup rootfs for '%s'", name);
return -1; return -1;
} }
...@@ -4093,55 +4028,46 @@ static bool verify_start_hooks(struct lxc_conf *conf) ...@@ -4093,55 +4028,46 @@ static bool verify_start_hooks(struct lxc_conf *conf)
return true; return true;
} }
static int send_fd(int sock, int fd) static int lxc_send_ttys_to_parent(struct lxc_handler *handler)
{ {
int ret = lxc_abstract_unix_send_fd(sock, fd, NULL, 0); int i;
int *ttyfds;
struct lxc_pty_info *pty_info;
if (ret < 0) {
SYSERROR("Error sending tty fd to parent");
return -1;
}
return 0;
}
static int send_ttys_to_parent(struct lxc_handler *handler)
{
int i, ret;
struct lxc_conf *conf = handler->conf; struct lxc_conf *conf = handler->conf;
const struct lxc_tty_info *tty_info = &conf->tty_info; const struct lxc_tty_info *tty_info = &conf->tty_info;
int sock = handler->ttysock[0]; int sock = handler->ttysock[0];
int ret = -1;
size_t num_ttyfds = (2 * conf->tty);
for (i = 0; i < tty_info->nbtty; i++) { ttyfds = malloc(num_ttyfds * sizeof(int));
struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; if (!ttyfds)
ret = send_fd(sock, pty_info->slave); return -1;
if (ret >= 0)
send_fd(sock, pty_info->master); for (i = 0; i < num_ttyfds; i++) {
TRACE("sending pty \"%s\" with master fd %d and slave fd %d to " pty_info = &tty_info->pty_info[i / 2];
ttyfds[i++] = pty_info->slave;
ttyfds[i] = pty_info->master;
TRACE("send pty \"%s\" with master fd %d and slave fd %d to "
"parent", "parent",
pty_info->name, pty_info->master, pty_info->slave); pty_info->name, pty_info->master, pty_info->slave);
close(pty_info->slave);
pty_info->slave = -1;
close(pty_info->master);
pty_info->master = -1;
if (ret < 0) {
ERROR("failed to send pty \"%s\" with master fd %d and "
"slave fd %d to parent : %s",
pty_info->name, pty_info->master, pty_info->slave,
strerror(errno));
goto bad;
}
} }
ret = lxc_abstract_unix_send_fds(sock, ttyfds, num_ttyfds, NULL, 0);
if (ret < 0)
ERROR("failed to send %d ttys to parent: %s", conf->tty,
strerror(errno));
else
TRACE("sent %d ttys to parent", conf->tty);
close(handler->ttysock[0]); close(handler->ttysock[0]);
close(handler->ttysock[1]); close(handler->ttysock[1]);
return 0; for (i = 0; i < num_ttyfds; i++)
close(ttyfds[i]);
bad: free(ttyfds);
ERROR("Error writing tty fd to parent");
return -1; return ret;
} }
int lxc_setup(struct lxc_handler *handler) int lxc_setup(struct lxc_handler *handler)
...@@ -4260,7 +4186,7 @@ int lxc_setup(struct lxc_handler *handler) ...@@ -4260,7 +4186,7 @@ int lxc_setup(struct lxc_handler *handler)
return -1; return -1;
} }
if (send_ttys_to_parent(handler) < 0) { if (lxc_send_ttys_to_parent(handler) < 0) {
ERROR("failure sending console info to parent"); ERROR("failure sending console info to parent");
return -1; return -1;
} }
......
...@@ -472,7 +472,7 @@ extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf); ...@@ -472,7 +472,7 @@ extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype); extern int find_unmapped_nsid(struct lxc_conf *conf, enum idtype idtype);
extern int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype); extern int mapped_hostid(unsigned id, struct lxc_conf *conf, enum idtype idtype);
extern int chown_mapped_root(char *path, struct lxc_conf *conf); extern int chown_mapped_root(char *path, struct lxc_conf *conf);
extern int ttys_shift_ids(struct lxc_conf *c); extern int lxc_ttys_shift_ids(struct lxc_conf *c);
extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data, extern int userns_exec_1(struct lxc_conf *conf, int (*fn)(void *), void *data,
const char *fn_name); const char *fn_name);
extern int parse_mntopts(const char *mntopts, unsigned long *mntflags, extern int parse_mntopts(const char *mntopts, unsigned long *mntflags,
......
...@@ -481,7 +481,7 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char ...@@ -481,7 +481,7 @@ struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf, const char
goto out_restore_sigmask; goto out_restore_sigmask;
} }
if (ttys_shift_ids(conf) < 0) { if (lxc_ttys_shift_ids(conf) < 0) {
ERROR("Failed to shift tty into container."); ERROR("Failed to shift tty into container.");
goto out_restore_sigmask; goto out_restore_sigmask;
} }
...@@ -1008,23 +1008,16 @@ static int save_phys_nics(struct lxc_conf *conf) ...@@ -1008,23 +1008,16 @@ static int save_phys_nics(struct lxc_conf *conf)
return 0; return 0;
} }
static int recv_fd(int sock, int *fd) static int lxc_recv_ttys_from_child(struct lxc_handler *handler)
{ {
if (lxc_abstract_unix_recv_fd(sock, fd, NULL, 0) < 0) { int i;
SYSERROR("Error receiving tty file descriptor from child process."); int *ttyfds;
return -1; struct lxc_pty_info *pty_info;
} int ret = -1;
if (*fd == -1)
return -1;
return 0;
}
static int recv_ttys_from_child(struct lxc_handler *handler)
{
int i, ret;
int sock = handler->ttysock[1]; int sock = handler->ttysock[1];
struct lxc_conf *conf = handler->conf; struct lxc_conf *conf = handler->conf;
struct lxc_tty_info *tty_info = &conf->tty_info; struct lxc_tty_info *tty_info = &conf->tty_info;
size_t num_ttyfds = (2 * conf->tty);
if (!conf->tty) if (!conf->tty)
return 0; return 0;
...@@ -1033,25 +1026,31 @@ static int recv_ttys_from_child(struct lxc_handler *handler) ...@@ -1033,25 +1026,31 @@ static int recv_ttys_from_child(struct lxc_handler *handler)
if (!tty_info->pty_info) if (!tty_info->pty_info)
return -1; return -1;
for (i = 0; i < conf->tty; i++) { ttyfds = malloc(num_ttyfds * sizeof(int));
struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; if (!ttyfds)
pty_info->busy = 0;
ret = recv_fd(sock, &pty_info->slave);
if (ret >= 0)
recv_fd(sock, &pty_info->master);
if (ret < 0) {
ERROR("failed to receive pty with master fd %d and "
"slave fd %d from child: %s",
pty_info->master, pty_info->slave,
strerror(errno));
return -1; return -1;
ret = lxc_abstract_unix_recv_fds(sock, ttyfds, num_ttyfds, NULL, 0);
for (i = 0; (ret >= 0 && *ttyfds != -1) && (i < num_ttyfds); i++) {
pty_info = &tty_info->pty_info[i / 2];
pty_info->busy = 0;
pty_info->slave = ttyfds[i++];
pty_info->master = ttyfds[i];
TRACE("received pty with master fd %d and slave fd %d from "
"parent", pty_info->master, pty_info->slave);
} }
TRACE("received pty with master fd %d and slave fd %d from child",
pty_info->master, pty_info->slave);
}
tty_info->nbtty = conf->tty; tty_info->nbtty = conf->tty;
return 0; free(ttyfds);
if (ret < 0)
ERROR("failed to receive %d ttys from child: %s", conf->tty,
strerror(errno));
else
TRACE("received %d ttys from child", conf->tty);
return ret;
} }
void resolve_clone_flags(struct lxc_handler *handler) void resolve_clone_flags(struct lxc_handler *handler)
...@@ -1294,7 +1293,7 @@ static int lxc_spawn(struct lxc_handler *handler) ...@@ -1294,7 +1293,7 @@ static int lxc_spawn(struct lxc_handler *handler)
cgroups_connected = false; cgroups_connected = false;
/* Read tty fds allocated by child. */ /* Read tty fds allocated by child. */
if (recv_ttys_from_child(handler) < 0) { if (lxc_recv_ttys_from_child(handler) < 0) {
ERROR("Failed to receive tty info from child process."); ERROR("Failed to receive tty info from child process.");
goto out_delete_net; goto out_delete_net;
} }
......
...@@ -315,7 +315,7 @@ static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int * ...@@ -315,7 +315,7 @@ static int get_pty_on_host(struct lxc_container *c, struct wrapargs *wrap, int *
conf->console.descr = &descr; conf->console.descr = &descr;
/* Shift ttys to container. */ /* Shift ttys to container. */
if (ttys_shift_ids(conf) < 0) { if (lxc_ttys_shift_ids(conf) < 0) {
ERROR("Failed to shift tty into container"); ERROR("Failed to shift tty into container");
goto err1; goto err1;
} }
......
...@@ -39,6 +39,11 @@ ...@@ -39,6 +39,11 @@
#include "initutils.h" #include "initutils.h"
/* Define __S_ISTYPE if missing from the C library. */
#ifndef __S_ISTYPE
#define __S_ISTYPE(mode, mask) (((mode)&S_IFMT) == (mask))
#endif
/* Useful macros */ /* Useful macros */
/* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */ /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */
#define LXC_NUMSTRLEN64 21 #define LXC_NUMSTRLEN64 21
......
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