Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
f30cbb8
lxc/criu: restore cgroup limits and freezer on restore
emirbuljubasic May 29, 2026
3224f46
doc: update cgroup section of lxc.container.conf(5) to reflect cgroup…
tenforward Jun 6, 2026
cfa3d17
Merge pull request #4698 from tenforward/japanese
stgraber Jun 6, 2026
195088d
build(deps): bump actions/checkout from 6 to 7
dependabot[bot] Jun 22, 2026
af38dcf
Merge pull request #4706 from lxc/dependabot/github_actions/actions/c…
stgraber Jun 22, 2026
c2809b0
tree-wide: fix const-correctness issues exposed by glibc 2.43
10ne1 Jul 18, 2026
fcc9426
Merge pull request #4711 from 10ne1/glibc-2.43-const-fixes
stgraber Jul 23, 2026
dc15af1
Merge pull request #4695 from emirbuljubasic/fix/restore-cgroup-freezer
stgraber Jul 23, 2026
06f6260
commands: validate string in lxc_cmd_get_config_item_callback
netliomax25-code Jun 9, 2026
1fb43d2
Merge pull request #4701 from netliomax25-code/commands-get-config-it…
stgraber Aug 18, 2026
19ad80e
commands: validate datalen in lxc_cmd_console_log_callback
netliomax25-code Aug 20, 2026
e7b855a
Merge pull request #4702 from netliomax25-code/console-log-validate-d…
stgraber Aug 20, 2026
f378e2e
keep capabilities if init process is not run as root
Aug 26, 2026
74a7e56
fixup! keep capabilities if init process is not run as root
Aug 31, 2026
95cd30c
Merge pull request #4720 from ElJeffe/keep_inheritance
hallyn Aug 31, 2026
4843817
lxc-net MTU option
oktay454 Sep 7, 2026
4f12581
Merge pull request #4721 from oktay454/patch-1
stgraber Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v6
uses: actions/checkout@v7

- name: Install dependencies
run: |
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/coverity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down Expand Up @@ -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: |
Expand Down
2 changes: 2 additions & 0 deletions config/init/common/lxc-net.in
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}

Expand Down
132 changes: 48 additions & 84 deletions doc/ja/lxc.container.conf.sgml.in

Large diffs are not rendered by default.

111 changes: 36 additions & 75 deletions doc/lxc.container.conf.sgml.in
Original file line number Diff line number Diff line change
Expand Up @@ -1546,17 +1546,11 @@
</para>

<para>
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
<option>lxc.cgroup.</option> must be used and in order to alter the
settings for a controller in the unified hierarchy the
<option>lxc.cgroup2.</option> key must be used. Note that LXC will
ignore <option>lxc.cgroup.</option> settings on systems that only use
the unified hierarchy. Conversely, it will ignore
<option>lxc.cgroup2.</option> options on systems that only use legacy
hierarchies. <option>lxc.cgroup.</option> (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 <option>lxc.cgroup2.</option> key prefix must be used.
The <option>lxc.cgroup.</option> key prefix, which was used for
legacy and hybrid hierarchy configurations, is no longer supported.
</para>

<para>
Expand All @@ -1573,45 +1567,30 @@
</para>

<para>
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.
</para>

<para>
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
<option>BPF_PROG_TYPE_CGROUP_DEVICE</option> 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.
</para>

<para>
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
<option>BPF_PROG_TYPE_CGROUP_DEVICE</option> 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 <option>lxc.cgroup2.devices.allow</option> and
<option>lxc.cgroup2.devices.deny</option>.
</para>

<para>
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 <option>lxc.cgroup.devices.allow</option> and
<option>lxc.cgroup.devices.deny</option> whereas for the
cgroup2 eBPF-based device controller
<option>lxc.cgroup2.devices.allow</option> and
<option>lxc.cgroup2.devices.deny</option> must be used.
</para>
<para>
<itemizedlist>
<listitem>
Expand Down Expand Up @@ -1722,21 +1701,6 @@
switch from an allowlist program to a denylist program.
</para>
<variablelist>
<varlistentry>
<term>
<option>lxc.cgroup.[controller name].[controller file]</option>
</term>
<listitem>
<para>
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.
<option>lxc.cgroup.cpuset.cpus</option>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>lxc.cgroup2.[controller name].[controller file]</option>
Expand All @@ -1758,16 +1722,13 @@
</term>
<listitem>
<para>
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
<option>lxc.cgroup.dir = my-cgroup/first</option> 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.
</para>
</listitem>
</varlistentry>
Expand Down Expand Up @@ -3093,11 +3054,11 @@
cpus.share prioritize the control group, devices.allow makes
usable the specified devices.</para>
<programlisting>
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
</programlisting>
</refsect2>

Expand Down Expand Up @@ -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
Expand Down
17 changes: 15 additions & 2 deletions src/lxc/attach.c
Original file line number Diff line number Diff line change
Expand Up @@ -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->nonroot_keepcaps) {
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);

Expand Down
42 changes: 42 additions & 0 deletions src/lxc/caps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 13 additions & 0 deletions src/lxc/caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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) \
Expand Down
17 changes: 17 additions & 0 deletions src/lxc/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -1554,6 +1565,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;

Expand Down
4 changes: 4 additions & 0 deletions src/lxc/conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,10 @@ struct lxc_conf {
/* The groups to use for the container. */
lxc_groups_t init_groups;

/* 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;

Expand Down
Loading