From 5d160e2a5a71f3ba7426c68271810e1e697ff4a8 Mon Sep 17 00:00:00 2001 From: Jake Chacko Date: Sat, 29 Nov 2025 16:19:12 -0600 Subject: [PATCH 1/8] meson: add meson option for running doxygen in build Co-developed-by: Jake Chacko Co-developed-by: Rahik Sikder Signed-off-by: Jake Chacko --- doc/meson.build | 13 +++++++++++++ meson.build | 7 +++++++ meson_options.txt | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/doc/meson.build b/doc/meson.build index 2932314d9f..79d52fecc2 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -72,3 +72,16 @@ if want_mans install_dir: join_paths(mandir, 'man' + page[1])) endforeach endif + +# API Docs (Doxygen) +if want_api_docs + doxygen = find_program('doxygen', required: true) + + api_docs = custom_target( + 'api-docs', + input: files('api/Doxyfile'), + output: 'api-docs.stamp', + command: [doxygen, '@INPUT@'], + build_by_default: true + ) +endif \ No newline at end of file diff --git a/meson.build b/meson.build index 4b3a8f07f1..40973279e7 100644 --- a/meson.build +++ b/meson.build @@ -133,6 +133,7 @@ want_install_init = get_option('install-init-files') want_io_uring = get_option('io-uring-event-loop') want_pam_cgroup = get_option('pam-cgroup') want_mans = get_option('man') +want_api_docs = get_option('api-docs') want_tests = get_option('tests') want_tools = get_option('tools') want_tools_multicall = get_option('tools-multicall') @@ -341,6 +342,12 @@ if not sgml2man.found() endif endif +## API Docs. +doxygen = find_program('doxygen', required: false) +if not doxygen.found() and want_api_docs + error('missing required doxygen dependency') +endif + ## Threads. threads = dependency('threads') liblxc_dependencies += threads diff --git a/meson_options.txt b/meson_options.txt index f00e7406da..f93ab1f607 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -31,6 +31,10 @@ option('io-uring-event-loop', type: 'boolean', value: false, option('man', type: 'boolean', value: true, description: 'build and install manpages') +# was --{disable,enable}-api-docs in autotools +option('api-docs', type: 'boolean', value: false, + description: 'build and install API documentation (Doxygen)') + # was --{disable,enable}-pam in autotools option('pam-cgroup', type: 'boolean', value: false, description: 'build and install the pam cgroup module') From 1090d85dfcdfd08c0847deb1ecc5acbf01856598 Mon Sep 17 00:00:00 2001 From: Rahik-Sikder Date: Tue, 9 Dec 2025 16:12:25 -0600 Subject: [PATCH 2/8] added "--rbduser" option in "lxc-create -B rbd" Co-developed-by: Rahik Sikder Co-developed-by: Jake Chacko Signed-off-by: Rahik-Sikder --- src/lxc/initutils.c | 1 + src/lxc/initutils.h | 1 + src/lxc/lxccontainer.h | 1 + src/lxc/storage/rbd.c | 40 +++++++++++++++++++++++++++++++++----- src/lxc/tools/arguments.h | 2 +- src/lxc/tools/lxc_create.c | 11 ++++++++++- 6 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/lxc/initutils.c b/src/lxc/initutils.c index 2081692475..181f5841c2 100644 --- a/src/lxc/initutils.c +++ b/src/lxc/initutils.c @@ -49,6 +49,7 @@ const char *lxc_global_config_value(const char *option_name) { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL }, { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT }, { "lxc.bdev.rbd.rbdpool", DEFAULT_RBDPOOL }, + { "lxc.bdev.rbd.rbduser", DEFAULT_RBDUSER }, { "lxc.lxcpath", NULL }, { "lxc.default_config", NULL }, { "lxc.cgroup.pattern", NULL }, diff --git a/src/lxc/initutils.h b/src/lxc/initutils.h index 2e749063f0..6ae0997ace 100644 --- a/src/lxc/initutils.h +++ b/src/lxc/initutils.h @@ -25,6 +25,7 @@ #define DEFAULT_THIN_POOL "lxc" #define DEFAULT_ZFSROOT "lxc" #define DEFAULT_RBDPOOL "lxc" +#define DEFAULT_RBDUSER NULL #ifndef PR_SET_MM #define PR_SET_MM 35 diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 2d90fe8d8e..ee94840bfe 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -936,6 +936,7 @@ struct bdev_specs { struct { char *rbdname; /*!< RBD image name */ char *rbdpool; /*!< Ceph pool name */ + char *rbduser; /*!< Ceph user name*/ } rbd; }; diff --git a/src/lxc/storage/rbd.c b/src/lxc/storage/rbd.c index c6d8204658..50227f48fa 100644 --- a/src/lxc/storage/rbd.c +++ b/src/lxc/storage/rbd.c @@ -22,6 +22,7 @@ lxc_log_define(rbd, lxc); struct rbd_args { const char *osd_pool_name; + const char *rbd_user; const char *rbd_name; const char *size; }; @@ -30,8 +31,14 @@ static int rbd_create_wrapper(void *data) { struct rbd_args *args = data; - execlp("rbd", "rbd", "create", "--pool", args->osd_pool_name, + if (args->rbd_user){ + execlp("rbd", "rbd", "create", "--id", args->rbd_user, "--pool", + args->osd_pool_name, args->rbd_name, "--size", args->size, + (char *)NULL); + } else { + execlp("rbd", "rbd", "create", "--pool", args->osd_pool_name, args->rbd_name, "--size", args->size, (char *)NULL); + } return -1; } @@ -40,9 +47,13 @@ static int rbd_map_wrapper(void *data) { struct rbd_args *args = data; - execlp("rbd", "rbd", "map", "--pool", args->osd_pool_name, + if (args->rbd_user){ + execlp("rbd", "rbd", "map", "--id", args->rbd_user, "--pool", + args->osd_pool_name, args->rbd_name, (char *)NULL); + } else { + execlp("rbd", "rbd", "map", "--pool", args->osd_pool_name, args->rbd_name, (char *)NULL); - + } return -1; } @@ -50,7 +61,13 @@ static int rbd_unmap_wrapper(void *data) { struct rbd_args *args = data; - execlp("rbd", "rbd", "unmap", args->rbd_name, (char *)NULL); + if (args->rbd_user){ + execlp("rbd", "rbd", "unmap", "--id", args->rbd_user, args->rbd_name, + (char *)NULL); + } else { + execlp("rbd", "rbd", "unmap", args->rbd_name, (char *)NULL); + } + return -1; } @@ -59,7 +76,12 @@ static int rbd_delete_wrapper(void *data) { struct rbd_args *args = data; - execlp("rbd", "rbd", "rm", args->rbd_name, (char *)NULL); + if (args->rbd_user){ + execlp("rbd", "rbd", "rm", "--id", args->rbd_user, args->rbd_name, + (char *)NULL); + } else { + execlp("rbd", "rbd", "rm", args->rbd_name, (char *)NULL); + } return -1; } @@ -83,6 +105,7 @@ int rbd_create(struct lxc_storage *bdev, const char *dest, const char *n, const char *cmd_args[2]; char cmd_output[PATH_MAX]; const char *rbdname = n; + const char *rbduser; struct rbd_args args = {0}; if (!specs) @@ -94,6 +117,10 @@ int rbd_create(struct lxc_storage *bdev, const char *dest, const char *n, if (specs->rbd.rbdname) rbdname = specs->rbd.rbdname; + + rbduser = specs->rbd.rbduser; + if (!rbduser) + rbduser = lxc_global_config_value("lxc.bdev.rbd.rbduser"); /* source device /dev/rbd/lxc/ctn */ len = strlen(rbdpool) + strlen(rbdname) + 4 + 11; @@ -123,6 +150,7 @@ int rbd_create(struct lxc_storage *bdev, const char *dest, const char *n, args.osd_pool_name = rbdpool; args.rbd_name = rbdname; + args.rbd_user = rbduser; args.size = sz; ret = run_command(cmd_output, sizeof(cmd_output), rbd_create_wrapper, (void *)&args); @@ -179,6 +207,8 @@ int rbd_destroy(struct lxc_storage *orig) struct rbd_args args = {0}; size_t len; + args.rbd_user = lxc_global_config_value("lxc.bdev.rbd.rbduser"); + src = lxc_storage_get_path(orig->src, orig->type); if (file_exists(src)) { args.rbd_name = src; diff --git a/src/lxc/tools/arguments.h b/src/lxc/tools/arguments.h index 92510ecbca..3c9ae4365b 100644 --- a/src/lxc/tools/arguments.h +++ b/src/lxc/tools/arguments.h @@ -73,7 +73,7 @@ struct lxc_arguments { char *fstype; uint64_t fssize; char *lvname, *vgname, *thinpool; - char *rbdname, *rbdpool; + char *rbdname, *rbdpool, *rbduser; char *zfsroot, *lowerdir, *dir; /* lxc-execute and lxc-unshare */ diff --git a/src/lxc/tools/lxc_create.c b/src/lxc/tools/lxc_create.c index 41756078c6..15d8b10427 100644 --- a/src/lxc/tools/lxc_create.c +++ b/src/lxc/tools/lxc_create.c @@ -36,6 +36,7 @@ static const struct option my_longopts[] = { {"dir", required_argument, 0, '6'}, {"rbdname", required_argument, 0, '7'}, {"rbdpool", required_argument, 0, '8'}, + {"rbduser", required_argument, 0, '9'}, LXC_COMMON_OPTIONS }; @@ -67,6 +68,8 @@ Options :\n\ (Default: container name)\n\ --rbdpool=POOL Use Ceph RBD pool name POOL\n\ (Default: lxc)\n\ + --rbduser=RBDUSER Use Ceph user RBDUSER for auth\n\ + (Default: admin)\n\ \n\ BDEV option for ZFS (with -B/--bdev zfs) :\n\ --zfsroot=PATH Create zfs under given zfsroot\n\ @@ -128,6 +131,9 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg) case '8': args->rbdpool = arg; break; + case '9': + args->rbduser = arg; + break; } return 0; } @@ -175,7 +181,7 @@ static bool validate_bdev_args(struct lxc_arguments *args) } if (strncmp(args->bdevtype, "rbd", strlen(args->bdevtype)) != 0) - if (args->rbdname || args->rbdpool) { + if (args->rbdname || args->rbdpool ) { ERROR("--rbdname and --rbdpool are only valid with -B rbd"); return false; } @@ -303,6 +309,9 @@ int lxc_create_main(int argc, char *argv[]) if (my_args.rbdpool) spec.rbd.rbdpool = my_args.rbdpool; + + if(my_args.rbduser) + spec.rbd.rbduser = my_args.rbduser; } if (my_args.dir) From 9799ebacc67fbe01b5097c8b7991c49c128d2461 Mon Sep 17 00:00:00 2001 From: Rahik-Sikder Date: Thu, 11 Dec 2025 15:14:36 -0600 Subject: [PATCH 3/8] added doc for --rbduser Signed-off-by: Rahik-Sikder --- doc/lxc-create.sgml.in | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/lxc-create.sgml.in b/doc/lxc-create.sgml.in index 5ad6c7f29f..28b1820e6f 100644 --- a/doc/lxc-create.sgml.in +++ b/doc/lxc-create.sgml.in @@ -139,6 +139,7 @@ You can specify the following options : --rbdname RBDNAME will create a blockdevice named RBDNAME rather than the default, which is the container name. --rbdpool POOL will create the blockdevice in the pool named POOL, rather than the default, which is 'lxc'. + --rbduser RBDUSER will specify the ceph user RBDUSER creating the blockdevice, rather than the default, which is 'admin'. If backingstore is 'best', then lxc will try, in order, btrfs, From f085a8cbd16ea20279220858887a9df9c4a9fc33 Mon Sep 17 00:00:00 2001 From: Jake Chacko Date: Mon, 1 Dec 2025 20:47:53 -0600 Subject: [PATCH 4/8] Added documentation on unprivileged LXC containers Co-developed-by: Jake Chacko Co-developed-by: Rahik Sikder Signed-off-by: Jake Chacko --- doc/lxc.sgml.in | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/lxc.sgml.in b/doc/lxc.sgml.in index f4c5848ff3..4505db806c 100644 --- a/doc/lxc.sgml.in +++ b/doc/lxc.sgml.in @@ -206,6 +206,21 @@ rootfs + + Unprivileged containers + + Unprivileged LXC containers run without root host-level privileges in a + user namespace, mapping container UID 0 to a non-root host ID, which + strictly limits the accessible devices and filesystems of the + container. In order to mount a rootfs in an unprivileged container, the + mapped host user must have execute permissions for all directories + along the path to and including the rootfs. Additionally, all files and + directories under the rootfs must be owned by the correct user ID and + group ID. The correct user ID and group ID are the host IDs mapped to + the container root(UID 0) in lxc.idmap. + + + Creating / Destroying containers From af691a1fa9585ae3fdcbc6b7e84edf533fa3c2aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:03:44 +0000 Subject: [PATCH 5/8] build(deps): bump actions/upload-artifact from 5 to 6 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/builds.yml | 2 +- .github/workflows/fuzzing.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 3344479e37..81eb6ef472 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -85,7 +85,7 @@ jobs: mv ../lxc_* out/ - name: Upload resulting build - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 continue-on-error: true with: name: ${{ matrix.os }} diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml index d221dcfd16..efd074feb9 100644 --- a/.github/workflows/fuzzing.yml +++ b/.github/workflows/fuzzing.yml @@ -37,7 +37,7 @@ jobs: sanitizer: ${{ matrix.sanitizer }} - name: Upload Crash - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 if: failure() && steps.build.outcome == 'success' with: name: ${{ matrix.sanitizer }}-artifacts From e6ad17a796ae056337744980fb0719607a6be985 Mon Sep 17 00:00:00 2001 From: Filip Schauer Date: Mon, 15 Dec 2025 15:59:31 +0100 Subject: [PATCH 6/8] start: Remove outdated comment about group dropping Commit b58214ac30bd (tree-wide: improve setgroups() dropping) moved the group dropping code to occur before lxc_switch_uid_gid. Therefore this comment is no longer correct. Signed-off-by: Filip Schauer --- src/lxc/start.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lxc/start.c b/src/lxc/start.c index 9311d61452..4927faf952 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1307,9 +1307,6 @@ static int do_start(void *data) if (!handler->conf->root_nsgid_map) nsgid = handler->conf->init_gid; - /* Drop groups only after we switched to a valid gid in the new - * user namespace. - */ if (!lxc_drop_groups() && (handler->am_root || errno != EPERM)) goto out_warn_father; From 9e6caeabec77471c46a629ad5a5a6586ff31e9ce Mon Sep 17 00:00:00 2001 From: Filip Schauer Date: Mon, 15 Dec 2025 16:03:43 +0100 Subject: [PATCH 7/8] start: Respect lxc.init.groups also in new user namespace Fix supplementary groups defined in 'lxc.init.groups' being ignored when the container uses a new user namespace. In other words: Fix lxc.init.groups for unprivileged containers. Signed-off-by: Filip Schauer --- src/lxc/start.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lxc/start.c b/src/lxc/start.c index 4927faf952..b5ca683dbd 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1603,17 +1603,19 @@ static int do_start(void *data) if (lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE)) #endif { - if (handler->conf->init_groups.size > 0) { - if (!lxc_setgroups(handler->conf->init_groups.list, - handler->conf->init_groups.size)) - goto out_warn_father; - } else { + if (handler->conf->init_groups.size == 0) { if (!lxc_drop_groups()) goto out_warn_father; } } } + if (handler->conf->init_groups.size > 0) { + if (!lxc_setgroups(handler->conf->init_groups.list, + handler->conf->init_groups.size)) + goto out_warn_father; + } + if (!lxc_switch_uid_gid(new_uid, new_gid)) goto out_warn_father; From 49c34b1bcd72c602953ab9c4cb60bc4f2ebcf653 Mon Sep 17 00:00:00 2001 From: jamesfeatherston Date: Sat, 13 Dec 2025 18:49:57 -0600 Subject: [PATCH 8/8] copy_rdepends: Don't fail on missing source file Signed-off-by: jamesfeatherston --- src/lxc/lxccontainer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 6f110ea3b7..ea3a31bb4a 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -3468,6 +3468,10 @@ static void copy_rdepends(struct lxc_container *c, struct lxc_container *c0) return; } + if (!file_exists(path0)) { + return; + } + if (copy_file(path0, path1) < 0) { INFO("Error copying reverse dependencies"); return;