diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index 8f9a7ab297..185d2a4807 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -4,7 +4,6 @@ pkginclude_HEADERS = \ version.h noinst_HEADERS = \ - tools/arguments.h \ attach.h \ storage/storage.h \ storage/aufs.h \ @@ -18,6 +17,9 @@ noinst_HEADERS = \ storage/rsync.h \ storage/zfs.h \ storage/storage_utils.h \ + tools/arguments.h \ + tools/tool_utils.h \ + tools/tool_list.h \ cgroups/cgroup.h \ cgroups/cgroup_utils.h \ caps.h \ @@ -266,7 +268,7 @@ AM_LDFLAGS += -Wl,-rpath -Wl,$(libdir) endif LDADD=liblxc.la @CAP_LIBS@ @SELINUX_LIBS@ @SECCOMP_LIBS@ -lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c +lxc_attach_SOURCES = tools/lxc_attach.c tools/arguments.c tools/tool_utils.c lxc_autostart_SOURCES = tools/lxc_autostart.c tools/arguments.c lxc_cgroup_SOURCES = tools/lxc_cgroup.c tools/arguments.c lxc_config_SOURCES = tools/lxc_config.c tools/arguments.c diff --git a/src/lxc/confile.c b/src/lxc/confile.c index fa4f84da9e..9950c7ea4c 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2409,47 +2409,6 @@ signed long lxc_config_parse_arch(const char *arch) return -1; } -int lxc_fill_elevated_privileges(char *flaglist, int *flags) -{ - char *token, *saveptr = NULL; - int i, aflag; - struct { - const char *token; - int flag; - } all_privs[] = { - { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP }, - { "CAP", LXC_ATTACH_DROP_CAPABILITIES }, - { "LSM", LXC_ATTACH_LSM_EXEC }, - { NULL, 0 } - }; - - if (!flaglist) { - /* For the sake of backward compatibility, drop all privileges - * if none is specified. - */ - for (i = 0; all_privs[i].token; i++) - *flags |= all_privs[i].flag; - - return 0; - } - - token = strtok_r(flaglist, "|", &saveptr); - while (token) { - aflag = -1; - for (i = 0; all_privs[i].token; i++) - if (!strcmp(all_privs[i].token, token)) - aflag = all_privs[i].flag; - if (aflag < 0) - return -1; - - *flags |= aflag; - - token = strtok_r(NULL, "|", &saveptr); - } - - return 0; -} - /* Write out a configuration file. */ void write_config(FILE *fout, struct lxc_conf *c) { diff --git a/src/lxc/confile.h b/src/lxc/confile.h index d502178604..6c69bc7a5f 100644 --- a/src/lxc/confile.h +++ b/src/lxc/confile.h @@ -92,8 +92,6 @@ extern int lxc_config_define_load(struct lxc_list *defines, /* needed for lxc-attach */ extern signed long lxc_config_parse_arch(const char *arch); -extern int lxc_fill_elevated_privileges(char *flaglist, int *flags); - extern int lxc_clear_config_item(struct lxc_conf *c, const char *key); extern void write_config(FILE *fout, struct lxc_conf *c); diff --git a/src/lxc/tools/arguments.c b/src/lxc/tools/arguments.c index 272340b65d..f98053feca 100644 --- a/src/lxc/tools/arguments.c +++ b/src/lxc/tools/arguments.c @@ -182,6 +182,13 @@ static int lxc_arguments_lxcpath_add(struct lxc_arguments *args, return 0; } +void remove_trailing_slashes(char *p) +{ + int l = strlen(p); + while (--l >= 0 && (p[l] == '/' || p[l] == '\n')) + p[l] = '\0'; +} + extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, char *const argv[]) { @@ -250,7 +257,7 @@ extern int lxc_arguments_parse(struct lxc_arguments *args, int argc, /* If no lxcpaths were given, use default */ if (!args->lxcpath_cnt) { ret = lxc_arguments_lxcpath_add( - args, lxc_global_config_value("lxc.lxcpath")); + args, lxc_get_global_config_item("lxc.lxcpath")); if (ret < 0) return ret; } diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c index 926bf079ee..b2c405d3ad 100644 --- a/src/lxc/tools/lxc_attach.c +++ b/src/lxc/tools/lxc_attach.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -36,16 +37,8 @@ #include -#include "attach.h" #include "arguments.h" -#include "caps.h" -#include "conf.h" -#include "confile.h" -#include "console.h" -#include "log.h" -#include "list.h" -#include "mainloop.h" -#include "utils.h" +#include "tool_utils.h" static const struct option my_longopts[] = { {"elevated-privileges", optional_argument, 0, 'e'}, @@ -290,7 +283,6 @@ int main(int argc, char *argv[]) r = lxc_log_init(&log); if (r) exit(EXIT_FAILURE); - lxc_log_options_no_override(); if (geteuid()) { if (access(my_args.lxcpath[0], O_RDONLY) < 0) { diff --git a/src/lxc/tools/lxc_autostart.c b/src/lxc/tools/lxc_autostart.c index 48727b9f12..a3d4a8a8a4 100644 --- a/src/lxc/tools/lxc_autostart.c +++ b/src/lxc/tools/lxc_autostart.c @@ -24,7 +24,6 @@ #include #include "arguments.h" -#include "list.h" #include "log.h" #include "utils.h" diff --git a/src/lxc/tools/tool_utils.c b/src/lxc/tools/tool_utils.c new file mode 100644 index 0000000000..39b3881615 --- /dev/null +++ b/src/lxc/tools/tool_utils.c @@ -0,0 +1,336 @@ +/* liblxcapi + * + * Copyright © 2018 Christian Brauner . + * Copyright © 2018 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_SYS_PERSONALITY_H +#include +#endif + +#include + +#include "tool_utils.h" + +int lxc_fill_elevated_privileges(char *flaglist, int *flags) +{ + char *token, *saveptr = NULL; + int i, aflag; + struct { + const char *token; + int flag; + } all_privs[] = { + { "CGROUP", LXC_ATTACH_MOVE_TO_CGROUP }, + { "CAP", LXC_ATTACH_DROP_CAPABILITIES }, + { "LSM", LXC_ATTACH_LSM_EXEC }, + { NULL, 0 } + }; + + if (!flaglist) { + /* For the sake of backward compatibility, drop all privileges + * if none is specified. + */ + for (i = 0; all_privs[i].token; i++) + *flags |= all_privs[i].flag; + + return 0; + } + + token = strtok_r(flaglist, "|", &saveptr); + while (token) { + aflag = -1; + for (i = 0; all_privs[i].token; i++) + if (!strcmp(all_privs[i].token, token)) + aflag = all_privs[i].flag; + if (aflag < 0) + return -1; + + *flags |= aflag; + + token = strtok_r(NULL, "|", &saveptr); + } + + return 0; +} + +signed long lxc_config_parse_arch(const char *arch) +{ +#if HAVE_SYS_PERSONALITY_H + size_t i; + struct per_name { + char *name; + unsigned long per; + } pername[] = { + { "x86", PER_LINUX32 }, + { "linux32", PER_LINUX32 }, + { "i386", PER_LINUX32 }, + { "i486", PER_LINUX32 }, + { "i586", PER_LINUX32 }, + { "i686", PER_LINUX32 }, + { "athlon", PER_LINUX32 }, + { "mips", PER_LINUX32 }, + { "mipsel", PER_LINUX32 }, + { "ppc", PER_LINUX32 }, + { "arm", PER_LINUX32 }, + { "armv7l", PER_LINUX32 }, + { "armhf", PER_LINUX32 }, + { "armel", PER_LINUX32 }, + { "powerpc", PER_LINUX32 }, + { "linux64", PER_LINUX }, + { "x86_64", PER_LINUX }, + { "amd64", PER_LINUX }, + { "mips64", PER_LINUX }, + { "mips64el", PER_LINUX }, + { "ppc64", PER_LINUX }, + { "ppc64le", PER_LINUX }, + { "ppc64el", PER_LINUX }, + { "powerpc64", PER_LINUX }, + { "s390x", PER_LINUX }, + { "aarch64", PER_LINUX }, + { "arm64", PER_LINUX }, + }; + size_t len = sizeof(pername) / sizeof(pername[0]); + + for (i = 0; i < len; i++) { + if (!strcmp(pername[i].name, arch)) + return pername[i].per; + } +#endif + + return -1; +} + +enum { + LXC_NS_USER, + LXC_NS_MNT, + LXC_NS_PID, + LXC_NS_UTS, + LXC_NS_IPC, + LXC_NS_NET, + LXC_NS_CGROUP, + LXC_NS_MAX +}; + +const static struct ns_info { + const char *proc_name; + int clone_flag; +} ns_info[LXC_NS_MAX] = { + [LXC_NS_USER] = { "user", CLONE_NEWUSER }, + [LXC_NS_MNT] = { "mnt", CLONE_NEWNS }, + [LXC_NS_PID] = { "pid", CLONE_NEWPID }, + [LXC_NS_UTS] = { "uts", CLONE_NEWUTS }, + [LXC_NS_IPC] = { "ipc", CLONE_NEWIPC }, + [LXC_NS_NET] = { "net", CLONE_NEWNET }, + [LXC_NS_CGROUP] = { "cgroup", CLONE_NEWCGROUP } +}; + +int lxc_namespace_2_cloneflag(const char *namespace) +{ + int i; + for (i = 0; i < LXC_NS_MAX; i++) + if (!strcasecmp(ns_info[i].proc_name, namespace)) + return ns_info[i].clone_flag; + + fprintf(stderr, "Invalid namespace name \"%s\"", namespace); + return -EINVAL; +} + +int lxc_fill_namespace_flags(char *flaglist, int *flags) +{ + char *token, *saveptr = NULL; + int aflag; + + if (!flaglist) { + fprintf(stderr, "At least one namespace is needed\n"); + return -1; + } + + token = strtok_r(flaglist, "|", &saveptr); + while (token) { + + aflag = lxc_namespace_2_cloneflag(token); + if (aflag < 0) + return -1; + + *flags |= aflag; + + token = strtok_r(NULL, "|", &saveptr); + } + + return 0; +} + +#if HAVE_LIBCAP + +#ifndef PR_CAPBSET_READ +#define PR_CAPBSET_READ 23 +#endif + +int lxc_caps_init(void) +{ + uid_t uid = getuid(); + gid_t gid = getgid(); + uid_t euid = geteuid(); + + if (!uid) + return 0; + + if (uid && !euid) { + if (prctl(PR_SET_KEEPCAPS, 1)) { + fprintf(stderr, "%s - Failed to set PR_SET_KEEPCAPS\n", strerror(errno)); + return -1; + } + + if (setresgid(gid, gid, gid)) { + fprintf(stderr, "%s - Failed to change gid to %d\n", strerror(errno), gid); + return -1; + } + + if (setresuid(uid, uid, uid)) { + fprintf(stderr, "%s - Failed to change uid to %d\n", strerror(errno), uid); + return -1; + } + + if (lxc_caps_up()) { + fprintf(stderr, "%s - Failed to restore capabilities\n", strerror(errno)); + return -1; + } + } + + return 0; +} + +int lxc_caps_up(void) +{ + cap_t caps; + cap_value_t cap; + int ret; + + /* when we are run as root, we don't want to play + * with the capabilities */ + if (!getuid()) + return 0; + + caps = cap_get_proc(); + if (!caps) { + fprintf(stderr, "%s - Failed to cap_get_proc\n", strerror(errno)); + return -1; + } + + for (cap = 0; cap <= CAP_LAST_CAP; cap++) { + cap_flag_value_t flag; + + ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag); + if (ret) { + if (errno == EINVAL) { + break; + } else { + fprintf(stderr, "%s- Failed to call cap_get_flag\n", strerror(errno)); + goto out; + } + } + + ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag); + if (ret) { + fprintf(stderr, "%s - Failed to call cap_set_flag", strerror(errno)); + goto out; + } + } + + ret = cap_set_proc(caps); + if (ret) { + fprintf(stderr, "%s - Failed to cap_set_proc", strerror(errno)); + goto out; + } + +out: + cap_free(caps); + return 0; +} + +#endif + +int lxc_wait_for_pid_status(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + return -1; + } + if (ret != pid) + goto again; + return status; +} + +int lxc_safe_int(const char *numstr, int *converted) +{ + char *err = NULL; + signed long int sli; + + errno = 0; + sli = strtol(numstr, &err, 0); + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) + return -ERANGE; + + if (errno != 0 && sli == 0) + return -EINVAL; + + if (err == numstr || *err != '\0') + return -EINVAL; + + if (sli > INT_MAX || sli < INT_MIN) + return -ERANGE; + + *converted = (int)sli; + return 0; +} + +int lxc_safe_long(const char *numstr, long int *converted) +{ + char *err = NULL; + signed long int sli; + + errno = 0; + sli = strtol(numstr, &err, 0); + if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN)) + return -ERANGE; + + if (errno != 0 && sli == 0) + return -EINVAL; + + if (err == numstr || *err != '\0') + return -EINVAL; + + *converted = sli; + return 0; +} diff --git a/src/lxc/tools/tool_utils.h b/src/lxc/tools/tool_utils.h new file mode 100644 index 0000000000..9f0e6a01fd --- /dev/null +++ b/src/lxc/tools/tool_utils.h @@ -0,0 +1,130 @@ +/* liblxcapi + * + * Copyright © 2018 Christian Brauner . + * Copyright © 2018 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __LXC_UTILS_H +#define __LXC_UTILS_H + +/* Properly support loop devices on 32bit systems. */ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include +#include + +#include + +#include "tool_list.h" + +#define TOOL_MAXPATHLEN 4096 + +#ifndef CLONE_PARENT_SETTID +#define CLONE_PARENT_SETTID 0x00100000 +#endif + +#ifndef CLONE_CHILD_CLEARTID +#define CLONE_CHILD_CLEARTID 0x00200000 +#endif + +#ifndef CLONE_CHILD_SETTID +#define CLONE_CHILD_SETTID 0x01000000 +#endif + +#ifndef CLONE_VFORK +#define CLONE_VFORK 0x00004000 +#endif + +#ifndef CLONE_THREAD +#define CLONE_THREAD 0x00010000 +#endif + +#ifndef CLONE_SETTLS +#define CLONE_SETTLS 0x00080000 +#endif + +#ifndef CLONE_VM +#define CLONE_VM 0x00000100 +#endif + +#ifndef CLONE_FILES +#define CLONE_FILES 0x00000400 +#endif + +#ifndef CLONE_FS +# define CLONE_FS 0x00000200 +#endif +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif +#ifndef CLONE_NEWCGROUP +# define CLONE_NEWCGROUP 0x02000000 +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif + +enum { + LXC_NS_USER, + LXC_NS_MNT, + LXC_NS_PID, + LXC_NS_UTS, + LXC_NS_IPC, + LXC_NS_NET, + LXC_NS_CGROUP, + LXC_NS_MAX +}; + +extern int lxc_fill_elevated_privileges(char *flaglist, int *flags); +extern signed long lxc_config_parse_arch(const char *arch); +extern int lxc_namespace_2_cloneflag(const char *namespace); +extern int lxc_fill_namespace_flags(char *flaglist, int *flags); + +#if HAVE_LIBCAP +#include + +extern int lxc_caps_up(void); +extern int lxc_caps_init(void); +#else +static inline int lxc_caps_up(void) { + return 0; +} + +static inline int lxc_caps_init(void) { + return 0; +} +#endif + +extern int lxc_wait_for_pid_status(pid_t pid); +extern int lxc_safe_int(const char *numstr, int *converted); +extern int lxc_safe_long(const char *numstr, long int *converted); + +#endif /* __LXC_UTILS_H */