Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package lxcfs for openSUSE:Factory checked in at 2024-07-16 22:03:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/lxcfs (Old) and /work/SRC/openSUSE:Factory/.lxcfs.new.17339 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "lxcfs" Tue Jul 16 22:03:03 2024 rev:23 rq:1187672 version:6.0.1 Changes: -------- --- /work/SRC/openSUSE:Factory/lxcfs/lxcfs.changes 2024-05-01 14:58:14.177792125 +0200 +++ /work/SRC/openSUSE:Factory/.lxcfs.new.17339/lxcfs.changes 2024-07-16 22:03:10.939529509 +0200 @@ -1,0 +2,21 @@ +Sat Jul 13 10:58:47 UTC 2024 - Johannes Kastl <[email protected]> + +- update to 6.0.1 LTS: + * Some of the highlights for this release are: + - Support for running multiple instances of LXCFS + (--runtime-dir) + - Detect systems that has a Yama policy preventing reading + process personalities + * Detailed changelog + - github: add lxcfs live upgrade compatibility test + - proc: checks system security policy before trying to get + personalities + - lxcfs/bindings: Refactor RUNTIME_PATH so that it can be + overridden on startup + - lxcfs/bindings: add a flag for overriding the runtime dir + - github: update coverity test to use Ubuntu 22.04 + - README.md: add info about how to collect a core dump + - github: add ISSUE_TEMPLATE.md + - tests: Update for multiple runtime paths + +------------------------------------------------------------------- Old: ---- lxcfs-6.0.0.tar.gz lxcfs-6.0.0.tar.gz.asc New: ---- lxcfs-6.0.1.tar.gz lxcfs-6.0.1.tar.gz.asc ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ lxcfs.spec ++++++ --- /var/tmp/diff_new_pack.n4xlnd/_old 2024-07-16 22:03:11.527550955 +0200 +++ /var/tmp/diff_new_pack.n4xlnd/_new 2024-07-16 22:03:11.527550955 +0200 @@ -22,7 +22,7 @@ %endif Name: lxcfs -Version: 6.0.0 +Version: 6.0.1 Release: 0 Summary: FUSE filesystem for LXC License: Apache-2.0 ++++++ lxcfs-6.0.0.tar.gz -> lxcfs-6.0.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/.github/ISSUE_TEMPLATE.md new/lxcfs-6.0.1/.github/ISSUE_TEMPLATE.md --- old/lxcfs-6.0.0/.github/ISSUE_TEMPLATE.md 1970-01-01 01:00:00.000000000 +0100 +++ new/lxcfs-6.0.1/.github/ISSUE_TEMPLATE.md 2024-06-26 04:31:57.000000000 +0200 @@ -0,0 +1,32 @@ +The template below is mostly useful for bug reports and support questions. +Feel free to remove anything which doesn't apply to you and add more information where it makes sense. + +# Required information + + * Distribution: + * `cat /etc/os-release` or `cat /etc/lsb-release` + * LXCFS version: + * The output of + * `uname -a` + * `cat /proc/1/mounts` + * `ps aux | grep lxcfs` + * LXCFS logs + +# Issue description + +A brief description of what failed or what could be improved. + +If you have LXCFS crashing, please, collect a crash dump. + +# Steps to reproduce + + 1. Step one + 2. Step two + 3. Step three + +# Information to attach + + - [ ] any relevant kernel output (`dmesg`) + - [ ] LXCFS daemon output / logs + - [ ] LXCFS configuration (Which options were used to start a LXCFS daemon? `ps aux | grep lxcfs`) + - [ ] in case of crash, a core dump (please, read [how to collect a core dump](https://github.com/lxc/lxcfs?tab=readme-ov-file#core-dump)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/.github/workflows/builds.yml new/lxcfs-6.0.1/.github/workflows/builds.yml --- old/lxcfs-6.0.0/.github/workflows/builds.yml 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/.github/workflows/builds.yml 2024-06-26 04:31:57.000000000 +0200 @@ -10,7 +10,7 @@ jobs: coverity: name: Coverity - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout code uses: actions/checkout@v2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/.github/workflows/tests.yml new/lxcfs-6.0.1/.github/workflows/tests.yml --- old/lxcfs-6.0.0/.github/workflows/tests.yml 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/.github/workflows/tests.yml 2024-06-26 04:31:57.000000000 +0200 @@ -93,3 +93,66 @@ run: | echo 1 | sudo tee /sys/fs/cgroup/cpuset/cgroup.clone_children || true sudo -E PATH="${PATH}" LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" build/tests/main.sh + + live-upgrade-compatibility: + name: Live upgrade test + strategy: + fail-fast: false + matrix: + compiler: + - gcc + - clang + os: + - ubuntu-22.04 + runs-on: ${{ matrix.os }} + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install dependencies + run: | + sudo add-apt-repository universe + sudo apt-get update -qq + sudo apt-get install -qq gcc clang + sudo apt-get install -qq libfuse3-dev uuid-runtime + sudo apt-get install -qq python3 python3-setuptools + sudo pip3 install meson==0.55.1 ninja + + - name: Compiler version + env: + CC: ${{ matrix.compiler }} + run: | + ${CC} --version + + - name: Build PR head version + env: + CC: ${{ matrix.compiler }} + run: | + meson setup -Ddocs=false -Dtests=true -Dinit-script=systemd -Dprefix=/usr -Db_sanitize=address,undefined build/ + meson compile -C build + + - name: Build upstream head version + env: + CC: ${{ matrix.compiler }} + run: | + git clone -b stable-6.0 https://github.com/lxc/lxcfs.git ../upstream-lxcfs + cd ../upstream-lxcfs + meson setup -Ddocs=false -Dtests=true -Dinit-script=systemd -Dprefix=/usr -Db_sanitize=address,undefined build/ + meson compile -C build + + - name: Test + env: + CC: ${{ matrix.compiler }} + WORKSPACE_PATH: ${{ github.workspace }} + run: | + UPSTREAM_LXCFS_TREE=$(realpath ${WORKSPACE_PATH}/../upstream-lxcfs) + NEW_LXCFS_TREE="${WORKSPACE_PATH}" + + echo "${NEW_LXCFS_TREE}" + echo "${UPSTREAM_LXCFS_TREE}" + + cd $UPSTREAM_LXCFS_TREE + [ -f build/tests/live-upgrade-test.sh ] || exit 0 + + echo 1 | sudo tee /sys/fs/cgroup/cpuset/cgroup.clone_children || true + sudo -E PATH="${PATH}" LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" build/tests/live-upgrade-test.sh "${NEW_LXCFS_TREE}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/README.md new/lxcfs-6.0.1/README.md --- old/lxcfs-6.0.0/README.md 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/README.md 2024-06-26 04:31:57.000000000 +0200 @@ -98,7 +98,7 @@ lxc.include = /usr/share/lxc/config/common.conf.d/00-lxcfs.conf ``` -## Using with Docker +### Using with Docker ``` docker run -it -m 256m --memory-swap 256m \ @@ -163,3 +163,29 @@ usage (100% full) is reported. This provides adequate reporting of the memory consumption while preventing applications from assuming more SWAP is available. + +## Issue reporting + +### Core dump + +In case of LXCFS crash, it can be extremely useful for us to have a core dump of the LXCFS process memory. + +1. Please, check `/var/crash` and `coredumpctl list` just in case if you already have an LXCFS core dump file +2. If not, you can use the following way to collect it from your system: + +On the machine where you run LXCFS, execute as root: +``` +# save an old core_pattern setting value: +cat /proc/sys/kernel/core_pattern > /root/core_pattern.old_value.bak + +# set a new one to collect all core dumps: +echo '|/bin/sh -c $@ -- eval exec gzip --fast > /var/crash/core-%e.%p.gz' > /proc/sys/kernel/core_pattern + +# wait for the next LXCFS crash and check +ls -lah /var/crash + +# there should be a file with a name like "core-lxcfs.80581.gz". Please, upload it somewhere and share with us. + +# restore the old "core_pattern" value: +cat /root/core_pattern.old_value.bak > /proc/sys/kernel/core_pattern +``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/meson.build new/lxcfs-6.0.1/meson.build --- old/lxcfs-6.0.0/meson.build 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/meson.build 2024-06-26 04:31:57.000000000 +0200 @@ -4,7 +4,7 @@ project( 'lxcfs', 'c', - version: '6.0.0', + version: '6.0.1', license: 'LGPLv2+', default_options: [ 'b_colorout=always', @@ -57,7 +57,7 @@ conf.set_quoted('BINDIR', bindir) conf.set_quoted('LIBDIR', libdir) conf.set_quoted('LOCALSTATEDIR', localstatedir) -conf.set_quoted('RUNTIME_PATH', runtimepath) +conf.set_quoted('DEFAULT_RUNTIME_PATH', runtimepath) conf.set_quoted('SYSCONFDIR', sysconfdir) conf.set_quoted('LXCCONFDIR', lxcconfdir) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/src/bindings.c new/lxcfs-6.0.1/src/bindings.c --- old/lxcfs-6.0.0/src/bindings.c 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/src/bindings.c 2024-06-26 04:31:57.000000000 +0200 @@ -7,6 +7,7 @@ #include <fcntl.h> #include <inttypes.h> #include <libgen.h> +#include <linux/limits.h> #include <linux/magic.h> #include <linux/sched.h> #include <pthread.h> @@ -40,15 +41,32 @@ #include "syscall_numbers.h" #include "utils.h" +/* directory under which we mount the controllers - /run/lxcfs/controllers */ +#define BASEDIR "/lxcfs/controllers" +#define ROOTDIR "/lxcfs/root" + static bool can_use_pidfd; static bool can_use_swap; static bool can_use_sys_cpu; static bool has_versioned_opts; static bool memory_is_cgroupv2; static __u32 host_personality; +static char runtime_path[PATH_MAX] = DEFAULT_RUNTIME_PATH; + static volatile sig_atomic_t reload_successful; + +static char *get_base_dir(void) +{ + return must_make_path(runtime_path, BASEDIR, NULL); +} + +static char *get_root_dir(void) +{ + return must_make_path(runtime_path, ROOTDIR, NULL); +} + bool liblxcfs_functional(void) { return reload_successful != 0; @@ -580,8 +598,9 @@ static bool umount_if_mounted(void) { - if (umount2(BASEDIR, MNT_DETACH) < 0 && errno != EINVAL) { - lxcfs_error("Failed to unmount %s: %s.\n", BASEDIR, strerror(errno)); + __do_free char *base_dir = get_base_dir(); + if (umount2(base_dir, MNT_DETACH) < 0 && errno != EINVAL) { + lxcfs_error("Failed to unmount %s: %s.\n", base_dir, strerror(errno)); return false; } return true; @@ -639,13 +658,14 @@ static int pivot_enter(void) { __do_close int oldroot = -EBADF, newroot = -EBADF; + __do_free char *root_dir = get_root_dir(); oldroot = open("/", O_DIRECTORY | O_RDONLY | O_CLOEXEC); if (oldroot < 0) return log_error_errno(-1, errno, "Failed to open old root for fchdir"); - newroot = open(ROOTDIR, O_DIRECTORY | O_RDONLY | O_CLOEXEC); + newroot = open(root_dir, O_DIRECTORY | O_RDONLY | O_CLOEXEC); if (newroot < 0) return log_error_errno(-1, errno, "Failed to open new root for fchdir"); @@ -654,7 +674,7 @@ if (fchdir(newroot) < 0) return log_error_errno(-1, errno, "Failed to change directory to new rootfs: %s", - ROOTDIR); + root_dir); /* pivot_root into our new root fs */ if (pivot_root(".", ".") < 0) @@ -681,8 +701,10 @@ static int chroot_enter(void) { - if (mount(ROOTDIR, "/", NULL, MS_REC | MS_BIND, NULL)) { - lxcfs_error("Failed to recursively bind-mount %s into /.", ROOTDIR); + __do_free char *root_dir = get_root_dir(); + + if (mount(root_dir, "/", NULL, MS_REC | MS_BIND, NULL)) { + lxcfs_error("Failed to recursively bind-mount %s into /.", root_dir); return -1; } @@ -725,23 +747,33 @@ /* Prepare our new clean root. */ static int permute_prepare(void) { - if (mkdir(ROOTDIR, 0700) < 0 && errno != EEXIST) { + __do_free char *base_dir = get_base_dir(); + __do_free char *root_dir = get_root_dir(); + __do_free char *new_runtime = must_make_path(root_dir, runtime_path, NULL); + __do_free char *new_base_dir = must_make_path(root_dir, base_dir, NULL); + + if (mkdir(root_dir, 0700) < 0 && errno != EEXIST) { lxcfs_error("%s\n", "Failed to create directory for new root."); return -1; } - if (mount("/", ROOTDIR, NULL, MS_BIND, 0) < 0) { + if (mount("/", root_dir, NULL, MS_BIND, 0) < 0) { lxcfs_error("Failed to bind-mount / for new root: %s.\n", strerror(errno)); return -1; } - if (mount(RUNTIME_PATH, ROOTDIR RUNTIME_PATH, NULL, MS_BIND, 0) < 0) { - lxcfs_error("Failed to bind-mount /run into new root: %s.\n", strerror(errno)); + if (!mkdir_p(new_runtime, 0700)) { + lxcfs_error("Failed to create dir %s\n", new_runtime); + return -1; + } + + if (mount(runtime_path, new_runtime, NULL, MS_BIND, 0) < 0) { + lxcfs_error("Failed to bind-mount %s into new root: %s.\n", runtime_path, strerror(errno)); return -1; } - if (mount(BASEDIR, ROOTDIR BASEDIR, NULL, MS_REC | MS_MOVE, 0) < 0) { - printf("Failed to move " BASEDIR " into new root: %s.\n", strerror(errno)); + if (mount(base_dir, new_base_dir, NULL, MS_REC | MS_MOVE, 0) < 0) { + printf("Failed to move %s into new root: %s.\n", base_dir, strerror(errno)); return -1; } @@ -764,7 +796,9 @@ static bool cgfs_prepare_mounts(void) { - if (!mkdir_p(BASEDIR, 0700)) { + __do_free char *base_dir = get_base_dir(); + + if (!mkdir_p(base_dir, 0700)) { lxcfs_error("%s\n", "Failed to create lxcfs cgroup mountpoint."); return false; } @@ -790,7 +824,7 @@ return false; } - if (mount("tmpfs", BASEDIR, "tmpfs", 0, "size=100000,mode=700") < 0) { + if (mount("tmpfs", base_dir, "tmpfs", 0, "size=100000,mode=700") < 0) { lxcfs_error("%s\n", "Failed to mount tmpfs over lxcfs cgroup mountpoint."); return false; } @@ -800,14 +834,17 @@ static bool cgfs_mount_hierarchies(void) { - if (!mkdir_p(BASEDIR DEFAULT_CGROUP_MOUNTPOINT, 0755)) + __do_free char *base_dir = get_base_dir(); + __do_free char *base_dir_cgroup_mount = must_make_path(base_dir, DEFAULT_CGROUP_MOUNTPOINT, NULL); + + if (!mkdir_p(base_dir_cgroup_mount, 0700)) return false; - if (!cgroup_ops->mount(cgroup_ops, BASEDIR)) + if (!cgroup_ops->mount(cgroup_ops, base_dir)) return false; for (struct hierarchy **h = cgroup_ops->hierarchies; h && *h; h++) { - __do_free char *path = must_make_path(BASEDIR, (*h)->mountpoint, NULL); + __do_free char *path = must_make_path(base_dir, (*h)->mountpoint, NULL); (*h)->fd = open(path, O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW); if ((*h)->fd < 0) return false; @@ -862,7 +899,19 @@ return; } -static void __attribute__((constructor)) lxcfs_init(void) +bool set_runtime_path(const char* new_path) +{ + if (new_path && strlen(new_path) < PATH_MAX) { + strcpy(runtime_path, new_path); + lxcfs_info("Using runtime path %s", runtime_path); + return true; + } else { + lxcfs_error("%s\n", "Failed to overwrite the runtime path"); + return false; + } +} + +void lxcfslib_init(void) { __do_close int init_ns = -EBADF, root_fd = -EBADF, pidfd = -EBADF; @@ -871,7 +920,7 @@ pid_t pid; struct hierarchy *hierarchy; - lxcfs_info("Running constructor %s to reload liblxcfs", __func__); + lxcfs_info("Running %s to reload liblxcfs", __func__); cgroup_ops = cgroup_init(); if (!cgroup_ops) { @@ -971,9 +1020,20 @@ void *lxcfs_fuse_init(struct fuse_conn_info *conn, void *data) { struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = fc ? fc->private_data : NULL; + #if HAVE_FUSE_RETURNS_DT_TYPE can_use_sys_cpu = true; #endif has_versioned_opts = true; - return fc ? fc->private_data : NULL; + + // We can read runtime_path as of opts version 2. + if (opts && opts->version >= 2) { + set_runtime_path(opts->runtime_path); + } + + /* initialize the library */ + lxcfslib_init(); + + return opts; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/src/bindings.h new/lxcfs-6.0.1/src/bindings.h --- old/lxcfs-6.0.0/src/bindings.h 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/src/bindings.h 2024-06-26 04:31:57.000000000 +0200 @@ -23,10 +23,6 @@ #include "proc_loadavg.h" #include "sysfs_fuse.h" -/* directory under which we mount the controllers - /run/lxcfs/controllers */ -#define BASEDIR RUNTIME_PATH "/lxcfs/controllers" -#define ROOTDIR RUNTIME_PATH "/lxcfs/root" - /* Maximum number for 64 bit integer is a string with 21 digits: 2^64 - 1 = 21 */ #define LXCFS_NUMSTRLEN64 21 @@ -116,6 +112,8 @@ * and the use of bool instead of explicited __u32 and __u64 we can't. */ __u32 version; + // As of opts version 2. + char runtime_path[PATH_MAX]; }; typedef enum lxcfs_opt_t { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/src/lxcfs.c new/lxcfs-6.0.1/src/lxcfs.c --- old/lxcfs-6.0.0/src/lxcfs.c 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/src/lxcfs.c 2024-06-26 04:31:57.000000000 +0200 @@ -32,7 +32,11 @@ #include "macro.h" #include "memory_utils.h" +#define PID_FILE "/lxcfs.pid" + void *dlopen_handle; +static char runtime_path[PATH_MAX] = DEFAULT_RUNTIME_PATH; + /* Functions to keep track of number of threads using the library */ @@ -146,7 +150,7 @@ static volatile sig_atomic_t need_reload; -static int lxcfs_init_library(void) +static int do_lxcfs_fuse_init(void) { char *error; void *(*__lxcfs_fuse_init)(struct fuse_conn_info * conn, void * cfg); @@ -199,13 +203,12 @@ dlopen_handle = dlopen(lxcfs_lib_path, RTLD_LAZY); if (!dlopen_handle) - log_exit("%s - Failed to open liblxcfs.so", dlerror()); + log_exit("%s - Failed to open liblxcfs.so at %s", dlerror(), lxcfs_lib_path); else lxcfs_debug("Opened %s", lxcfs_lib_path); good: - /* initialize the library */ - if (reinit && lxcfs_init_library() < 0) { + if (reinit && do_lxcfs_fuse_init() < 0) { log_exit("Failed to initialize liblxcfs.so"); } @@ -1119,7 +1122,7 @@ static void *lxcfs_init(struct fuse_conn_info *conn) #endif { - if (lxcfs_init_library() < 0) + if (do_lxcfs_fuse_init() < 0) return NULL; #if HAVE_FUSE3 @@ -1187,12 +1190,14 @@ lxcfs_info(" -l, --enable-loadavg Enable loadavg virtualization"); lxcfs_info(" -o Options to pass directly through fuse"); lxcfs_info(" -p, --pidfile=FILE Path to use for storing lxcfs pid"); - lxcfs_info(" Default pidfile is %s/lxcfs.pid", RUNTIME_PATH); + lxcfs_info(" Default pidfile is %s/lxcfs.pid", DEFAULT_RUNTIME_PATH); lxcfs_info(" -u, --disable-swap Disable swap virtualization"); lxcfs_info(" -v, --version Print lxcfs version"); lxcfs_info(" --enable-cfs Enable CPU virtualization via CPU shares"); lxcfs_info(" --enable-pidfd Use pidfd for process tracking"); lxcfs_info(" --enable-cgroup Enable cgroup emulation code"); + lxcfs_info(" --runtime-dir=DIR Path to use as the runtime directory."); + lxcfs_info(" Default is %s", DEFAULT_RUNTIME_PATH); exit(EXIT_FAILURE); } @@ -1244,6 +1249,7 @@ {"enable-cgroup", no_argument, 0, 0 }, {"pidfile", required_argument, 0, 'p' }, + {"runtime-dir", required_argument, 0, 0 }, { }, }; @@ -1286,7 +1292,7 @@ int pidfile_fd = -EBADF; int ret = EXIT_FAILURE; char *pidfile = NULL, *token = NULL; - char pidfile_buf[STRLITERALLEN(RUNTIME_PATH) + STRLITERALLEN("/lxcfs.pid") + 1] = {}; + char pidfile_buf[PATH_MAX + sizeof(PID_FILE)] = {}; bool debug = false, foreground = false; #if !HAVE_FUSE3 bool nonempty = false; @@ -1303,6 +1309,7 @@ char *new_fuse_opts = NULL; char *const *new_argv; struct lxcfs_opts *opts; + char *runtime_path_arg = NULL; opts = malloc(sizeof(struct lxcfs_opts)); if (opts == NULL) { @@ -1313,7 +1320,7 @@ opts->swap_off = false; opts->use_pidfd = false; opts->use_cfs = false; - opts->version = 1; + opts->version = 2; while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) { switch (c) { @@ -1324,6 +1331,8 @@ opts->use_cfs = true; else if (strcmp(long_options[idx].name, "enable-cgroup") == 0) cgroup_is_enabled = true; + else if (strcmp(long_options[idx].name, "runtime-dir") == 0) + runtime_path_arg = optarg; else usage(); break; @@ -1376,6 +1385,12 @@ goto out; } + if (runtime_path_arg) { + strcpy(runtime_path, runtime_path_arg); + lxcfs_info("runtime path set to %s", runtime_path); + } + strcpy(opts->runtime_path, runtime_path); + fuse_argv[fuse_argc++] = argv[0]; if (debug) fuse_argv[fuse_argc++] = "-d"; @@ -1467,6 +1482,7 @@ lxcfs_info("Starting LXCFS at %s", argv[0]); do_reload(false); + if (install_signal_handler(SIGUSR1, sigusr1_reload)) { lxcfs_error("%s - Failed to install SIGUSR1 signal handler", strerror(errno)); goto out; @@ -1480,7 +1496,7 @@ #endif if (!pidfile) { - snprintf(pidfile_buf, sizeof(pidfile_buf), "%s/lxcfs.pid", RUNTIME_PATH); + snprintf(pidfile_buf, sizeof(pidfile_buf), "%s%s", runtime_path, PID_FILE); pidfile = pidfile_buf; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/src/proc_fuse.c new/lxcfs-6.0.1/src/proc_fuse.c --- old/lxcfs-6.0.0/src/proc_fuse.c 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/src/proc_fuse.c 2024-06-26 04:31:57.000000000 +0200 @@ -145,8 +145,11 @@ strcmp(path, "/proc/swaps") == 0 || strcmp(path, "/proc/loadavg") == 0 || strcmp(path, "/proc/slabinfo") == 0) { - if (liblxcfs_functional()) + if (liblxcfs_functional()) { + if (!can_access_personality()) + return log_error(-EACCES, RESTRICTED_PERSONALITY_ACCESS_POLICY); sb->st_size = get_procfile_size_with_personality(path); + } else sb->st_size = get_procfile_size(path); sb->st_mode = S_IFREG | 00444; @@ -206,8 +209,11 @@ info->type = type; - if (liblxcfs_functional()) + if (liblxcfs_functional()) { + if (!can_access_personality()) + return log_error(-EACCES, RESTRICTED_PERSONALITY_ACCESS_POLICY); info->buflen = get_procfile_size_with_personality(path) + BUF_RESERVE_SIZE; + } else info->buflen = get_procfile_size(path) + BUF_RESERVE_SIZE; @@ -1646,8 +1652,11 @@ return read_file_fuse_with_offset(LXC_TYPE_PROC_MEMINFO_PATH, buf, size, offset, f); case LXC_TYPE_PROC_CPUINFO: - if (liblxcfs_functional()) + if (liblxcfs_functional()) { + if (!can_access_personality()) + return log_error(-EACCES, RESTRICTED_PERSONALITY_ACCESS_POLICY); return proc_read_with_personality(&proc_cpuinfo_read, buf, size, offset, fi); + } return read_file_fuse_with_offset(LXC_TYPE_PROC_CPUINFO_PATH, buf, size, offset, f); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/src/utils.c new/lxcfs-6.0.1/src/utils.c --- old/lxcfs-6.0.0/src/utils.c 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/src/utils.c 2024-06-26 04:31:57.000000000 +0200 @@ -685,9 +685,31 @@ ret = read_nointr(fd, buf, sizeof(buf) - 1); if (ret >= 0) { buf[ret] = '\0'; - if (safe_uint32(buf, personality, 16) < 0) + if (personality != NULL && safe_uint32(buf, personality, 16) < 0) return log_error(-1, "Failed to convert personality %s", buf); } return ret; } + +/* + This function checks whether system security policy (i.e. Yama LSM) allows personality access, by trying on + init own one. + This is required as it may be restricted by a ptrace access mode check (see PROC(5)), and + `get_task_personality` function relies on this. +*/ +bool can_access_personality(void) +{ + static int could_access_init_personality = -1; + + /* init personality has never been accessed (cache is empty) */ + if (could_access_init_personality == -1) { + if (get_task_personality(1, NULL) < 0) { + could_access_init_personality = 0; + } else { + could_access_init_personality = 1; + } + } + + return could_access_init_personality != 0; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/src/utils.h new/lxcfs-6.0.1/src/utils.h --- old/lxcfs-6.0.0/src/utils.h 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/src/utils.h 2024-06-26 04:31:57.000000000 +0200 @@ -25,6 +25,8 @@ #define SEND_CREDS_NOTSK 1 #define SEND_CREDS_FAIL 2 +#define RESTRICTED_PERSONALITY_ACCESS_POLICY "Due to restricted personality access policy, reading proc files from containers is not permitted" + struct file_info; __attribute__((__format__(__printf__, 4, 5))) extern char *must_strcat(char **src, size_t *sz, size_t *asz, const char *format, ...); @@ -77,6 +79,7 @@ extern char *read_file_at(int dfd, const char *fnam, unsigned int o_flags); extern int get_task_personality(pid_t pid, __u32 *personality); +extern bool can_access_personality(void); extern int get_host_personality(__u32 *personality); #endif /* __LXCFS_UTILS_H */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/tests/live-upgrade-test.sh.in new/lxcfs-6.0.1/tests/live-upgrade-test.sh.in --- old/lxcfs-6.0.0/tests/live-upgrade-test.sh.in 1970-01-01 01:00:00.000000000 +0100 +++ new/lxcfs-6.0.1/tests/live-upgrade-test.sh.in 2024-06-26 04:31:57.000000000 +0200 @@ -0,0 +1,143 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1+ + +set -eu +[ -n "${DEBUG:-}" ] && set -x + +[ $(id -u) -eq 0 ] + +NEW_LXCFS_TREE=$1 + +echo "LXCFS trees:" +pwd +echo "${NEW_LXCFS_TREE}" + +# Run lxcfs testsuite +export LXCFSDIR=$(mktemp -d) +pidfile=$(mktemp) +export LXCFSPID=-1 + +cmdline=$(realpath $0) +dirname=$(dirname ${cmdline}) + +FAILED=1 +UNSHARE=1 +cleanup() { + echo "=> Cleaning up" + set +e + if [ $LXCFSPID -ne -1 ]; then + kill -9 $LXCFSPID + fi + if [ ${LXCFSDIR} != "/var/lib/lxcfs" ]; then + umount -l ${LXCFSDIR} + rmdir ${LXCFSDIR} + fi + rm -f ${pidfile} + if [ ${FAILED} -eq 1 ]; then + echo "=> FAILED at $TESTCASE" + exit 1 + fi + echo "=> PASSED" + exit 0 +} + +TESTCASE="setup" +lxcfs="{{LXCFS_BUILD_ROOT}}/lxcfs" + +if [ -x ${lxcfs} ]; then + if [ -n "${LD_LIBRARY_PATH:-}" ]; then + export LD_LIBRARY_PATH="{{LXCFS_BUILD_ROOT}}:${LD_LIBRARY_PATH}" + else + export LD_LIBRARY_PATH="{{LXCFS_BUILD_ROOT}}" + fi + echo "=> Spawning ${lxcfs} ${LXCFSDIR}" + ${lxcfs} --enable-cgroup -p ${pidfile} ${LXCFSDIR} & + LXCFSPID=$! +else + UNSHARE=0 + LXCFSPID=$(cat "{{DEFAULT_RUNTIME_PATH}}/lxcfs.pid") + echo "=> Re-using host lxcfs" + rmdir $LXCFSDIR + export LXCFSDIR=/var/lib/lxcfs +fi + +trap cleanup EXIT HUP INT TERM + +count=1 +while ! mountpoint -q $LXCFSDIR; do + sleep 1s + if [ $count -gt 5 ]; then + echo "lxcfs failed to start" + false + fi + count=$((count+1)) +done + +RUNTEST() { + echo "" + echo "=> Running ${TESTCASE}" + + if [ "${UNSHARE:-1}" != "0" ]; then + unshare -fmp --mount-proc $* + else + $* + fi +} + +RUNTESTS() { + TESTCASE="Stress readdir" + RUNTEST ${dirname}/test_readdir + TESTCASE="test_proc" + RUNTEST ${dirname}/test_proc + TESTCASE="test_cgroup" + RUNTEST ${dirname}/test_cgroup + TESTCASE="test_read_proc.sh" + RUNTEST ${dirname}/test_read_proc.sh + TESTCASE="cpusetrange" + RUNTEST ${dirname}/test-cpusetrange + TESTCASE="meminfo hierarchy" + RUNTEST ${dirname}/test_meminfo_hierarchy.sh + + TESTCASE="SIGUSR2 virtualization mode switching" + echo "==> Switching to non-virtualization mode" + kill -USR2 $LXCFSPID + RUNTEST ${dirname}/test_sigusr2.sh + echo "==> Switching to virtualization mode" + kill -USR2 $LXCFSPID +} + +echo "" +echo "=> Running tests BEFORE reload" +RUNTESTS + +TESTCASE="liblxcfs reloading (with upgrade)" + +rm -f /tmp/lxcfs-iwashere + +echo "==> Ensure that lxcfs is functional BEFORE reload" +cat ${LXCFSDIR}/proc/uptime + +libdir="{{LXCFS_BUILD_ROOT}}" + +[ ! -f /tmp/lxcfs-iwashere ] +rm -f ${libdir}/liblxcfs.so ${libdir}/liblxcfs.la +cp ${NEW_LXCFS_TREE}/build/liblxcfstest.so ${libdir}/liblxcfs.so + +echo "==> Reload liblxcfs" +kill -USR1 $LXCFSPID +sleep 1 + +echo "==> Ensure that lxcfs is functional AFTER reload" +cat ${LXCFSDIR}/proc/uptime +sleep 1 +[ -f /tmp/lxcfs-iwashere ] + +echo "" +echo "=> Running tests AFTER reload" +RUNTESTS + +# Check for any defunct processes - children we didn't reap +n=`ps -ef | grep lxcfs | grep defunct | wc -l` +[ $n = 0 ] + +FAILED=0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/tests/main.sh.in new/lxcfs-6.0.1/tests/main.sh.in --- old/lxcfs-6.0.0/tests/main.sh.in 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/tests/main.sh.in 2024-06-26 04:31:57.000000000 +0200 @@ -49,7 +49,7 @@ LXCFSPID=$! else UNSHARE=0 - LXCFSPID=$(cat "{{RUNTIME_PATH}}/lxcfs.pid") + LXCFSPID=$(cat "{{DEFAULT_RUNTIME_PATH}}/lxcfs.pid") echo "=> Re-using host lxcfs" rmdir $LXCFSDIR export LXCFSDIR=/var/lib/lxcfs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lxcfs-6.0.0/tests/meson.build new/lxcfs-6.0.1/tests/meson.build --- old/lxcfs-6.0.0/tests/meson.build 2024-03-28 03:44:27.000000000 +0100 +++ new/lxcfs-6.0.1/tests/meson.build 2024-06-26 04:31:57.000000000 +0200 @@ -13,6 +13,18 @@ ]) test_programs += custom_target( + 'live-upgrade-test.sh', + build_by_default: want_tests != false, + input: 'live-upgrade-test.sh.in', + output: 'live-upgrade-test.sh', + command: [ + meson_render_jinja2, + config_h, + '@INPUT@', + '@OUTPUT@', + ]) + +test_programs += custom_target( 'test_cgroup', build_by_default: want_tests != false, input: 'test_cgroup.in',
