Version in base suite: 5.0.2-5 Version in overlay suite: 5.0.2-5+deb12u1 Base version: lxd_5.0.2-5+deb12u1 Target version: lxd_5.0.2-5+deb12u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/l/lxd/lxd_5.0.2-5+deb12u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/l/lxd/lxd_5.0.2-5+deb12u2.dsc changelog | 6 patches/104-GHSA-56mx-8g9f-5crf.patch | 262 ++++++++++++++++++++++++++++++++++ patches/series | 1 3 files changed, 269 insertions(+) diff -Nru lxd-5.0.2/debian/changelog lxd-5.0.2/debian/changelog --- lxd-5.0.2/debian/changelog 2025-10-02 16:38:32.000000000 +0000 +++ lxd-5.0.2/debian/changelog 2025-11-11 16:07:42.000000000 +0000 @@ -1,3 +1,9 @@ +lxd (5.0.2-5+deb12u2) bookworm-security; urgency=high + + * Cherry-pick upstream fix for CVE-2025-64507 / GHSA-56mx-8g9f-5crf + + -- Mathias Gibbens Tue, 11 Nov 2025 16:07:42 +0000 + lxd (5.0.2-5+deb12u1) bookworm-security; urgency=high * Backport fixes for the following security issues that are unfixed by diff -Nru lxd-5.0.2/debian/patches/104-GHSA-56mx-8g9f-5crf.patch lxd-5.0.2/debian/patches/104-GHSA-56mx-8g9f-5crf.patch --- lxd-5.0.2/debian/patches/104-GHSA-56mx-8g9f-5crf.patch 1970-01-01 00:00:00.000000000 +0000 +++ lxd-5.0.2/debian/patches/104-GHSA-56mx-8g9f-5crf.patch 2025-11-11 16:04:59.000000000 +0000 @@ -0,0 +1,262 @@ +From 2236fb7001bec8a4dd6a9070eb59d2cc818f833c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?St=C3=A9phane=20Graber?= +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 +(cherry picked from commit b0c6c0bac42c6ac27d536984cc043a6ec02b9e7c) +Signed-off-by: Thomas Parrott +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 +@@ -6,6 +6,7 @@ import ( + "errors" + "fmt" + "io" ++ "io/fs" + "net/http" + "os" + "path/filepath" +@@ -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 +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 +(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 +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 +(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?= +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 +(cherry picked from commit 3abdc12cf6a8dce391d28d340a32c137125357dd) +Signed-off-by: Thomas Parrott +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,8 @@ import ( + "context" + "errors" + "fmt" ++ "io/fs" ++ "net/http" + "os" + "path/filepath" + "strings" +@@ -20,6 +22,7 @@ import ( + "github.com/lxc/lxd/lxd/project" + "github.com/lxc/lxd/lxd/revert" + storagePools "github.com/lxc/lxd/lxd/storage" ++ storageDrivers "github.com/lxc/lxd/lxd/storage/drivers" + "github.com/lxc/lxd/lxd/util" + "github.com/lxc/lxd/shared" + "github.com/lxc/lxd/shared/api" +@@ -83,6 +84,7 @@ var patches = []patch{ + {name: "warnings_remove_empty_node", stage: patchPostDaemonStorage, run: patchRemoveWarningsWithEmptyNode}, + {name: "dnsmasq_entries_include_device_name", stage: patchPostDaemonStorage, run: patchDnsmasqEntriesIncludeDeviceName}, + {name: "storage_missing_snapshot_records", stage: patchPostDaemonStorage, run: patchGenericStorage}, ++ {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/debian/patches/series lxd-5.0.2/debian/patches/series --- lxd-5.0.2/debian/patches/series 2025-10-02 16:38:32.000000000 +0000 +++ lxd-5.0.2/debian/patches/series 2025-11-11 15:41:00.000000000 +0000 @@ -10,3 +10,4 @@ 102-CVE-2025-54288.patch 103a-CVE-2025-54286.patch 103b-CVE-2025-54286.patch +104-GHSA-56mx-8g9f-5crf.patch