Your message dated Sat, 10 Jan 2026 11:52:34 +0000
with message-id <[email protected]>
and subject line Released with 13.3
has caused the Debian Bug report #1120520,
regarding trixie-pu: package lxd/5.0.2+git20231211.1364ae4-9+deb13u2
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1120520: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1120520
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
Tags: trixie
User: [email protected]
Usertags: pu
X-Debbugs-Cc: [email protected], [email protected]
Control: affects -1 + src:lxd

[ Reason ]
While investigating CVE-2025-64507, I discovered that filesystem ID
mapping is broken for LXD in trixie. This renders the attack
unexploitable (yay!) but is a regression for anyone who wants/needs to
setup filesystem ID mapping.

After discussion with the Security Team, I have prepared this updated
version of LXD that fixes both the ID mapping and relevant CVE. Please
note that is NOT being treated as a security update for trixie and it's
fine to be included in the 13.3 point release.

[ Impact ]
Users cannot currently configure filesystem ID mapping for their
containers/VMs.

[ Tests ]
I have manually tested creating containers with an ID-shifted storage
volume and verified it works as expected and that the mitigation for
CVE-2025-64507 prevents the attack.

[ Risks ]
Minor/none -- the regression fix has been in the stable-5.0 branch for
a year and a half, and the CVE has been applied on all upstream
supported LXD/Incus branches.

[ Checklist ]
  [*] *all* changes are documented in the d/changelog
  [*] I reviewed all changes and I approve them
  [*] attach debdiff against the package in (old)stable
  [ ] the issue is verified as fixed in unstable
      NOTE: lxd was RM'ed from unstable, so there is no fix to
            apply there

[ Changes ]
Cherry-pick relevant fixes Canonical's stable-5.0 branch.

[ Other info ]
The source debdiff is attached.
diff -Nru lxd-5.0.2+git20231211.1364ae4/debian/changelog lxd-5.0.2+git20231211.1364ae4/debian/changelog
--- lxd-5.0.2+git20231211.1364ae4/debian/changelog	2025-10-02 16:23:38.000000000 +0000
+++ lxd-5.0.2+git20231211.1364ae4/debian/changelog	2025-11-11 15:25:08.000000000 +0000
@@ -1,3 +1,10 @@
+lxd (5.0.2+git20231211.1364ae4-9+deb13u2) trixie; urgency=medium
+
+  * Cherry-pick upstream fix for broken idmapping with kernel 6.9+
+  * Cherry-pick upstream fix for CVE-2025-64507 / GHSA-56mx-8g9f-5crf
+
+ -- Mathias Gibbens <[email protected]>  Tue, 11 Nov 2025 15:25:08 +0000
+
 lxd (5.0.2+git20231211.1364ae4-9+deb13u1) trixie-security; urgency=high
 
   * Backport fixes for the following security issues that are unfixed by
diff -Nru lxd-5.0.2+git20231211.1364ae4/debian/patches/013-cherry-pick-fix-idmapping.patch lxd-5.0.2+git20231211.1364ae4/debian/patches/013-cherry-pick-fix-idmapping.patch
--- lxd-5.0.2+git20231211.1364ae4/debian/patches/013-cherry-pick-fix-idmapping.patch	1970-01-01 00:00:00.000000000 +0000
+++ lxd-5.0.2+git20231211.1364ae4/debian/patches/013-cherry-pick-fix-idmapping.patch	2025-11-11 15:25:08.000000000 +0000
@@ -0,0 +1,111 @@
+From 891b129ab6dde6c63eb7cdadbbd746419d2f6d26 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]>
+Date: Wed, 22 May 2024 13:29:18 -0400
+Subject: [PATCH] shared/idmap: Make get_userns_fd configure the userns
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Stéphane Graber <[email protected]>
+(cherry picked from commit ec223f75e7056f271fb84be56980243cd68e67b3)
+Signed-off-by: Alexander Mikhalitsyn <[email protected]>
+License: Apache-2.0
+---
+ lxd/idmap/shift_linux.go | 68 +++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 64 insertions(+), 4 deletions(-)
+
+diff --git a/shared/idmap/shift_linux.go b/shared/idmap/shift_linux.go
+index 024c55fa819b..d8fbff31101e 100644
+--- a/shared/idmap/shift_linux.go
++++ b/shared/idmap/shift_linux.go
+@@ -279,19 +279,78 @@ static int get_userns_fd_cb(void *data)
+ 
+ static int get_userns_fd(void)
+ {
+-	int ret;
++	int userns_fd = -EBADF;
++	int file_fd = -EBADF;
+ 	pid_t pid;
+ 	char path[256];
+ 
++	// Create the namespace.
+ 	pid = do_clone(get_userns_fd_cb, NULL, CLONE_NEWUSER);
+ 	if (pid < 0)
+-		return -errno;
++		goto err;
+ 
++	// Fetch a reference.
+ 	snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
+-	ret = open(path, O_RDONLY | O_CLOEXEC);
++	userns_fd = open(path, O_RDONLY | O_CLOEXEC);
++	if (userns_fd < 0)
++		goto err_process;
++
++	// Setup uid_map
++	snprintf(path, sizeof(path), "/proc/%d/uid_map", pid);
++	file_fd = openat(AT_FDCWD, path, O_WRONLY);
++	if (file_fd < 0)
++		goto err_process;
++
++	if (write(file_fd, "0 0 1", 5) != 5)
++		goto err_process;
++
++	if (close(file_fd) < 0) {
++		file_fd = -EBADF;
++		goto err_process;
++	}
++
++	// Setup setgroups
++	snprintf(path, sizeof(path), "/proc/%d/setgroups", pid);
++	file_fd = openat(AT_FDCWD, path, O_WRONLY);
++	if (file_fd < 0)
++		goto err_process;
++
++	if (write(file_fd, "deny", 4) != 4)
++		goto err_process;
++
++	if (close(file_fd) < 0) {
++		file_fd = -EBADF;
++		goto err_process;
++	}
++
++	// Setup gid_map
++	snprintf(path, sizeof(path), "/proc/%d/gid_map", pid);
++	file_fd = openat(AT_FDCWD, path, O_WRONLY);
++	if (file_fd < 0)
++		goto err_process;
++
++	if (write(file_fd, "0 0 1", 5) != 5)
++		goto err_process;
++
++	if (close(file_fd) < 0) {
++		file_fd = -EBADF;
++		goto err_process;
++	}
++
++	// Kill the temporary process.
++	kill(pid, SIGKILL);
++	wait_for_pid(pid);
++
++	return userns_fd;
++
++err_process:
+ 	kill(pid, SIGKILL);
+ 	wait_for_pid(pid);
+-	return ret;
++
++err:
++	close(userns_fd);
++	close(file_fd);
++	return -1;
+ }
+ 
+ static int create_detached_idmapped_mount(const char *path, const char *fstype)
+@@ -335,6 +394,7 @@ static int create_detached_idmapped_mount(const char *path, const char *fstype)
+ 	if (ret < 0)
+ 		return -errno;
+ 
++	close(fd_userns);
+ 	return 0;
+ }
+ */
diff -Nru lxd-5.0.2+git20231211.1364ae4/debian/patches/104-GHSA-56mx-8g9f-5crf.patch lxd-5.0.2+git20231211.1364ae4/debian/patches/104-GHSA-56mx-8g9f-5crf.patch
--- lxd-5.0.2+git20231211.1364ae4/debian/patches/104-GHSA-56mx-8g9f-5crf.patch	1970-01-01 00:00:00.000000000 +0000
+++ lxd-5.0.2+git20231211.1364ae4/debian/patches/104-GHSA-56mx-8g9f-5crf.patch	2025-11-11 15:25:08.000000000 +0000
@@ -0,0 +1,245 @@
+From 2236fb7001bec8a4dd6a9070eb59d2cc818f833c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]>
+Date: Sun, 9 Nov 2025 18:41:24 -0500
+Subject: [PATCH 1/5] lxd/storage: Tighten storage pool volume permissions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related to https://github.com/lxc/incus/issues/2641
+
+Signed-off-by: Stéphane Graber <[email protected]>
+(cherry picked from commit b0c6c0bac42c6ac27d536984cc043a6ec02b9e7c)
+Signed-off-by: Thomas Parrott <[email protected]>
+License: Apache-2.0
+(cherry picked from commit 7598d5ab710e05829c7bc4a6e30106a022f376c1)
+(cherry picked from commit 049d86def7c26e8736bb991e4223ec89dab0b05e)
+---
+ lxd/storage/backend_lxd.go              |  4 ++--
+ lxd/storage/drivers/driver_btrfs.go     |  2 +-
+ lxd/storage/drivers/driver_zfs_utils.go |  3 +--
+ lxd/storage/drivers/generic_vfs.go      |  4 ++--
+ lxd/storage/drivers/volume.go           | 17 +++++++++++------
+ 5 files changed, 17 insertions(+), 13 deletions(-)
+
+diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
+index 76be2843343b..7da6aaf631df 100644
+--- a/lxd/storage/backend_lxd.go
++++ b/lxd/storage/backend_lxd.go
+@@ -5116,9 +5116,9 @@ func (b *lxdBackend) RestoreCustomVolume(projectName, volName string, snapshotNa
+ 
+ func (b *lxdBackend) createStorageStructure(path string) error {
+ 	for _, volType := range b.driver.Info().VolumeTypes {
+-		for _, name := range drivers.BaseDirectories[volType] {
++		for _, name := range drivers.BaseDirectories[volType].Paths {
+ 			path := filepath.Join(path, name)
+-			err := os.MkdirAll(path, 0711)
++			err := os.MkdirAll(path, drivers.BaseDirectories[volType].Mode)
+ 			if err != nil && !os.IsExist(err) {
+ 				return fmt.Errorf("Failed to create directory %q: %w", path, err)
+ 			}
+diff --git a/lxd/storage/drivers/driver_btrfs.go b/lxd/storage/drivers/driver_btrfs.go
+index 89310350d3bb..1e8577043cc5 100644
+--- a/lxd/storage/drivers/driver_btrfs.go
++++ b/lxd/storage/drivers/driver_btrfs.go
+@@ -283,7 +283,7 @@ func (d *btrfs) Delete(op *operations.Operation) error {
+ 
+ 	// Delete potential intermediate btrfs subvolumes.
+ 	for _, volType := range d.Info().VolumeTypes {
+-		for _, dir := range BaseDirectories[volType] {
++		for _, dir := range BaseDirectories[volType].Paths {
+ 			path := filepath.Join(GetPoolMountPath(d.name), dir)
+ 			if !shared.PathExists(path) {
+ 				continue
+diff --git a/lxd/storage/drivers/driver_zfs_utils.go b/lxd/storage/drivers/driver_zfs_utils.go
+index 0381c98be034..d72f5add2527 100644
+--- a/lxd/storage/drivers/driver_zfs_utils.go
++++ b/lxd/storage/drivers/driver_zfs_utils.go
+@@ -286,8 +286,7 @@ func (d *zfs) initialDatasets() []string {
+ 
+ 	// Iterate over the listed supported volume types.
+ 	for _, volType := range d.Info().VolumeTypes {
+-		entries = append(entries, BaseDirectories[volType][0])
+-		entries = append(entries, filepath.Join("deleted", BaseDirectories[volType][0]))
++		entries = append(entries, BaseDirectories[volType].Paths[0], "deleted/"+BaseDirectories[volType].Paths[0])
+ 	}
+ 
+ 	return entries
+diff --git a/lxd/storage/drivers/generic_vfs.go b/lxd/storage/drivers/generic_vfs.go
+index 03e729b4092f..7327a5b43487 100644
+--- a/lxd/storage/drivers/generic_vfs.go
++++ b/lxd/storage/drivers/generic_vfs.go
+@@ -1153,11 +1153,11 @@ func genericVFSListVolumes(d Driver) ([]Volume, error) {
+ 	poolMountPath := GetPoolMountPath(poolName)
+ 
+ 	for _, volType := range d.Info().VolumeTypes {
+-		if len(BaseDirectories[volType]) < 1 {
++		if len(BaseDirectories[volType].Paths) < 1 {
+ 			return nil, fmt.Errorf("Cannot get base directory name for volume type %q", volType)
+ 		}
+ 
+-		volTypePath := filepath.Join(poolMountPath, BaseDirectories[volType][0])
++		volTypePath := filepath.Join(poolMountPath, BaseDirectories[volType].Paths[0])
+ 		ents, err := os.ReadDir(volTypePath)
+ 		if err != nil {
+ 			return nil, fmt.Errorf("Failed to list directory %q for volume type %q: %w", volTypePath, volType, err)
+diff --git a/lxd/storage/drivers/volume.go b/lxd/storage/drivers/volume.go
+index 96ee6ffcfa11..c2188b826004 100644
+--- a/lxd/storage/drivers/volume.go
++++ b/lxd/storage/drivers/volume.go
+@@ -76,13 +76,18 @@ const ContentTypeISO = ContentType("iso")
+ // VolumePostHook function returned from a storage action that should be run later to complete the action.
+ type VolumePostHook func(vol Volume) error
+ 
++type baseDirectory struct {
++	Paths []string
++	Mode  os.FileMode
++}
++
+ // BaseDirectories maps volume types to the expected directories.
+-var BaseDirectories = map[VolumeType][]string{
+-	VolumeTypeBucket:    {"buckets"},
+-	VolumeTypeContainer: {"containers", "containers-snapshots"},
+-	VolumeTypeCustom:    {"custom", "custom-snapshots"},
+-	VolumeTypeImage:     {"images"},
+-	VolumeTypeVM:        {"virtual-machines", "virtual-machines-snapshots"},
++var BaseDirectories = map[VolumeType]baseDirectory{
++	VolumeTypeBucket:    {Paths: []string{"buckets"}, Mode: 0o711},
++	VolumeTypeContainer: {Paths: []string{"containers", "containers-snapshots"}, Mode: 0o711},
++	VolumeTypeCustom:    {Paths: []string{"custom", "custom-snapshots"}, Mode: 0o700},
++	VolumeTypeImage:     {Paths: []string{"images"}, Mode: 0o700},
++	VolumeTypeVM:        {Paths: []string{"virtual-machines", "virtual-machines-snapshots"}, Mode: 0o700},
+ }
+ 
+ // Volume represents a storage volume, and provides functions to mount and unmount it.
+
+From 54eca5752e47bd9443f43850ca8241074de49609 Mon Sep 17 00:00:00 2001
+From: Thomas Parrott <[email protected]>
+Date: Mon, 10 Nov 2025 10:49:26 +0000
+Subject: [PATCH 2/5] lxd/storage/drivers/volume: Add comments explaining
+ differences in BaseDirectories permissions
+
+Signed-off-by: Thomas Parrott <[email protected]>
+(cherry picked from commit 52a551c8f0452eda858ac7ba27dc250d84ce72bf)
+(cherry picked from commit 10ad9d7419b4127cd127d2850e79aee3e1dc07e1)
+---
+ lxd/storage/drivers/volume.go | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/lxd/storage/drivers/volume.go b/lxd/storage/drivers/volume.go
+index c2188b826004..3ef75f98c671 100644
+--- a/lxd/storage/drivers/volume.go
++++ b/lxd/storage/drivers/volume.go
+@@ -83,8 +83,8 @@ type baseDirectory struct {
+ 
+ // BaseDirectories maps volume types to the expected directories.
+ var BaseDirectories = map[VolumeType]baseDirectory{
+-	VolumeTypeBucket:    {Paths: []string{"buckets"}, Mode: 0o711},
+-	VolumeTypeContainer: {Paths: []string{"containers", "containers-snapshots"}, Mode: 0o711},
++	VolumeTypeBucket:    {Paths: []string{"buckets"}, Mode: 0o711},                            // MinIO is run as non-root, so 0700 won't work, however as S3 interface doesn't allow creation of setuid binaries this is OK.
++	VolumeTypeContainer: {Paths: []string{"containers", "containers-snapshots"}, Mode: 0o711}, // Containers may be run as non-root, so 0700 won't work, however as containers have their own sub-directory with correct ownership that is 0100 this is OK.
+ 	VolumeTypeCustom:    {Paths: []string{"custom", "custom-snapshots"}, Mode: 0o700},
+ 	VolumeTypeImage:     {Paths: []string{"images"}, Mode: 0o700},
+ 	VolumeTypeVM:        {Paths: []string{"virtual-machines", "virtual-machines-snapshots"}, Mode: 0o700},
+
+From 693c65f114b7ab94f896e38f3deaa3b53a48c6e1 Mon Sep 17 00:00:00 2001
+From: Thomas Parrott <[email protected]>
+Date: Mon, 10 Nov 2025 09:35:28 +0000
+Subject: [PATCH 3/5] lxd/storage/backend/lxd: Replace deprecated os.IsExist
+
+Signed-off-by: Thomas Parrott <[email protected]>
+(cherry picked from commit 89c0906e5107fa059263490d020b99dfa1c9c26b)
+(cherry picked from commit 97219271d4c67e388e584944349a87f86647fcdb)
+---
+ lxd/storage/backend_lxd.go | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lxd/storage/backend_lxd.go b/lxd/storage/backend_lxd.go
+index 7da6aaf631df..f76847380c6e 100644
+--- a/lxd/storage/backend_lxd.go
++++ b/lxd/storage/backend_lxd.go
+@@ -5119,7 +5119,7 @@ func (b *lxdBackend) createStorageStructure(path string) error {
+ 		for _, name := range drivers.BaseDirectories[volType].Paths {
+ 			path := filepath.Join(path, name)
+ 			err := os.MkdirAll(path, drivers.BaseDirectories[volType].Mode)
+-			if err != nil && !os.IsExist(err) {
++			if err != nil && !errors.Is(err, fs.ErrExist) {
+ 				return fmt.Errorf("Failed to create directory %q: %w", path, err)
+ 			}
+ 		}
+
+From 849ed20a5fbb5229efec24c98ca3caee608fd87d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]>
+Date: Sun, 9 Nov 2025 18:41:39 -0500
+Subject: [PATCH 4/5] lxd/patches: Re-apply storage permissions on update
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Related to https://github.com/lxc/incus/issues/2641
+
+Signed-off-by: Stéphane Graber <[email protected]>
+(cherry picked from commit 3abdc12cf6a8dce391d28d340a32c137125357dd)
+Signed-off-by: Thomas Parrott <[email protected]>
+License: Apache-2.0
+(cherry picked from commit 87a34bbe6bd3f918081db431ac1a6ee22346f172)
+(cherry picked from commit b2d38e82bda982e337a3cbdc173ec4b372ab8b24)
+---
+ lxd/patches.go | 32 ++++++++++++++++++++++++++++++++
+ 1 file changed, 32 insertions(+)
+
+diff --git a/lxd/patches.go b/lxd/patches.go
+index 01ad6926aed1..b4559b13fde0 100644
+--- a/lxd/patches.go
++++ b/lxd/patches.go
+@@ -4,6 +4,7 @@ import (
+ 	"context"
+ 	"errors"
+ 	"fmt"
++	"io/fs"
+ 	"net/http"
+ 	"os"
+ 	"path/filepath"
+@@ -83,6 +84,7 @@ var patches = []patch{
+ 	{name: "zfs_set_content_type_user_property", stage: patchPostDaemonStorage, run: patchZfsSetContentTypeUserProperty},
+ 	{name: "storage_zfs_unset_invalid_block_settings", stage: patchPostDaemonStorage, run: patchStorageZfsUnsetInvalidBlockSettings},
+ 	{name: "storage_zfs_unset_invalid_block_settings_v2", stage: patchPostDaemonStorage, run: patchStorageZfsUnsetInvalidBlockSettingsV2},
++	{name: "pool_fix_default_permissions", stage: patchPostDaemonStorage, run: patchDefaultStoragePermissions},
+ }
+ 
+ type patch struct {
+@@ -1148,4 +1149,34 @@ func patchStorageZfsUnsetInvalidBlockSettingsV2(_ string, d *Daemon) error {
+ 	return nil
+ }
+ 
++// patchDefaultStoragePermissions re-applies the default modes to all storage pools.
++func patchDefaultStoragePermissions(_ string, d *Daemon) error {
++	s := d.State()
++
++	pools, err := s.DB.Cluster.GetStoragePoolNames()
++	if err != nil {
++		// Skip the rest of the patch if no storage pools were found.
++		if api.StatusErrorCheck(err, http.StatusNotFound) {
++			return nil
++		}
++
++		return fmt.Errorf("Failed getting storage pool names: %w", err)
++	}
++
++	for _, pool := range pools {
++		for _, volEntry := range storageDrivers.BaseDirectories {
++			for _, volDir := range volEntry.Paths {
++				path := storageDrivers.GetPoolMountPath(pool) + "/" + volDir
++
++				err := os.Chmod(path, volEntry.Mode)
++				if err != nil && !errors.Is(err, fs.ErrNotExist) {
++					return fmt.Errorf("Failed to set directory mode %q: %w", path, err)
++				}
++			}
++		}
++	}
++
++	return nil
++}
++
+ // Patches end here
diff -Nru lxd-5.0.2+git20231211.1364ae4/debian/patches/series lxd-5.0.2+git20231211.1364ae4/debian/patches/series
--- lxd-5.0.2+git20231211.1364ae4/debian/patches/series	2025-10-02 16:23:38.000000000 +0000
+++ lxd-5.0.2+git20231211.1364ae4/debian/patches/series	2025-11-11 15:25:08.000000000 +0000
@@ -9,8 +9,10 @@
 010-cherry-pick-update-test-cert.patch
 011-newer-qemu-fixes.patch
 012-fix-issues-with-old-nvram.patch
+013-cherry-pick-fix-idmapping.patch
 100-CVE-2025-54293.patch
 101-CVE-2025-54287.patch
 102-CVE-2025-54288.patch
 103a-CVE-2025-54286.patch
 103b-CVE-2025-54286.patch
+104-GHSA-56mx-8g9f-5crf.patch

Attachment: signature.asc
Description: This is a digitally signed message part


--- End Message ---
--- Begin Message ---
Package: release.debian.org\nVersion: 13.3\n\nThis update has been released as 
part of Debian 13.3.

--- End Message ---

Reply via email to