GHSA-X9QQ-236J-GJ97

Vulnerability from github – Published: 2023-12-05 23:32 – Updated: 2025-07-22 14:57
VLAI
Summary
Canonical LXD documentation improvement to make clear restricted.devices.disk=allow without restricted.devices.disk.paths also allows shift=true
Details

Summary

If a user has restricted access to a project that is configured with restricted=true, they can gain root access on the system by creating a disk device with shift=true and creating a setuid root executable. This is possible because the shift property is not restricted unless restricted.devices.disk.paths is set.

Details

The following patch shows the offending code with a possible fix:

--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -429,17 +429,19 @@ func (d *disk) validateEnvironmentSourcePath() error {
        if instProject.Name != api.ProjectDefaultName {
                // If restricted disk paths are in force, then check the disk's source is allowed, and record the
                // allowed parent path for later user during device start up sequence.
-               if shared.IsTrue(instProject.Config["restricted"]) && instProject.Config["restricted.devices.disk.paths"] != "" {
-                       allowed, restrictedParentSourcePath := project.CheckRestrictedDevicesDiskPaths(instProject.Config, d.config["source"])
-                       if !allowed {
-                               return fmt.Errorf("Disk source path %q not allowed by project for disk %q", d.config["source"], d.name)
+               if shared.IsTrue(instProject.Config["restricted"]) {
+                       if instProject.Config["restricted.devices.disk.paths"] != "" {
+                               allowed, restrictedParentSourcePath := project.CheckRestrictedDevicesDiskPaths(instProject.Config, d.config["source"])
+                               if !allowed {
+                                       return fmt.Errorf("Disk source path %q not allowed by project for disk %q", d.config["source"], d.name)
+                               }
+
+                               d.restrictedParentSourcePath = shared.HostPath(restrictedParentSourcePath)
                        }

                        if shared.IsTrue(d.config["shift"]) {
                                return fmt.Errorf(`The "shift" property cannot be used with a restricted source path`)
                        }
-
-                       d.restrictedParentSourcePath = shared.HostPath(restrictedParentSourcePath)
                }
        }

PoC

$ lxc project create restricted -c restricted=true -c restricted.devices.disk=allow
$ lxc project switch restricted
$ lxc profile device add default root disk path=/ pool=default
$ lxc init ubuntu:22.04 c1
$ lxc config device add c1 d1 disk source=/ path=/mnt shift=true
$ lxc start c1  # no error

$ lxc project set restricted restricted.devices.disk.paths=/  # explicitly allow mounting /
$ lxc restart c1
Error: Failed to start device "d1": The "shift" property cannot be used with a restricted source path

Created https://github.com/canonical/lxd/issues/12606 to improve the documentation as per https://github.com/canonical/lxd/security/advisories/GHSA-x9qq-236j-gj97#advisory-comment-91918

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/canonical/lxd"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "5.19.0"
            },
            {
              "fixed": "5.20.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "5.19.0"
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/canonical/lxd"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.0.0-20230920084527-cbe39c5d3f14"
            },
            {
              "fixed": "0.0.0-20240118092008-ce1bd0dd37bb"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [],
    "github_reviewed": true,
    "github_reviewed_at": "2023-12-05T23:32:58Z",
    "nvd_published_at": null,
    "severity": "LOW"
  },
  "details": "### Summary\n\nIf a user has restricted access to a project that is configured with `restricted=true`, they can gain root access on the system by creating a disk device with `shift=true` and creating a setuid root executable. This is possible because the `shift` property is not restricted unless `restricted.devices.disk.paths` is set.\n\n### Details\n\nThe following patch shows the offending code with a possible fix:\n```patch\n--- a/lxd/device/disk.go\n+++ b/lxd/device/disk.go\n@@ -429,17 +429,19 @@ func (d *disk) validateEnvironmentSourcePath() error {\n        if instProject.Name != api.ProjectDefaultName {\n                // If restricted disk paths are in force, then check the disk\u0027s source is allowed, and record the\n                // allowed parent path for later user during device start up sequence.\n-               if shared.IsTrue(instProject.Config[\"restricted\"]) \u0026\u0026 instProject.Config[\"restricted.devices.disk.paths\"] != \"\" {\n-                       allowed, restrictedParentSourcePath := project.CheckRestrictedDevicesDiskPaths(instProject.Config, d.config[\"source\"])\n-                       if !allowed {\n-                               return fmt.Errorf(\"Disk source path %q not allowed by project for disk %q\", d.config[\"source\"], d.name)\n+               if shared.IsTrue(instProject.Config[\"restricted\"]) {\n+                       if instProject.Config[\"restricted.devices.disk.paths\"] != \"\" {\n+                               allowed, restrictedParentSourcePath := project.CheckRestrictedDevicesDiskPaths(instProject.Config, d.config[\"source\"])\n+                               if !allowed {\n+                                       return fmt.Errorf(\"Disk source path %q not allowed by project for disk %q\", d.config[\"source\"], d.name)\n+                               }\n+\n+                               d.restrictedParentSourcePath = shared.HostPath(restrictedParentSourcePath)\n                        }\n\n                        if shared.IsTrue(d.config[\"shift\"]) {\n                                return fmt.Errorf(`The \"shift\" property cannot be used with a restricted source path`)\n                        }\n-\n-                       d.restrictedParentSourcePath = shared.HostPath(restrictedParentSourcePath)\n                }\n        }\n```\n\n### PoC\n\n```bash\n$ lxc project create restricted -c restricted=true -c restricted.devices.disk=allow\n$ lxc project switch restricted\n$ lxc profile device add default root disk path=/ pool=default\n$ lxc init ubuntu:22.04 c1\n$ lxc config device add c1 d1 disk source=/ path=/mnt shift=true\n$ lxc start c1  # no error\n\n$ lxc project set restricted restricted.devices.disk.paths=/  # explicitly allow mounting /\n$ lxc restart c1\nError: Failed to start device \"d1\": The \"shift\" property cannot be used with a restricted source path\n```\n\nCreated https://github.com/canonical/lxd/issues/12606 to improve the documentation as per https://github.com/canonical/lxd/security/advisories/GHSA-x9qq-236j-gj97#advisory-comment-91918",
  "id": "GHSA-x9qq-236j-gj97",
  "modified": "2025-07-22T14:57:33Z",
  "published": "2023-12-05T23:32:58Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/canonical/lxd/security/advisories/GHSA-x9qq-236j-gj97"
    },
    {
      "type": "WEB",
      "url": "https://github.com/canonical/lxd/issues/12606"
    },
    {
      "type": "WEB",
      "url": "https://github.com/canonical/lxd/commit/ce1bd0dd37bb3810fe6f16c237a4b65257f231f1"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/canonical/lxd"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [],
  "summary": "Canonical LXD documentation improvement to make clear restricted.devices.disk=allow without restricted.devices.disk.paths also allows shift=true"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.