From 20502652347ac34ef5a582a8107f6efaed7acd20 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Wed, 5 Jun 2019 23:43:53 +0200 Subject: [PATCH] start: generate new boot id on container start Closes #3027. BugLink: https://bugs.launchpad.net/bugs/1831258 Cc: Dimitri John Ledkov Cc: Scott Moser Signed-off-by: Christian Brauner --- src/lxc/Makefile.am | 4 +- src/lxc/conf.c | 55 +++++++++++++++++ src/lxc/uuid.c | 146 ++++++++++++++++++++++++++++++++++++++++++++ src/lxc/uuid.h | 44 +++++++++++++ 4 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/lxc/uuid.c create mode 100644 src/lxc/uuid.h diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am index b868d530e..49b3b014d 100644 --- a/src/lxc/Makefile.am +++ b/src/lxc/Makefile.am @@ -45,7 +45,8 @@ noinst_HEADERS = api_extensions.h \ ../tests/lxctest.h \ tools/arguments.h \ storage/storage_utils.h \ - utils.h + utils.h \ + uuid.h if IS_BIONIC noinst_HEADERS += ../include/fexecve.h \ @@ -143,6 +144,7 @@ liblxc_la_SOURCES = af_unix.c af_unix.h \ syscall_wrappers.h \ terminal.c \ utils.c utils.h \ + uuid.c uuid.h \ version.h \ $(LSM_SOURCES) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 0fbbbfa79..a72900529 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -79,6 +79,7 @@ #include "syscall_wrappers.h" #include "terminal.h" #include "utils.h" +#include "uuid.h" #ifdef MAJOR_IN_MKDEV #include @@ -3488,6 +3489,56 @@ static bool execveat_supported(void) return true; } +static int lxc_setup_boot_id(void) +{ + int ret; + const char *boot_id_path = "/proc/sys/kernel/random/boot_id"; + const char *mock_boot_id_path = "/dev/.lxc-boot-id"; + lxc_id128_t n; + + if (access(boot_id_path, F_OK)) + return 0; + + memset(&n, 0, sizeof(n)); + if (lxc_id128_randomize(&n)) { + SYSERROR("Failed to generate random data for uuid"); + return -1; + } + + ret = lxc_id128_write(mock_boot_id_path, n); + if (ret < 0) { + SYSERROR("Failed to write uuid to %s", mock_boot_id_path); + return -1; + } + + ret = chmod(mock_boot_id_path, 0444); + if (ret < 0) { + SYSERROR("Failed to chown %s", mock_boot_id_path); + (void)unlink(mock_boot_id_path); + return -1; + } + + ret = mount(mock_boot_id_path, boot_id_path, NULL, MS_BIND, NULL); + if (ret < 0) { + SYSERROR("Failed to mount %s to %s", mock_boot_id_path, + boot_id_path); + (void)unlink(mock_boot_id_path); + return -1; + } + + ret = mount(NULL, boot_id_path, NULL, + (MS_BIND | MS_REMOUNT | MS_RDONLY | MS_NOSUID | MS_NOEXEC | + MS_NODEV), + NULL); + if (ret < 0) { + SYSERROR("Failed to remount %s read-only", boot_id_path); + (void)unlink(mock_boot_id_path); + return -1; + } + + return 0; +} + int lxc_setup(struct lxc_handler *handler) { int ret; @@ -3645,6 +3696,10 @@ int lxc_setup(struct lxc_handler *handler) return -1; } + /* Setting the boot-id is best-effort for now. */ + if (lxc_conf->autodev > 0) + (void)lxc_setup_boot_id(); + ret = lxc_setup_devpts(lxc_conf); if (ret < 0) { ERROR("Failed to setup new devpts instance"); diff --git a/src/lxc/uuid.c b/src/lxc/uuid.c new file mode 100644 index 000000000..567304a02 --- /dev/null +++ b/src/lxc/uuid.c @@ -0,0 +1,146 @@ +/* liblxcapi + * + * Copyright © 2019 Christian Brauner . + * Copyright © 2019 Canonical Ltd. + * + * 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 License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Stolen and reworked from systemd. + */ + +#define _GNU_SOURCE +#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "file_utils.h" +#include "memory_utils.h" +#include "uuid.h" + +static lxc_id128_t make_v4_uuid(lxc_id128_t id) +{ + /* Stolen from generate_random_uuid() of drivers/char/random.c + * in the kernel sources */ + + /* Set UUID version to 4 --- truly random generation */ + id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; + + /* Set the UUID variant to DCE */ + id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; + + return id; +} + +static int get_random_bytes(void *p, size_t n) +{ + __do_close_prot_errno int fd = -1; + ssize_t bytes = 0; + + fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOCTTY); + if (fd < 0) + return -1; + + bytes = read(fd, p, n); + if (bytes != n) + return -1; + + return 0; +} + +int lxc_id128_randomize(lxc_id128_t *ret) +{ + lxc_id128_t t; + int r; + + /* We allow usage if x86-64 RDRAND here. It might not be trusted enough + * for keeping secrets, but it should be fine for UUIDS. */ + r = get_random_bytes(&t, sizeof(t)); + if (r < 0) + return r; + + /* Turn this into a valid v4 UUID, to be nice. Note that we + * only guarantee this for newly generated UUIDs, not for + * pre-existing ones. */ + + *ret = make_v4_uuid(t); + return 0; +} + +static char hexchar(int x) +{ + static const char table[16] = "0123456789abcdef"; + + return table[x & 15]; +} + +char *id128_to_uuid_string(lxc_id128_t id, char s[37]) +{ + unsigned n, k = 0; + + for (n = 0; n < 16; n++) { + + if (n == 4 || n == 6 || n == 8 || n == 10) + s[k++] = '-'; + + s[k++] = hexchar(id.bytes[n] >> 4); + s[k++] = hexchar(id.bytes[n] & 0xF); + } + + s[k] = 0; + + return s; +} + +int lxc_id128_write_fd(int fd, lxc_id128_t id) +{ + char buffer[36 + 2]; + size_t sz; + int ret; + + id128_to_uuid_string(id, buffer); + buffer[36] = '\n'; + sz = 37; + + ret = lxc_write_nointr(fd, buffer, sz); + if (ret < 0) + return -1; + + return 0; +} + +int lxc_id128_write(const char *p, lxc_id128_t id) +{ + int fd = -1; + + fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444); + if (fd < 0) + return -1; + + return lxc_id128_write_fd(fd, id); +} diff --git a/src/lxc/uuid.h b/src/lxc/uuid.h new file mode 100644 index 000000000..c9b04a3bf --- /dev/null +++ b/src/lxc/uuid.h @@ -0,0 +1,44 @@ +/* liblxcapi + * + * Copyright © 2019 Christian Brauner . + * Copyright © 2019 Canonical Ltd. + * + * 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 License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Stolen and reworked from systemd. + */ + +#ifndef __LXC_UUID_H +#define __LXC_UUID_H + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif +#define __STDC_FORMAT_MACROS +#include + +typedef union lxc_id128 lxc_id128_t; + +union lxc_id128 { + uint8_t bytes[16]; + uint64_t qwords[2]; +} +; +extern int lxc_id128_randomize(lxc_id128_t *ret); +extern int lxc_id128_write(const char *p, lxc_id128_t id); +extern int lxc_id128_write_fd(int fd, lxc_id128_t id); +extern char *id128_to_uuid_string(lxc_id128_t id, char s[37]); + +#endif /* __LXC_UUID_H */