Package: release.debian.org Severity: normal Tags: trixie User: [email protected] Usertags: pu X-Debbugs-Cc: [email protected], [email protected] Control: affects -1 + src:incus
[ Reason ] Last week's release of Incus 7.4 included fixes for two moderate severity issues, CVE-2026-81500 and CVE-2026-81501. After discussion with the Security Team, these vulnerabilities won't receive their own DSA, but will be addressed via the upcoming point release. [ Impact ] Incus in trixie is currently vulnerable to CVE-2026-81500 and CVE-2026- 81501. [ Tests ] None -- both security issues are somewhat obscure edge cases, but the fixes have been in the stable release for a week now and no regressions have been reported upstream. [ Risks ] Minor/none -- two targeted fixes cherry-picked from the upstream git repo. [ 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 [ Changes ] Two security fixes as outlined above. Also updated d/changelog with missing CVEs that hadn't been assigned by GitHub when the previous release was uploaded. [ Other info ] The source debdiff is attached.
diff --git a/debian/changelog b/debian/changelog index 438c618e46..8cc80a7c1f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +incus (6.0.4-2+deb13u10) trixie; urgency=medium + + * Cherry-pick fixes for the following security issues + - CVE-2026-81500 / GHSA-9pqw-c7m4-xvg7 + - CVE-2026-81501 / GHSA-c6wx-8679-hpr9 + + -- Mathias Gibbens <[email protected]> Wed, 02 Sep 2026 16:39:29 +0000 + incus (6.0.4-2+deb13u9) trixie-security; urgency=high * Cherry-pick upstream fix for large nft ruleset performance @@ -8,11 +16,11 @@ incus (6.0.4-2+deb13u9) trixie-security; urgency=high - CVE-2026-62941 / GHSA-mq9x-prm8-3vpw - CVE-2026-63125 / GHSA-6rqx-22hc-qm36 - CVE-2026-63343 / GHSA-fmjx-5j3g-997p - - GHSA-26gp-p5fw-3r2h - - GHSA-4qxq-p5hm-3q3p - - GHSA-67qw-68v3-36h6 - - GHSA-m3j6-p3v3-qmjv - - GHSA-p2v3-6wvc-cv3p + - CVE-2026-81493 / GHSA-p2v3-6wvc-cv3p + - CVE-2026-81495 / GHSA-67qw-68v3-36h6 + - CVE-2026-81496 / GHSA-26gp-p5fw-3r2h + - CVE-2026-81497 / GHSA-4qxq-p5hm-3q3p + - CVE-2026-81498 / GHSA-m3j6-p3v3-qmjv * Cherry-pick four additional security fixes not assigned CVEs -- Mathias Gibbens <[email protected]> Thu, 30 Jul 2026 22:57:51 +0000 diff --git a/debian/patches/147-CVE-2026-81500.patch b/debian/patches/147-CVE-2026-81500.patch new file mode 100644 index 0000000000..217f0de519 --- /dev/null +++ b/debian/patches/147-CVE-2026-81500.patch @@ -0,0 +1,91 @@ +From d4d7badf6597274320b78575e77aec5720163c9c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]> +Date: Sun, 23 Aug 2026 17:26:26 -0400 +Subject: [PATCH] client/images: Prevent path traversal in downloaded image + name +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The local filename for an exported image came from server-controlled +data (Content-Disposition for unified images, the simplestreams index +path) and was joined with the target directory. Basename it. + +This addresses GHSA-9pqw-c7m4-xvg7 (CVE pending) + +Signed-off-by: Stéphane Graber <[email protected]> +Rebased-by: Mathias Gibbens <[email protected]> +--- + client/incus_images.go | 4 +++- + client/simplestreams_images.go | 13 +++++++------ + 2 files changed, 10 insertions(+), 7 deletions(-) + +diff --git a/client/incus_images.go b/client/incus_images.go +index ed48d08be..3a0afccb2 100644 +--- a/client/incus_images.go ++++ b/client/incus_images.go +@@ -9,6 +9,7 @@ import ( + "net/http" + "net/url" + "os" ++ "path/filepath" + "slices" + "strings" + "time" +@@ -325,7 +326,8 @@ func incusDownloadImage(fingerprint string, uri string, userAgent string, do fun + } + + resp.MetaSize = size +- resp.MetaName = filename ++ // Basename the server-provided name to prevent path traversal. ++ resp.MetaName = filepath.Base(filename) + + // Check the hash + hash := fmt.Sprintf("%x", sha256.Sum(nil)) +diff --git a/client/simplestreams_images.go b/client/simplestreams_images.go +index 00cc35409..6bbfbe9d4 100644 +--- a/client/simplestreams_images.go ++++ b/client/simplestreams_images.go +@@ -10,6 +10,7 @@ import ( + "net/url" + "os" + "os/exec" ++ "path/filepath" + "strings" + "time" + +@@ -143,8 +144,8 @@ func (r *ProtocolSimpleStreams) GetImageFile(fingerprint string, req ImageFileRe + return nil, err + } + +- parts := strings.Split(meta.Path, "/") +- resp.MetaName = parts[len(parts)-1] ++ // Basename the server-provided name to prevent path traversal. ++ resp.MetaName = filepath.Base(meta.Path) + resp.MetaSize = size + } + +@@ -205,8 +206,8 @@ func (r *ProtocolSimpleStreams) GetImageFile(fingerprint string, req ImageFileRe + return nil, err + } + +- parts := strings.Split(rootfs.Path, "/") +- resp.RootfsName = parts[len(parts)-1] ++ // Basename the server-provided name to prevent path traversal. ++ resp.RootfsName = filepath.Base(rootfs.Path) + resp.RootfsSize = size + downloaded = true + } +@@ -219,8 +220,8 @@ func (r *ProtocolSimpleStreams) GetImageFile(fingerprint string, req ImageFileRe + return nil, err + } + +- parts := strings.Split(rootfs.Path, "/") +- resp.RootfsName = parts[len(parts)-1] ++ // Basename the server-provided name to prevent path traversal. ++ resp.RootfsName = filepath.Base(rootfs.Path) + resp.RootfsSize = size + } + } +-- +2.47.3 diff --git a/debian/patches/148-CVE-2026-81501.patch b/debian/patches/148-CVE-2026-81501.patch new file mode 100644 index 0000000000..f05a56fb8b --- /dev/null +++ b/debian/patches/148-CVE-2026-81501.patch @@ -0,0 +1,115 @@ +From a04abf23169d0597a544c6d96044a0f7aa9f19bf Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?St=C3=A9phane=20Graber?= <[email protected]> +Date: Sun, 23 Aug 2026 17:26:26 -0400 +Subject: [PATCH] incusd/images: Check access before reusing cross-project + image +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +imageDownload reused an image from another project without checking the +caller could view it, letting a client that knew a private fingerprint +import it. Only reuse it directly when public or viewable, otherwise +download it (proving access) and dedupe against the on-disk copy. + +This addresses GHSA-c6wx-8679-hpr9 (CVE pending) + +Signed-off-by: Stéphane Graber <[email protected]> +Rebased-by: Mathias Gibbens <[email protected]> +--- + cmd/incusd/daemon_images.go | 38 +++++++++++++++++++++++++++++++----- + internal/server/db/images.go | 1 + + 2 files changed, 34 insertions(+), 5 deletions(-) + +diff --git a/cmd/incusd/daemon_images.go b/cmd/incusd/daemon_images.go +index 8eafb6de4..c26e1540e 100644 +--- a/cmd/incusd/daemon_images.go ++++ b/cmd/incusd/daemon_images.go +@@ -14,6 +14,7 @@ import ( + + incus "github.com/lxc/incus/v6/client" + internalIO "github.com/lxc/incus/v6/internal/io" ++ "github.com/lxc/incus/v6/internal/server/auth" + "github.com/lxc/incus/v6/internal/server/db" + "github.com/lxc/incus/v6/internal/server/db/cluster" + "github.com/lxc/incus/v6/internal/server/locking" +@@ -195,13 +196,37 @@ func ImageDownload(ctx context.Context, r *http.Request, s *state.State, op *ope + } + } + } else if response.IsNotFoundError(err) { ++ var otherImg *api.Image + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { + // Check if the image already exists in some other project. +- _, imgInfo, err = tx.GetImageFromAnyProject(ctx, fp) ++ _, otherImg, err = tx.GetImageFromAnyProject(ctx, fp) + + return err + }) + if err == nil { ++ // Only reuse another project's image when the caller may see it, ++ // otherwise download it (proving access) and dedupe on disk. ++ reuse := otherImg.Public || r == nil ++ if !reuse { ++ err = s.Authorizer.CheckPermission(ctx, r, auth.ObjectImage(otherImg.Project, otherImg.Fingerprint), auth.EntitlementCanView) ++ if err == nil { ++ reuse = true ++ } else if !api.StatusErrorCheck(err, http.StatusForbidden) { ++ return nil, false, err ++ } ++ ++ err = nil ++ } ++ ++ if reuse { ++ imgInfo = otherImg ++ } else if args.Server == "" { ++ // No source to prove access against. ++ return nil, false, api.StatusErrorf(http.StatusNotFound, "Image not found") ++ } ++ } ++ ++ if err == nil && imgInfo != nil { + var nodeAddress string + + err = s.DB.Cluster.Transaction(ctx, func(ctx context.Context, tx *db.ClusterTx) error { +@@ -317,9 +342,9 @@ func ImageDownload(ctx context.Context, r *http.Request, s *state.State, op *ope + return nil, false, fmt.Errorf("Invalid image fingerprint") + } + +- // Cleanup any leftover from a past attempt ++ // Download to a temporary name so an existing on-disk copy isn't overwritten. + destDir := internalUtil.VarPath("images") +- destName := filepath.Join(destDir, fp) ++ destName := filepath.Join(destDir, fp+".download") + + failure := true + cleanup := func() { +@@ -576,9 +601,12 @@ func ImageDownload(ctx context.Context, r *http.Request, s *state.State, op *ope + return nil, false, fmt.Errorf("Invalid image fingerprint") + } + +- // Check if the image path changed (private images) ++ // Reuse an existing on-disk copy if present, otherwise move ours into place. + newDestName := filepath.Join(destDir, fp) +- if newDestName != destName { ++ if util.PathExists(newDestName) { ++ _ = os.Remove(destName) ++ _ = os.Remove(destName + ".rootfs") ++ } else { + err = internalUtil.FileMove(destName, newDestName) + if err != nil { + return nil, false, err +diff --git a/internal/server/db/images.go b/internal/server/db/images.go +index 2a730e596..b3719becf 100644 +--- a/internal/server/db/images.go ++++ b/internal/server/db/images.go +@@ -436,6 +436,7 @@ func (c *ClusterTx) GetImageFromAnyProject(ctx context.Context, fingerprint stri + + object = images[0] + ++ image.Project = object.Project + image.Fingerprint = object.Fingerprint + image.Filename = object.Filename + image.Size = object.Size +-- +2.47.3 diff --git a/debian/patches/series b/debian/patches/series index 45d2cab03b..f04af2fc4f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -54,3 +54,5 @@ 144-GHSA-m3j6-p3v3-qmjv.patch 145-GHSA-p2v3-6wvc-cv3p.patch 146-incus-7.3-fixes.patch +147-CVE-2026-81500.patch +148-CVE-2026-81501.patch
signature.asc
Description: This is a digitally signed message part

