From f30cbb86fff27e72ae25780aa2b90cf24937864e Mon Sep 17 00:00:00 2001 From: Emir Buljubasic Date: Fri, 29 May 2026 13:41:13 +0200 Subject: [PATCH 01/14] lxc/criu: restore cgroup limits and freezer on restore Signed-off-by: Emir Buljubasic --- src/lxc/criu.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/lxc/criu.c b/src/lxc/criu.c index 9996b888aa..d6c2c4cd65 100644 --- a/src/lxc/criu.c +++ b/src/lxc/criu.c @@ -939,6 +939,21 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_ goto out_fini_handler; } + if (!cgroup_ops->payload_delegate_controllers(cgroup_ops)) { + ERROR("Failed to delegate controllers to payload cgroup"); + goto out_fini_handler; + } + + if (!cgroup_ops->setup_limits(cgroup_ops, handler)) { + ERROR("Failed to setup cgroup limits"); + goto out_fini_handler; + } + + if (!cgroup_ops->chown(cgroup_ops, handler->conf)) + goto out_fini_handler; + + cgroup_ops->finalize(cgroup_ops); + if (!restore_net_info(c)) { ERROR("failed restoring network info"); goto out_fini_handler; From 3224f46d012a2ef2aca3790754d716f5068c3097 Mon Sep 17 00:00:00 2001 From: KATOH Yasufumi Date: Sun, 7 Jun 2026 00:48:47 +0900 Subject: [PATCH 02/14] doc: update cgroup section of lxc.container.conf(5) to reflect cgroup v1 removal Remove or rewrite descriptions that assumed cgroup v1 support, following its removal in LXC 7.0. Signed-off-by: KATOH Yasufumi --- doc/ja/lxc.container.conf.sgml.in | 132 +++++++++++------------------- doc/lxc.container.conf.sgml.in | 111 ++++++++----------------- 2 files changed, 84 insertions(+), 159 deletions(-) diff --git a/doc/ja/lxc.container.conf.sgml.in b/doc/ja/lxc.container.conf.sgml.in index 9e04085d30..40b5d5dee9 100644 --- a/doc/ja/lxc.container.conf.sgml.in +++ b/doc/ja/lxc.container.conf.sgml.in @@ -2069,27 +2069,20 @@ explanation of the differences between the two versions. --> カーネルにおける cgroup 実装は長年にわたって大きく変化してきました。 - Linux 4.5 で新しい cgroup ファイルシステムのサポートが追加されました。通常は "cgroup2" や "unified hierarchy"(単一階層構造) と呼ばれています。 - それ以来、通常は古い cgroup ファイルシステムは "cgroup1" や "legacy hierarchies"(レガシー階層構造)と呼ばれています。 + Linux 4.5 で新しい cgroup ファイルシステムのサポートが追加されました。通常は "cgroup v2" や "unified hierarchy"(単一階層構造) と呼ばれています。 + それ以来、通常は古い cgroup ファイルシステムは "cgroup v1" や "legacy hierarchies"(レガシー階層構造)と呼ばれています。 この 2 つのバージョンの違いについての詳細な説明は、cgroup のマニュアルページをご覧ください。 - LXC は cgroup1(レガシー階層構造)と cgroup2(単一階層構造)に対する設定を、異なる設定プレフィックスを使って区別しています。 - cgroup1 に対する設定を変更するには というプレフィックスを使う必要があり、cgroup2 の設定を変更するには を使う必要があります。 - LXC は、cgroup2 だけが使われているシステム上の を無視します。逆に cgroup1 だけが使われているシステム上の を無視します。 + Since LXC 7.0, only the unified cgroup hierarchy (cgroup v2) is + supported. To alter settings for controllers in the unified hierarchy, + the key prefix must be used. + The key prefix, which was used for + legacy and hybrid hierarchy configurations, is no longer supported. + --> + LXC 7.0 以降、cgroup v2(単一階層構造)のみがサポートされています。cgroup v2 のコントローラーの設定を変更するには、 というプレフィックスを使う必要があります。cgroup v1(レガシー階層構造)や v1 と v2 のハイブリッドな構成で使われていた というプレフィックスはサポートされなくなりました。 @@ -2108,67 +2101,44 @@ cgroup 階層の本質は、プロセスを階層的に構造化する方法です。通常は、cgroup 階層では 1 つ以上の「コントローラー」が有効になっています。 通常、cgroup 階層の「コントローラー」は階層に従って特定のタイプのシステムリソースを分配する役割を果たします。 コントローラーには "pids" コントローラー、"cpu" コントローラー、"memory" コントローラーなどがあります。 - しかし、システムリソースの分配するという役割に該当しないコントローラーもあります。このようなコントローラーは「ユーティリティー」コントローラーと呼ばれたりします。 + しかし、システムリソースを分配するという役割に該当しないコントローラーもあります。このようなコントローラーは「ユーティリティー」コントローラーと呼ばれたりします。 ユーティリティーコントローラーの 1 つにデバイスコントローラーがあります。このコントローラーはシステムリソースを分配する代わりにデバイスへのアクセスを管理できます。 - cgroup1 では、デバイスコントローラーは他の多くのコントローラーと同様に、書き込みできるファイルのセットとして実装されていました。 - これらのファイルは "devices.allow" と "devices.deny" という名前のファイルでした。レガシーデバイスコントローラーは「許可リスト(allowlists)」と「拒否リスト(denylists)」の両方を実装できました。 + LXC supports both "allowlist" and "denylist" semantics for device + access control. An allowlist blocks access to all devices by default, + and allow rules must be specified for particular devices or device + classes. A denylist allows access to all devices by default, and "deny + rules" must be specified to restrict access to particular devices or + device classes. + --> + LXC は、デバイスアクセスコントロールにおいて、「許可リスト(allowlist)」と「拒否リスト(denylist)」の両方をサポートしています。許可リストは、デフォルトですべてのデバイスへのアクセスをブロックし、特定のデバイスまたはデバイスクラスに対して「許可ルール(allow rules)」を指定する必要があります。拒否リストは、デフォルトですべてのデバイスへのアクセスを許可し、特定のデバイスまたはデバイスクラスへのアクセスを拒否するには「拒否ルール(deny rules)」を指定する必要があります。 - 許可リスト(allowlist)とは、すべてのデバイスへのアクセスをブロックするデバイスプログラムです。特定のデバイスへのアクセスを行うには、特定のデバイスもしくはデバイスクラスに対する「許可ルール(allow rules)」を指定する必要があります。 - 一方、拒否リスト(denylist)はデフォルトですべてのデバイスへのアクセスを許可するデバイスプログラムです。特定のデバイスへのアクセスを拒否するには、特定のデバイスもしくはデバイスクラスに対する「拒否ルール(deny rules)」を指定する必要があります。 + cgroup v2 では、デバイスコントローラーは、以前使用されていたファイルベースのインターフェースではなく、cgroup にアタッチされたタイプ の eBPF プログラムを介して実装されています。LXC は、この eBPF ベースのデバイスコントローラーで、v1 のときと同じ許可リスト・拒否リストのセマンティクスを保持します。このあとの段落では、cgroup v2 の eBPF デバイスコントローラーに対するセマンティクスを説明します。 - cgroup2 では、デバイスコントローラーの実装が完全に変わりました。読み書きするファイルの代わりに、 の eBPF プログラムを cgroup にアタッチできます。 - カーネルの実装が完全に変わったのにもかかわらず、LXC は cgroup1 のデバイスコントローラーと cgroup2 の eBPF ベースのデバイスコントローラーで同じセマンティクスに従えるようにしています。 - このあとの段落では、cgroup2 の eBPF デバイスコントローラーに対するセマンティクスを説明します。 + cgroup v2 の eBPF ベースのデバイスコントローラーのデバイスルールは、 と を使って指定します。 - - - 先に述べたように、cgroup2 の eBPF ベースのデバイスコントローラーに対するデバイスルールを指定するフォーマットは、cgroup1 のデバイスコントローラーと同じです。ただし、設定キーのプレフィックスは変更されています。 - 具体的には、cgroup1 のデバイスコントローラーに対するデバイスルールは と を使って指定します。一方、cgroup2 の eBPF ベースのコントローラーでは と を使わなければなりません。 - @@ -2376,22 +2346,16 @@ - - コンテナの cgroup を作成するパスやディレクトリを指定します。 - 例えば、"c1" という名前のコンテナで のように設定すると、"my-cgroup" のサブ cgroup のようにコンテナの cgroup を作成します。 - 例えば、ユーザのカレントの cgroup である "my-user" が cgroup v1 階層にある cpuset コントローラの root cgroup 内に存在する場合、この設定は "/sys/fs/cgroup/cpuset/my-user/my-cgroup/first/c1" という cgroup をこのコンテナ向けに作成します。 - 存在しない cgroup は LXC が作成しますが、ユーザがカレントの cgroup に書き込み権を持っていることが前提となります。 + named "c1", if the user's current cgroup is "my-user", will + create the container's cgroups under "my-user/my-cgroup/first". + Any missing cgroups will be created by LXC. This presupposes + that the user has write access to its current cgroup. + --> + コンテナの cgroup を作成するパスやディレクトリを指定します。例えば、"c1" という名前のコンテナで のように設定すると、ユーザのカレント cgroup が "my-user" の場合、コンテナの cgroup は "my-user/my-cgroup/first" の下に作成されます。存在しない cgroup は LXC が作成しますが、ユーザーがカレントの cgroup に書き込み権を持っていることが前提となります。 @@ -4139,11 +4103,11 @@ devices.allow は、特定のデバイスを使用可能にします。 - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw @@ -4177,11 +4141,11 @@ lxc.net.2.hwaddr = 4a:49:43:49:79:ff lxc.net.2.ipv4.address = 10.2.3.6/24 lxc.net.2.ipv6.address = 2003:db8:1:0:214:1234:fe0b:3297 - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw lxc.mount.fstab = /etc/fstab.complex lxc.mount.entry = /lib /root/myrootfs/lib none ro,bind 0 0 lxc.rootfs.path = dir:/mnt/rootfs.complex diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in index 8ba375df9c..b0eca005f8 100644 --- a/doc/lxc.container.conf.sgml.in +++ b/doc/lxc.container.conf.sgml.in @@ -1546,17 +1546,11 @@ - LXC distinguishes settings for the legacy and the unified hierarchy by - using different configuration key prefixes. To alter settings for - controllers in a legacy hierarchy the key prefix - must be used and in order to alter the - settings for a controller in the unified hierarchy the - key must be used. Note that LXC will - ignore settings on systems that only use - the unified hierarchy. Conversely, it will ignore - options on systems that only use legacy - hierarchies. (legacy and hybrid hierarchy) - support is dropped. + Since LXC 7.0, only the unified cgroup hierarchy (cgroup v2) is + supported. To alter settings for controllers in the unified hierarchy, + the key prefix must be used. + The key prefix, which was used for + legacy and hybrid hierarchy configurations, is no longer supported. @@ -1573,45 +1567,30 @@ - In the legacy hierarchy the device controller was implemented like most - other controllers as a set of files that could be written to. These - files where named "devices.allow" and "devices.deny". The legacy device - controller allowed the implementation of both "allowlists" and - "denylists". + LXC supports both "allowlist" and "denylist" semantics for device + access control. An allowlist blocks access to all devices by default, + and "allow rules" must be specified for particular devices or device + classes. A denylist allows access to all devices by default, and "deny + rules" must be specified to restrict access to particular devices or + device classes. - An allowlist is a device program that by default blocks access to all - devices. In order to access specific devices "allow rules" for - particular devices or device classes must be specified. In contrast, a - denylist is a device program that by default allows access to all - devices. In order to restrict access to specific devices "deny rules" - for particular devices or device classes must be specified. + In the unified cgroup hierarchy, the device controller is implemented + via an eBPF program of type + attached to a cgroup, + rather than the file-based interface used previously. LXC preserves + the same allowlist/denylist semantics in this eBPF-based device + controller. The following paragraphs explain these semantics in + detail. - In the unified cgroup hierarchy the implementation of the device - controller has completely changed. Instead of files to read from and - write to a eBPF program of - can be attached to a - cgroup. Even though the kernel implementation has changed completely - LXC tries to allow for the same semantics to be followed in the legacy - device cgroup and the unified eBPF-based device controller. The - following paragraphs explain the semantics for the unified eBPF-based - device controller. + Device rules for the cgroup2 eBPF-based device controller are + specified via and + . - - As mentioned the format for specifying device rules for the unified - eBPF-based device controller is the same as for the legacy cgroup - device controller; only the configuration key prefix has changed. - Specifically, device rules for the legacy cgroup device controller are - specified via and - whereas for the - cgroup2 eBPF-based device controller - and - must be used. - @@ -1722,21 +1701,6 @@ switch from an allowlist program to a denylist program. - - - - - - - Specify the control group value to be set on a legacy cgroup - hierarchy. The controller name is the literal name of the control - group. The permitted names and the syntax of their values is not - dictated by LXC, instead it depends on the features of the Linux - kernel running at the time the container is started, eg. - - - - @@ -1758,16 +1722,13 @@ - specify a directory or path in which the container's cgroup will + Specify a directory or path in which the container's cgroup will be created. For example, setting for a container - named "c1" will create the container's cgroup as a sub-cgroup of - "my-cgroup". For example, if the user's current cgroup "my-user" - is located in the root cgroup of the cpuset controller in a - cgroup v1 hierarchy this would create the cgroup - "/sys/fs/cgroup/cpuset/my-user/my-cgroup/first/c1" for the - container. Any missing cgroups will be created by LXC. This - presupposes that the user has write access to its current cgroup. + named "c1", if the user's current cgroup is "my-user", will + create the container's cgroups under "my-user/my-cgroup/first". + Any missing cgroups will be created by LXC. This presupposes + that the user has write access to its current cgroup. @@ -3093,11 +3054,11 @@ cpus.share prioritize the control group, devices.allow makes usable the specified devices. - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw @@ -3128,11 +3089,11 @@ lxc.net.2.hwaddr = 4a:49:43:49:79:ff lxc.net.2.ipv4.address = 10.2.3.6/24 lxc.net.2.ipv6.address = 2003:db8:1:0:214:1234:fe0b:3297 - lxc.cgroup.cpuset.cpus = 0,1 - lxc.cgroup.cpu.shares = 1234 - lxc.cgroup.devices.deny = a - lxc.cgroup.devices.allow = c 1:3 rw - lxc.cgroup.devices.allow = b 8:0 rw + lxc.cgroup2.cpuset.cpus = 0,1 + lxc.cgroup2.cpu.shares = 1234 + lxc.cgroup2.devices.deny = a + lxc.cgroup2.devices.allow = c 1:3 rw + lxc.cgroup2.devices.allow = b 8:0 rw lxc.mount.fstab = /etc/fstab.complex lxc.mount.entry = /lib /root/myrootfs/lib none ro,bind 0 0 lxc.rootfs.path = dir:/mnt/rootfs.complex From 195088dfa6647c0b92ac7c6ef5d4bcf02d2724f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 13:22:26 +0000 Subject: [PATCH 03/14] build(deps): bump actions/checkout from 6 to 7 Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/builds.yml | 2 +- .github/workflows/coverity.yml | 2 +- .github/workflows/tests.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index fcc620b007..9469fdf52e 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install dependencies run: | diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml index 6bccb6ffbb..45af834105 100644 --- a/.github/workflows/coverity.yml +++ b/.github/workflows/coverity.yml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'lxc/lxc' steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Download Coverity Build Tool run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9fb0805066..061b85f06a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install dependencies run: | @@ -64,7 +64,7 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Install dependencies run: | From c2809b067bbd5c63f0f78a5acd6f7af4e77e584c Mon Sep 17 00:00:00 2001 From: Adrian Ratiu Date: Sat, 18 Jul 2026 23:11:52 +0300 Subject: [PATCH 04/14] tree-wide: fix const-correctness issues exposed by glibc 2.43 glibc 2.43 implements strchr(3), strrchr(3) and strstr(3) as C23-style _Generic macros which propagate the const qualifier of the input string to the return type. For example, a 'const char *' input now produces 'const char *' output types and vice-versa (non-const -> non-const). Building with clang and -Werror=incompatible-pointer-types fails: src/lxc/confile.c:2690:4: error: assigning to 'char *' from 'const char *' discards qualifiers [-Werror,-Wincompatible-pointer-types-discards-qualifiers] Constify the result pointers where they are only read. Where the code intentionally writes through the result into caller-owned writable storage, drop the bogus const from the parameter instead of casting it away: update_hwaddr() (and thus its caller append_unexp_config_line()) modify the string in-place via rand_complete_hwaddr(), so 'char *' is the honest type. The two call sites already pass writable buffers (a strdup()'d line and an internally built one), so no cast is needed. The one remaining cast is in cgroup1-only pam_cgfs code (cgv1_handle_cpuset_hierarchy) where the writable buffer is passed down through a const 'cgroup' parameter; that hierarchy is slated for removal, so the minimal cast is kept there. This is just a build fix, the runtime behavior is unchanged. Fixes: #4710 Signed-off-by: Adrian Ratiu --- src/lxc/confile.c | 6 +++--- src/lxc/confile.h | 2 +- src/lxc/confile_utils.c | 2 +- src/lxc/pam/pam_cgfs.c | 4 ++-- src/lxc/storage/nbd.c | 2 +- src/lxc/storage/zfs.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 0bebe4687e..555b0e64ec 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -2675,7 +2675,7 @@ static int set_config_console_size(const char *key, const char *value, * lxc.include. * 'x' and 'X' are substituted in-place. */ -static void update_hwaddr(const char *line) +static void update_hwaddr(char *line) { char *p; @@ -2701,7 +2701,7 @@ static void update_hwaddr(const char *line) rand_complete_hwaddr(p); } -int append_unexp_config_line(const char *line, struct lxc_conf *conf) +int append_unexp_config_line(char *line, struct lxc_conf *conf) { size_t linelen; size_t len = conf->unexpanded_len; @@ -4213,7 +4213,7 @@ static int get_config_uts_name(const char *key, char *retv, int inlen, static int get_config_hooks(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - char *subkey; + const char *subkey; int len, fulllen = 0, found = -1; struct string_entry *entry; int i; diff --git a/src/lxc/confile.h b/src/lxc/confile.h index 33e97dbd46..cb9263849a 100644 --- a/src/lxc/confile.h +++ b/src/lxc/confile.h @@ -75,7 +75,7 @@ __hidden extern int lxc_list_net(struct lxc_conf *c, const char *key, char *retv __hidden extern int lxc_config_read(const char *file, struct lxc_conf *conf, bool from_include); -__hidden extern int append_unexp_config_line(const char *line, struct lxc_conf *conf); +__hidden extern int append_unexp_config_line(char *line, struct lxc_conf *conf); extern int lxc_config_define_add(struct lxc_list *defines, char *arg); diff --git a/src/lxc/confile_utils.c b/src/lxc/confile_utils.c index 7dcd735698..1467a112a2 100644 --- a/src/lxc/confile_utils.c +++ b/src/lxc/confile_utils.c @@ -903,7 +903,7 @@ int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath, { __do_free char *dup = NULL; int fd, pid; - char *lastslash; + const char *lastslash; if (nsfd_path[0] == '/') { return open(nsfd_path, O_RDONLY | O_CLOEXEC); diff --git a/src/lxc/pam/pam_cgfs.c b/src/lxc/pam/pam_cgfs.c index e638269bc8..f066345fab 100644 --- a/src/lxc/pam/pam_cgfs.c +++ b/src/lxc/pam/pam_cgfs.c @@ -362,7 +362,7 @@ static char *copy_to_eol(char *s) /* Check if given entry under /proc//mountinfo is a fuse.lxcfs mount. */ static bool is_lxcfs(const char *line) { - char *p = strstr(line, " - "); + const char *p = strstr(line, " - "); if (!p) return false; @@ -1914,7 +1914,7 @@ static bool cgv1_handle_cpuset_hierarchy(struct cgv1_hierarchy *h, if (*cgroup == '/') cgroup++; - slash = strchr(cgroup, '/'); + slash = (char *)strchr(cgroup, '/'); if (slash) *slash = '\0'; diff --git a/src/lxc/storage/nbd.c b/src/lxc/storage/nbd.c index c35f9e8659..73ea19b8c3 100644 --- a/src/lxc/storage/nbd.c +++ b/src/lxc/storage/nbd.c @@ -291,7 +291,7 @@ static void nbd_detach(const char *path) */ static int nbd_get_partition(const char *src) { - char *p = strchr(src, ':'); + const char *p = strchr(src, ':'); if (!p) return 0; diff --git a/src/lxc/storage/zfs.c b/src/lxc/storage/zfs.c index 521a9fd637..c3075962ab 100644 --- a/src/lxc/storage/zfs.c +++ b/src/lxc/storage/zfs.c @@ -461,7 +461,7 @@ int zfs_clonepaths(struct lxc_storage *orig, struct lxc_storage *new, orig_src = cmd_output; } - tmp = strrchr(orig_src, '/'); + tmp = (char *)strrchr(orig_src, '/'); if (!tmp) { ERROR("Failed to detect \"/\" in \"%s\"", orig_src); return -1; From 06f626091cb9f1d717cb9d63b7bc2ffdbf0c3cdf Mon Sep 17 00:00:00 2001 From: Kartik Kenchi Date: Tue, 9 Jun 2026 12:14:46 +0530 Subject: [PATCH 05/14] commands: validate string in lxc_cmd_get_config_item_callback Signed-off-by: Kartik Kenchi --- src/lxc/commands.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lxc/commands.c b/src/lxc/commands.c index 8c6460cdcc..1454d0ebaa 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -1028,8 +1028,19 @@ static int lxc_cmd_get_config_item_callback(int fd, struct lxc_cmd_req *req, int cilen; struct lxc_config_t *item; struct lxc_cmd_rsp rsp; + ssize_t ret; memset(&rsp, 0, sizeof(rsp)); + + if (req->datalen <= 0) { + rsp.ret = -EINVAL; + return lxc_cmd_rsp_send_reap(fd, &rsp); + } + + ret = validate_string_request(fd, req); + if (ret != 0) + return ret; + item = lxc_get_config(req->data); cilen = item->get(req->data, NULL, 0, handler->conf, NULL); if (cilen <= 0) From 19ad80ed8e6288904caaee5b7bd3c485d51a2291 Mon Sep 17 00:00:00 2001 From: Kartik Kenchi Date: Thu, 20 Aug 2026 13:03:50 +0530 Subject: [PATCH 06/14] commands: validate datalen in lxc_cmd_console_log_callback Signed-off-by: Kartik Kenchi --- src/lxc/commands.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lxc/commands.c b/src/lxc/commands.c index 8c6460cdcc..3a8353bf2a 100644 --- a/src/lxc/commands.c +++ b/src/lxc/commands.c @@ -1554,6 +1554,12 @@ static int lxc_cmd_console_log_callback(int fd, struct lxc_cmd_req *req, rsp.ret = -EFAULT; rsp.datalen = 0; rsp.data = NULL; + + if (req->datalen != sizeof(struct lxc_cmd_console_log) || !req->data) { + rsp.ret = -EINVAL; + goto out; + } + if (buffer_size <= 0) goto out; From f378e2ea11cbe1de29cfc583fd3d4aecda2e5629 Mon Sep 17 00:00:00 2001 From: Jef Steelant Date: Wed, 26 Aug 2026 12:41:41 +0200 Subject: [PATCH 07/14] keep capabilities if init process is not run as root If the init process is not run as root, then all capabilities will be dropped. This adds an option to let the container inherit the requested capabilities when the init process is not root: lxc.cap.inheritance=1 Signed-off-by: Jef Steelant --- src/lxc/attach.c | 17 +++++++++++++++-- src/lxc/caps.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/lxc/caps.h | 13 +++++++++++++ src/lxc/conf.h | 3 +++ src/lxc/confile.c | 21 +++++++++++++++++++++ src/lxc/start.c | 32 ++++++++++++++++++++++++-------- 6 files changed, 118 insertions(+), 10 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index f22f83f0df..635fc1c002 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -1368,8 +1368,21 @@ __noreturn static void do_attach(struct attach_payload *ap) lxc_seccomp_close_notifier_fd(&conf->seccomp); } - if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) - goto on_error; + if (conf->cap_inheritance) { + ret = lxc_set_keepcaps(); + if (ret < 0) + goto on_error; + + if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) + goto on_error; + + ret = lxc_bounding_as_ambient_caps(); + if (ret < 0) + goto on_error; + } else { + if (!lxc_switch_uid_gid(ctx->target_ns_uid, ctx->target_ns_gid)) + goto on_error; + } put_attach_payload(ap); diff --git a/src/lxc/caps.c b/src/lxc/caps.c index f6c5770ed3..df3a3da5c1 100644 --- a/src/lxc/caps.c +++ b/src/lxc/caps.c @@ -323,4 +323,46 @@ bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag) return lxc_cap_is_set(caps, cap, flag); } + +int lxc_bounding_as_ambient_caps(void) +{ + call_cleaner(cap_free) cap_t caps = NULL; + int ret; + cap_value_t cap; + + caps = cap_get_proc(); + if (!caps) + return log_error_errno(-1, errno, "Failed to retrieve capabilities"); + + for (cap = 0; cap <= CAP_LAST_CAP; cap++) { + if (cap_get_bound(cap) <= 0) + continue; + + ret = cap_set_flag(caps, CAP_PERMITTED, 1, &cap, CAP_SET); + if (ret < 0) { + return log_error_errno(ret, errno, "Failed to set cap %d as permitted", cap); + } + ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_SET); + if (ret < 0) { + return log_error_errno(ret, errno, "Failed to set cap %d as inheritable", cap); + } + + ret = cap_set_proc(caps); + if (ret < 0) + return log_error_errno(ret, errno, "Failed to set capabilities"); + + cap_set_ambient(cap, CAP_SET); + } + + return 0; +} + +int lxc_set_keepcaps(void) { + int ret = prctl(PR_SET_KEEPCAPS, prctl_arg(1)); + if (ret < 0) + return log_error_errno(ret, errno, "Failed to set PR_SET_KEEPCAPS"); + + return ret; +} + #endif diff --git a/src/lxc/caps.h b/src/lxc/caps.h index fbec1fdb54..13f6ea71ee 100644 --- a/src/lxc/caps.h +++ b/src/lxc/caps.h @@ -21,6 +21,8 @@ __hidden extern int lxc_caps_init(void); __hidden extern int lxc_caps_last_cap(__u32 *cap); __hidden extern bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag); __hidden extern bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag); +__hidden extern int lxc_bounding_as_ambient_caps(void); +__hidden extern int lxc_set_keepcaps(void); #else static inline int lxc_caps_down(void) { @@ -64,6 +66,17 @@ static inline bool lxc_file_cap_is_set(const char *path, cap_value_t cap, { return false; } + +static inline int lxc_bounding_as_ambiant_caps(void) +{ + return 0; +} + +static inline int lxc_set_keepcaps(void) +{ + return 0; +} + #endif #define lxc_priv(__lxc_function) \ diff --git a/src/lxc/conf.h b/src/lxc/conf.h index ea4e199404..b47815b9e7 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -534,6 +534,9 @@ struct lxc_conf { /* The groups to use for the container. */ lxc_groups_t init_groups; + /* Whether the available caps can be set as inheritable/ambient for the container */ + bool cap_inheritance; + /* indicator if the container will be destroyed on shutdown */ unsigned int ephemeral; diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 555b0e64ec..944751c5a8 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -92,6 +92,7 @@ lxc_config_define(init_cmd); lxc_config_define(init_cwd); lxc_config_define(init_gid); lxc_config_define(init_uid); +lxc_config_define(cap_inheritance); lxc_config_define(init_groups); lxc_config_define(jump_table_net); lxc_config_define(keyring_session); @@ -235,6 +236,7 @@ static struct lxc_config_t config_jump_table[] = { { "lxc.init.gid", true, set_config_init_gid, get_config_init_gid, clr_config_init_gid, }, { "lxc.init.groups", true, set_config_init_groups, get_config_init_groups, clr_config_init_groups, }, { "lxc.init.uid", true, set_config_init_uid, get_config_init_uid, clr_config_init_uid, }, + { "lxc.cap.inheritance", true, set_config_cap_inheritance, get_config_cap_inheritance, clr_config_cap_inheritance, }, { "lxc.init.cwd", true, set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, }, { "lxc.keyring.session", true, set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session }, { "lxc.log.file", true, set_config_log_file, get_config_log_file, clr_config_log_file, }, @@ -1287,6 +1289,12 @@ static int set_config_init_uid(const char *key, const char *value, return 0; } +static int set_config_cap_inheritance(const char *key, const char *value, + struct lxc_conf *lxc_conf, void *data) +{ + return set_config_bool_item(&lxc_conf->cap_inheritance, value, false); +} + static int set_config_init_gid(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { @@ -4535,6 +4543,12 @@ static int get_config_init_uid(const char *key, char *retv, int inlen, return lxc_get_conf_int(c, retv, inlen, c->init_uid); } +static int get_config_cap_inheritance(const char *key, char *retv, int inlen, + struct lxc_conf *c, void *data) +{ + return lxc_get_conf_bool(c, retv, inlen, c->cap_inheritance); +} + static int get_config_init_gid(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { @@ -5268,6 +5282,13 @@ static inline int clr_config_init_uid(const char *key, struct lxc_conf *c, return 0; } +static inline int clr_config_cap_inheritance(const char *key, struct lxc_conf *c, + void *data) +{ + c->cap_inheritance = false; + return 0; +} + static inline int clr_config_init_gid(const char *key, struct lxc_conf *c, void *data) { diff --git a/src/lxc/start.c b/src/lxc/start.c index 7e4381b5a3..55b8c64cf4 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1616,20 +1616,36 @@ static int do_start(void *data) goto out_warn_father; } - if (!lxc_switch_uid_gid(new_uid, new_gid)) - goto out_warn_father; + if (handler->conf->cap_inheritance) { + NOTICE("Inherit capabilities"); + ret = lxc_set_keepcaps(); + if (ret < 0) + goto out_warn_father; + + if (!lxc_switch_uid_gid(new_uid, new_gid)) + goto out_warn_father; + + ret = lxc_bounding_as_ambient_caps(); + if (ret < 0) { + ERROR("Failed to set bounding capabilities as ambiant"); + goto out_warn_father; + } + } else { + if (!lxc_switch_uid_gid(new_uid, new_gid)) + goto out_warn_father; + + ret = lxc_ambient_caps_down(); + if (ret < 0) { + ERROR("Failed to clear ambient capabilities"); + goto out_warn_father; + } + } ret = prctl(PR_SET_DUMPABLE, prctl_arg(1), prctl_arg(0), prctl_arg(0), prctl_arg(0)); if (ret < 0) goto out_warn_father; - ret = lxc_ambient_caps_down(); - if (ret < 0) { - ERROR("Failed to clear ambient capabilities"); - goto out_warn_father; - } - if (handler->conf->monitor_signal_pdeath != SIGKILL) { ret = lxc_set_death_signal(handler->conf->monitor_signal_pdeath, handler->monitor_pid, status_fd); From 74a7e562762bb3c25ef03082ce0fde2ab9480426 Mon Sep 17 00:00:00 2001 From: Jef Steelant Date: Mon, 31 Aug 2026 08:24:06 +0000 Subject: [PATCH 08/14] fixup! keep capabilities if init process is not run as root Signed-off-by: Jef Steelant --- src/lxc/attach.c | 2 +- src/lxc/conf.h | 5 +++-- src/lxc/confile.c | 16 ++++++++-------- src/lxc/start.c | 4 ++-- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 635fc1c002..55f748e9ab 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -1368,7 +1368,7 @@ __noreturn static void do_attach(struct attach_payload *ap) lxc_seccomp_close_notifier_fd(&conf->seccomp); } - if (conf->cap_inheritance) { + if (conf->nonroot_keepcaps) { ret = lxc_set_keepcaps(); if (ret < 0) goto on_error; diff --git a/src/lxc/conf.h b/src/lxc/conf.h index b47815b9e7..cf1c9aa4f2 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -534,8 +534,9 @@ struct lxc_conf { /* The groups to use for the container. */ lxc_groups_t init_groups; - /* Whether the available caps can be set as inheritable/ambient for the container */ - bool cap_inheritance; + /* Defines whether a privileged container with a nonroot user (init_uid != 0) + * will keep capabilities */ + bool nonroot_keepcaps; /* indicator if the container will be destroyed on shutdown */ unsigned int ephemeral; diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 944751c5a8..72238b10be 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -92,7 +92,7 @@ lxc_config_define(init_cmd); lxc_config_define(init_cwd); lxc_config_define(init_gid); lxc_config_define(init_uid); -lxc_config_define(cap_inheritance); +lxc_config_define(nonroot_keepcaps); lxc_config_define(init_groups); lxc_config_define(jump_table_net); lxc_config_define(keyring_session); @@ -236,7 +236,7 @@ static struct lxc_config_t config_jump_table[] = { { "lxc.init.gid", true, set_config_init_gid, get_config_init_gid, clr_config_init_gid, }, { "lxc.init.groups", true, set_config_init_groups, get_config_init_groups, clr_config_init_groups, }, { "lxc.init.uid", true, set_config_init_uid, get_config_init_uid, clr_config_init_uid, }, - { "lxc.cap.inheritance", true, set_config_cap_inheritance, get_config_cap_inheritance, clr_config_cap_inheritance, }, + { "lxc.cap.nonroot", true, set_config_nonroot_keepcaps, get_config_nonroot_keepcaps, clr_config_nonroot_keepcaps, }, { "lxc.init.cwd", true, set_config_init_cwd, get_config_init_cwd, clr_config_init_cwd, }, { "lxc.keyring.session", true, set_config_keyring_session, get_config_keyring_session, clr_config_keyring_session }, { "lxc.log.file", true, set_config_log_file, get_config_log_file, clr_config_log_file, }, @@ -1289,10 +1289,10 @@ static int set_config_init_uid(const char *key, const char *value, return 0; } -static int set_config_cap_inheritance(const char *key, const char *value, +static int set_config_nonroot_keepcaps(const char *key, const char *value, struct lxc_conf *lxc_conf, void *data) { - return set_config_bool_item(&lxc_conf->cap_inheritance, value, false); + return set_config_bool_item(&lxc_conf->nonroot_keepcaps, value, false); } static int set_config_init_gid(const char *key, const char *value, @@ -4543,10 +4543,10 @@ static int get_config_init_uid(const char *key, char *retv, int inlen, return lxc_get_conf_int(c, retv, inlen, c->init_uid); } -static int get_config_cap_inheritance(const char *key, char *retv, int inlen, +static int get_config_nonroot_keepcaps(const char *key, char *retv, int inlen, struct lxc_conf *c, void *data) { - return lxc_get_conf_bool(c, retv, inlen, c->cap_inheritance); + return lxc_get_conf_bool(c, retv, inlen, c->nonroot_keepcaps); } static int get_config_init_gid(const char *key, char *retv, int inlen, @@ -5282,10 +5282,10 @@ static inline int clr_config_init_uid(const char *key, struct lxc_conf *c, return 0; } -static inline int clr_config_cap_inheritance(const char *key, struct lxc_conf *c, +static inline int clr_config_nonroot_keepcaps(const char *key, struct lxc_conf *c, void *data) { - c->cap_inheritance = false; + c->nonroot_keepcaps = false; return 0; } diff --git a/src/lxc/start.c b/src/lxc/start.c index 55b8c64cf4..55866e0268 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1616,8 +1616,8 @@ static int do_start(void *data) goto out_warn_father; } - if (handler->conf->cap_inheritance) { - NOTICE("Inherit capabilities"); + if (handler->conf->nonroot_keepcaps) { + NOTICE("Keep capabilities"); ret = lxc_set_keepcaps(); if (ret < 0) goto out_warn_father; From 4843817da406cc36a4b8ac2974e8fecc7c12270e Mon Sep 17 00:00:00 2001 From: Kemal Oktay Date: Mon, 7 Sep 2026 14:43:15 +0300 Subject: [PATCH 09/14] lxc-net MTU option Signed-off-by: Kemal Oktay --- config/init/common/lxc-net.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/init/common/lxc-net.in b/config/init/common/lxc-net.in index 2e0958028a..5e2083832e 100755 --- a/config/init/common/lxc-net.in +++ b/config/init/common/lxc-net.in @@ -10,6 +10,7 @@ varlib="@LOCALSTATEDIR@/lib" USE_LXC_BRIDGE="true" LXC_BRIDGE="lxcbr0" LXC_BRIDGE_MAC="10:66:6a:00:00:00" +LXC_BRIDGE_MTU="1500" LXC_ADDR="10.0.3.1" LXC_NETMASK="255.255.255.0" LXC_NETWORK="10.0.3.0/24" @@ -59,6 +60,7 @@ _ifup() { CIDR_ADDR="${LXC_ADDR}/${MASK}" ip addr add ${CIDR_ADDR} broadcast + dev ${LXC_BRIDGE} ip link set dev ${LXC_BRIDGE} address $LXC_BRIDGE_MAC + ip link set dev ${LXC_BRIDGE} mtu ${LXC_BRIDGE_MTU:-1500} ip link set dev ${LXC_BRIDGE} up } From 6424a91a55efc54edc25ca46e9165bd9f35b50b7 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Tue, 14 Jul 2026 11:50:39 -0500 Subject: [PATCH 10/14] lxc-copy: open hostname in a safer way MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit lxc-copy without -K updates the hostname in the container. It does this by opening /etc/hostname in the container and writing the new hostname to it. If /etc/hostname is a symbolic link, we can end up ovewriting a host path. lxc-copy is not setuid-root, so unprivileged users can't exploit this without help. More likely would be unprivileged users shooting themselves in the foot and accidentally changing the hostname of the original container. Fix it by using openat2(RESOLVE_IN_ROOT) to make sure that if /etc or /etc/hostname is a symlink, it is resolved inside the container's fs. Signed-off-by: Serge Hallyn Reported-by: 怀硕 --- src/lxc/lxccontainer.c | 76 ++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index ba3d988b5b..736df037ac 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -3584,6 +3584,52 @@ struct clone_update_data { char **hookargs; }; +static int do_update_hostname(struct lxc_container *c, int flags) +{ + char *path; + __do_close int dir = -EBADF; + __do_close int hfd = -EBADF; + __do_fclose FILE *fout = NULL; + struct open_how how = { + .flags = O_RDWR, + .resolve = RESOLVE_IN_ROOT + }; + + path = c->lxc_conf->rootfs.storage->dest; + if (!file_exists(path)) + return 0; + + dir = open(path, O_RDONLY | O_DIRECTORY | O_PATH | O_CLOEXEC); + if (dir < 0) + return 0; + + hfd = openat2(dir, "/etc/hostname", &how, sizeof(how)); + if (hfd < 0) + return 0; + + fout = fdopen(hfd, "w"); + if (!fout) + return 0; + hfd = -EBADF; // fclose(fout) will close hfd + + if (fprintf(fout, "%s", c->name) < 0) + return -1; + + return 0; +} + +static int maybe_update_hostname(struct lxc_container *c, int flags) +{ + int ret = 0; + struct lxc_conf *conf = c->lxc_conf; + + if (!(flags & LXC_CLONE_KEEPNAME)) + ret = do_update_hostname(c, flags); + + lxc_storage_put(conf); + return ret; +} + static int clone_update_rootfs(struct clone_update_data *data) { struct lxc_container *c0 = data->c0; @@ -3591,9 +3637,7 @@ static int clone_update_rootfs(struct clone_update_data *data) int flags = data->flags; char **hookargs = data->hookargs; int ret = -1; - char path[PATH_MAX]; struct lxc_storage *bdev; - FILE *fout; struct lxc_conf *conf = c->lxc_conf; /* update hostname in rootfs */ @@ -3662,33 +3706,7 @@ static int clone_update_rootfs(struct clone_update_data *data) } } - if (!(flags & LXC_CLONE_KEEPNAME)) { - ret = strnprintf(path, sizeof(path), "%s/etc/hostname", bdev->dest); - lxc_storage_put(conf); - - if (ret < 0) - return -1; - - if (!file_exists(path)) - return 0; - - if (!(fout = fopen(path, "we"))) { - SYSERROR("unable to open %s: ignoring", path); - return 0; - } - - if (fprintf(fout, "%s", c->name) < 0) { - fclose(fout); - return -1; - } - - if (fclose(fout) < 0) - return -1; - } else { - lxc_storage_put(conf); - } - - return 0; + return maybe_update_hostname(c, flags); } static int clone_update_rootfs_wrapper(void *data) From fa12709a79c2b63b3918297d7505108fcc840eb6 Mon Sep 17 00:00:00 2001 From: Shuo Huai Date: Tue, 28 Jul 2026 17:22:28 +0800 Subject: [PATCH 11/14] lxc-copy: fix hostname truncation during clone The hostname update code switched from fopen() to openat2() and fdopen(), but fdopen() does not truncate an existing file. Add O_TRUNC to preserve the previous fopen() behavior and avoid leaving stale bytes after updating the hostname. Signed-off-by: Shuo Huai --- src/lxc/lxccontainer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index 736df037ac..c820f59090 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -3591,7 +3591,7 @@ static int do_update_hostname(struct lxc_container *c, int flags) __do_close int hfd = -EBADF; __do_fclose FILE *fout = NULL; struct open_how how = { - .flags = O_RDWR, + .flags = O_RDWR | O_TRUNC, .resolve = RESOLVE_IN_ROOT }; From 93927173ef21a2080bd4a5866da870af233452b0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 29 Sep 2026 13:29:11 +0200 Subject: [PATCH 12/14] lxc/caps.h: typo lxc_bounding_as_ambiant_caps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building lxc results in a build failure: src/lxc/attach.c: In function ‘do_attach’: src/lxc/attach.c:1379:23: error: implicit declaration of function ‘lxc_bounding_as_ambient_caps’; did you mean ‘lxc_bounding_as_ambiant_caps’? [-Wimplicit-function-declaration] 1379 | ret = lxc_bounding_as_ambient_caps(); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ | lxc_bounding_as_ambiant_caps Rename lxc_bounding_as_ambiant_caps() to lxc_bounding_as_ambient_cap() to match the rest of the code. Fixes:f378e2ea11cb ("keep capabilities if init process is not run as root") Signed-off-by: Heinrich Schuchardt --- src/lxc/caps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lxc/caps.h b/src/lxc/caps.h index 13f6ea71ee..92d7d12cc5 100644 --- a/src/lxc/caps.h +++ b/src/lxc/caps.h @@ -67,7 +67,7 @@ static inline bool lxc_file_cap_is_set(const char *path, cap_value_t cap, return false; } -static inline int lxc_bounding_as_ambiant_caps(void) +static inline int lxc_bounding_as_ambient_caps(void) { return 0; } From 5707d8dd65c2c94b1567aa3162e4cfc7745176ca Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 30 Sep 2026 13:46:49 +0200 Subject: [PATCH 13/14] lxc/criu: initialize controllers variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building results in a warning ../src/lxc/error_utils.h:33:21: warning: ‘controllers’ may be used uninitialized [-Wmaybe-uninitialized] 33 | return !ptr || IS_ERR_VALUE((unsigned long)ptr); ../src/lxc/criu.c: In function ‘exec_criu’: ../src/lxc/criu.c:291:59: note: ‘controllers’ was declared here 291 | __do_free char *cgroup_base_path = NULL, *controllers; We must initialize controllers to NULL to avoid calling free() with a random pointer. Signed-off-by: Heinrich Schuchardt --- src/lxc/criu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lxc/criu.c b/src/lxc/criu.c index d6c2c4cd65..b1bc06b593 100644 --- a/src/lxc/criu.c +++ b/src/lxc/criu.c @@ -288,7 +288,7 @@ static int exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf, DECLARE_ARG(log); for (int i = 0; i < cgroup_ops->criu_num_hierarchies(cgroup_ops); i++) { - __do_free char *cgroup_base_path = NULL, *controllers; + __do_free char *cgroup_base_path = NULL, *controllers = NULL; char **controllers_list = NULL; char *tmp; From ddb556c3ae915e90dfaa4a8becae680c52236827 Mon Sep 17 00:00:00 2001 From: Yinbin Xu Date: Tue, 29 Sep 2026 15:55:05 -0700 Subject: [PATCH 14/14] conf: share idmapped mount sequence counter across fstab and entries Signed-off-by: Yinbin Xu --- src/lxc/conf.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 2a81c70fda..6105d10767 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2565,11 +2565,10 @@ static int setup_mount_entries(const struct lxc_conf *conf, return mount_file_entries(rootfs, f, lxc_name, lxc_path); } -static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) +static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f, int *mnt_seq) { struct lxc_conf *conf = handler->conf; struct lxc_rootfs *rootfs = &conf->rootfs; - int mnt_seq = 0; int ret; char buf[PATH_MAX]; struct mntent mntent; @@ -2675,10 +2674,10 @@ static int __lxc_idmapped_mounts_child(struct lxc_handler *handler, FILE *f) dfd_from, source_relative, fd_userns); } - if (mnt_seq != cur_mnt_seq) + if (*mnt_seq != cur_mnt_seq) return syserror("Expected mount sequence number and mount sequence number from parent mismatch: %d != %d", - mnt_seq, cur_mnt_seq); - mnt_seq++; + *mnt_seq, cur_mnt_seq); + (*mnt_seq)++; /* Set regular mount options. */ attr = opts.attr; @@ -2779,6 +2778,7 @@ static int lxc_idmapped_mounts_child(struct lxc_handler *handler) int fret = -1; struct lxc_conf *conf = handler->conf; const char *fstab = conf->fstab; + int mnt_seq = 0; int ret; f_entries = make_anonymous_mount_file(&conf->mount_entries, @@ -2788,7 +2788,7 @@ static int lxc_idmapped_mounts_child(struct lxc_handler *handler) goto out; } - ret = __lxc_idmapped_mounts_child(handler, f_entries); + ret = __lxc_idmapped_mounts_child(handler, f_entries, &mnt_seq); if (ret) { SYSERROR("Failed to setup idmapped mount entries"); goto out; @@ -2805,7 +2805,7 @@ static int lxc_idmapped_mounts_child(struct lxc_handler *handler) goto out; } - ret = __lxc_idmapped_mounts_child(handler, f_fstab); + ret = __lxc_idmapped_mounts_child(handler, f_fstab, &mnt_seq); if (ret) { SYSERROR("Failed to setup idmapped mount entries specified in fstab"); goto out;