GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration

CVE-2026-89767 (GCVE-0-2026-89767)

Vulnerability from cvelistv5 – Published: 2026-09-11 19:47 – Updated: 2026-09-13 06:34
VLAI
Title
ovl: fix double end_creating() on the casefold-mismatch path
Summary
In the Linux kernel, the following vulnerability has been resolved: ovl: fix double end_creating() on the casefold-mismatch path ovl_create_real() releases the new dentry twice when the casefold consistency check fails. The S_IFDIR branch calls end_creating() and sets err, then falls through to the common out: label which calls end_creating() on the same dentry again: case S_IFDIR: newdentry = ovl_do_mkdir(ofs, dir, newdentry, attr->mode); err = PTR_ERR_OR_ZERO(newdentry); if (!err && ofs->casefold != ovl_dentry_casefolded(newdentry)) { pr_warn_ratelimited(...); end_creating(newdentry); /* first */ err = -EINVAL; } break; ... if (err) goto out; ... out: if (err) { end_creating(newdentry); /* second, same dentry */ return ERR_PTR(err); } end_creating() is end_dirop(), which does inode_unlock() on the parent and dput() on the dentry, so the parent directory's i_rwsem is unlocked twice and the dentry is put twice. The second unlock releases a lock that is not held, which is what wedges every later creation under that parent, and the second dput() drops a reference that was never taken. The branch was added by commit dfc7da402ccc ("ovl: Check for casefold consistency when creating new dentries") as a bare dput(), which already released the reference twice; commit fe497f0759e0 ("VFS: change vfs_mkdir() to unlock on failure.") converted both sites to end_creating(), adding the double unlock. This is reachable by an unprivileged user. The casefold consistency of the layers is validated at mount time in ovl_parse_layer(), and again on every lookup in ovl_lookup_single(), but ofs->workdir is the internal "work" subdirectory created inside the user-supplied workdir, and that subdirectory is not re-checked. Marking it casefolded after the mount therefore makes every ovl_create_temp() inherit the wrong state - and that path reaches ovl_create_real() through ovl_start_creating_temp(), which uses start_creating() with a generated name and so never runs the lookup-time check. unshare -Urm mount -t tmpfs -o casefold=utf8-12.1.0 tmpfs mnt mkdir -p mnt/lower/d mnt/upper mnt/work mnt/merged mount -t overlay ovl -o lowerdir=mnt/lower,\ upperdir=mnt/upper,workdir=mnt/work mnt/merged chattr +F mnt/work/work mkdir mnt/merged/d/sub # directory copy-up overlayfs: wrong inherited casefold (work/#5) and the next copy-up blocks forever on the parent's i_rwsem: mkdir D start_creating+0x65/0xb0 ovl_start_creating_temp+0xb0/0xe0 [overlay] ovl_create_temp+0xa3/0x1d0 [overlay] ovl_copy_up_one+0x1f1c/0x21c0 [overlay] ovl_copy_up_flags+0xf5/0x140 [overlay] ovl_create_object+0xb7/0x220 [overlay] ovl_mkdir+0x23/0x40 [overlay] Drop the end_creating() from the branch and let out: own the cleanup, which is what every other error path in this function already does.
Impacted products
Vendor Product Version CPE status
Linux Linux Affected: dfc7da402ccc92d6e4b01a4778a3f15f2496b9af , < 2fa220bc0f84597cb6de665e5b5021c5901ddf00 (git)
Affected: dfc7da402ccc92d6e4b01a4778a3f15f2496b9af , < b1aa8ab78a8e87aee9e306971465408e059f839a (git)
Affected: dfc7da402ccc92d6e4b01a4778a3f15f2496b9af , < 077ab8985ee278c3d8618182d335b0f0cd919e16 (git)
guessed Create a notification for this product.
Linux Linux Affected: 6.18
Unaffected: 0 , < 6.18 (semver)
Unaffected: 6.18.51 , ≤ 6.18.* (semver)
Unaffected: 7.2.4 , ≤ 7.2.* (semver)
Unaffected: 7.3-rc1 , ≤ * (original_commit_for_fix)
guessed Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "fs/overlayfs/dir.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "2fa220bc0f84597cb6de665e5b5021c5901ddf00",
              "status": "affected",
              "version": "dfc7da402ccc92d6e4b01a4778a3f15f2496b9af",
              "versionType": "git"
            },
            {
              "lessThan": "b1aa8ab78a8e87aee9e306971465408e059f839a",
              "status": "affected",
              "version": "dfc7da402ccc92d6e4b01a4778a3f15f2496b9af",
              "versionType": "git"
            },
            {
              "lessThan": "077ab8985ee278c3d8618182d335b0f0cd919e16",
              "status": "affected",
              "version": "dfc7da402ccc92d6e4b01a4778a3f15f2496b9af",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "fs/overlayfs/dir.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "6.18"
            },
            {
              "lessThan": "6.18",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.18.*",
              "status": "unaffected",
              "version": "6.18.51",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "7.2.*",
              "status": "unaffected",
              "version": "7.2.4",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "7.3-rc1",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "6.18.51",
                  "versionStartIncluding": "6.18",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.2.4",
                  "versionStartIncluding": "6.18",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.3-rc1",
                  "versionStartIncluding": "6.18",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\novl: fix double end_creating() on the casefold-mismatch path\n\novl_create_real() releases the new dentry twice when the casefold\nconsistency check fails.  The S_IFDIR branch calls end_creating() and\nsets err, then falls through to the common out: label which calls\nend_creating() on the same dentry again:\n\n\tcase S_IFDIR:\n\t\tnewdentry = ovl_do_mkdir(ofs, dir, newdentry, attr-\u003emode);\n\t\terr = PTR_ERR_OR_ZERO(newdentry);\n\t\tif (!err \u0026\u0026 ofs-\u003ecasefold != ovl_dentry_casefolded(newdentry)) {\n\t\t\tpr_warn_ratelimited(...);\n\t\t\tend_creating(newdentry);\t/* first */\n\t\t\terr = -EINVAL;\n\t\t}\n\t\tbreak;\n\t...\n\tif (err)\n\t\tgoto out;\n\t...\n out:\n\tif (err) {\n\t\tend_creating(newdentry);\t/* second, same dentry */\n\t\treturn ERR_PTR(err);\n\t}\n\nend_creating() is end_dirop(), which does inode_unlock() on the parent\nand dput() on the dentry, so the parent directory\u0027s i_rwsem is unlocked\ntwice and the dentry is put twice.  The second unlock releases a lock\nthat is not held, which is what wedges every later creation under that\nparent, and the second dput() drops a reference that was never taken.\n\nThe branch was added by commit dfc7da402ccc (\"ovl: Check for casefold\nconsistency when creating new dentries\") as a bare dput(), which already\nreleased the reference twice; commit fe497f0759e0 (\"VFS: change\nvfs_mkdir() to unlock on failure.\") converted both sites to\nend_creating(), adding the double unlock.\n\nThis is reachable by an unprivileged user.  The casefold consistency of\nthe layers is validated at mount time in ovl_parse_layer(), and again on\nevery lookup in ovl_lookup_single(), but ofs-\u003eworkdir is the internal\n\"work\" subdirectory created inside the user-supplied workdir, and that\nsubdirectory is not re-checked.  Marking it casefolded after the mount\ntherefore makes every ovl_create_temp() inherit the wrong state - and\nthat path reaches ovl_create_real() through ovl_start_creating_temp(),\nwhich uses start_creating() with a generated name and so never runs the\nlookup-time check.\n\n  unshare -Urm\n  mount -t tmpfs -o casefold=utf8-12.1.0 tmpfs mnt\n  mkdir -p mnt/lower/d mnt/upper mnt/work mnt/merged\n  mount -t overlay ovl -o lowerdir=mnt/lower,\\\n        upperdir=mnt/upper,workdir=mnt/work mnt/merged\n  chattr +F mnt/work/work\n  mkdir mnt/merged/d/sub\t\t# directory copy-up\n\n  overlayfs: wrong inherited casefold (work/#5)\n\nand the next copy-up blocks forever on the parent\u0027s i_rwsem:\n\n  mkdir           D  start_creating+0x65/0xb0\n                     ovl_start_creating_temp+0xb0/0xe0 [overlay]\n                     ovl_create_temp+0xa3/0x1d0 [overlay]\n                     ovl_copy_up_one+0x1f1c/0x21c0 [overlay]\n                     ovl_copy_up_flags+0xf5/0x140 [overlay]\n                     ovl_create_object+0xb7/0x220 [overlay]\n                     ovl_mkdir+0x23/0x40 [overlay]\n\nDrop the end_creating() from the branch and let out: own the cleanup,\nwhich is what every other error path in this function already does."
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "baseScore": 7.8,
            "baseSeverity": "HIGH",
            "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
            "version": "3.1"
          },
          "scenarios": [
            {
              "lang": "en",
              "value": "AV:L - The bug is in overlayfs ovl_create_real() on the S_IFDIR casefold-mismatch path, reached from local mkdir/creat copy-up (ovl_mkdir \u2192 ovl_create_object \u2192 ovl_copy_up_one \u2192 ovl_create_temp). An unprivileged user can mount overlay on tmpfs in a user+mount namespace; this is not a network packet path.\nAC:L - The attacker fully controls the overlay mount, the post-mount chattr +F on the internal work/ workdir, and the mkdir that forces directory copy-up. The mismatch is deterministic with no race or victim state beyond the attacker\u0027s control.\nPR:L - Overlayfs sets FS_USERNS_MOUNT, so a normal local user can unshare a user and mount namespace, mount overlay, and reach ovl_create_real without init-namespace root. The commit\u0027s unshare -Urm reproducer matches this unprivileged path.\nUI:N - The attacker mounts the overlay, marks the internal workdir casefolded, and issues mkdir themselves. No separate victim action is required.\nS:U - Double end_creating() corrupts kernel VFS locking and dentry references on the local host. This stays within the kernel\u0027s security authority and is not a VM escape, IOMMU bypass, or other cross-boundary impact.\nC:H - end_creating() is end_dirop(), which inode_unlock()s the parent and dput()s the dentry. The extra dput can free or underflow a still-used dentry, and the extra unlock corrupts i_rwsem so concurrent VFS operations can race, enabling kernel memory disclosure.\nI:H - Double dput plus double inode_unlock of the parent i_rwsem break directory serialization and dentry lifetime. That enables use-after-free and unsynchronized create/lookup on the workdir, a high-integrity kernel memory-corruption primitive.\nA:H - The extra unlock leaves the workdir i_rwsem corrupt so later copy-up/create sleeps uninterruptibly in D state, and the extra dput/UAF can oops or panic the kernel. Either outcome is high availability impact."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-09-13T06:34:10.053Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/2fa220bc0f84597cb6de665e5b5021c5901ddf00"
        },
        {
          "url": "https://git.kernel.org/stable/c/b1aa8ab78a8e87aee9e306971465408e059f839a"
        },
        {
          "url": "https://git.kernel.org/stable/c/077ab8985ee278c3d8618182d335b0f0cd919e16"
        }
      ],
      "title": "ovl: fix double end_creating() on the casefold-mismatch path",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2026-89767",
    "datePublished": "2026-09-11T19:47:07.353Z",
    "dateReserved": "2026-09-11T19:38:34.764Z",
    "dateUpdated": "2026-09-13T06:34:10.053Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-89767",
      "date": "2026-09-16",
      "epss": "0.00151",
      "percentile": "0.04638"
    },
    "nvd": "{\"cve\":{\"id\":\"CVE-2026-89767\",\"sourceIdentifier\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"published\":\"2026-09-11T20:20:07.960\",\"lastModified\":\"2026-09-13T07:17:41.050\",\"vulnStatus\":\"Received\",\"cveTags\":[],\"descriptions\":[{\"lang\":\"en\",\"value\":\"In the Linux kernel, the following vulnerability has been resolved:\\n\\novl: fix double end_creating() on the casefold-mismatch path\\n\\novl_create_real() releases the new dentry twice when the casefold\\nconsistency check fails.  The S_IFDIR branch calls end_creating() and\\nsets err, then falls through to the common out: label which calls\\nend_creating() on the same dentry again:\\n\\n\\tcase S_IFDIR:\\n\\t\\tnewdentry = ovl_do_mkdir(ofs, dir, newdentry, attr-\u003emode);\\n\\t\\terr = PTR_ERR_OR_ZERO(newdentry);\\n\\t\\tif (!err \u0026\u0026 ofs-\u003ecasefold != ovl_dentry_casefolded(newdentry)) {\\n\\t\\t\\tpr_warn_ratelimited(...);\\n\\t\\t\\tend_creating(newdentry);\\t/* first */\\n\\t\\t\\terr = -EINVAL;\\n\\t\\t}\\n\\t\\tbreak;\\n\\t...\\n\\tif (err)\\n\\t\\tgoto out;\\n\\t...\\n out:\\n\\tif (err) {\\n\\t\\tend_creating(newdentry);\\t/* second, same dentry */\\n\\t\\treturn ERR_PTR(err);\\n\\t}\\n\\nend_creating() is end_dirop(), which does inode_unlock() on the parent\\nand dput() on the dentry, so the parent directory\u0027s i_rwsem is unlocked\\ntwice and the dentry is put twice.  The second unlock releases a lock\\nthat is not held, which is what wedges every later creation under that\\nparent, and the second dput() drops a reference that was never taken.\\n\\nThe branch was added by commit dfc7da402ccc (\\\"ovl: Check for casefold\\nconsistency when creating new dentries\\\") as a bare dput(), which already\\nreleased the reference twice; commit fe497f0759e0 (\\\"VFS: change\\nvfs_mkdir() to unlock on failure.\\\") converted both sites to\\nend_creating(), adding the double unlock.\\n\\nThis is reachable by an unprivileged user.  The casefold consistency of\\nthe layers is validated at mount time in ovl_parse_layer(), and again on\\nevery lookup in ovl_lookup_single(), but ofs-\u003eworkdir is the internal\\n\\\"work\\\" subdirectory created inside the user-supplied workdir, and that\\nsubdirectory is not re-checked.  Marking it casefolded after the mount\\ntherefore makes every ovl_create_temp() inherit the wrong state - and\\nthat path reaches ovl_create_real() through ovl_start_creating_temp(),\\nwhich uses start_creating() with a generated name and so never runs the\\nlookup-time check.\\n\\n  unshare -Urm\\n  mount -t tmpfs -o casefold=utf8-12.1.0 tmpfs mnt\\n  mkdir -p mnt/lower/d mnt/upper mnt/work mnt/merged\\n  mount -t overlay ovl -o lowerdir=mnt/lower,\\\\\\n        upperdir=mnt/upper,workdir=mnt/work mnt/merged\\n  chattr +F mnt/work/work\\n  mkdir mnt/merged/d/sub\\t\\t# directory copy-up\\n\\n  overlayfs: wrong inherited casefold (work/#5)\\n\\nand the next copy-up blocks forever on the parent\u0027s i_rwsem:\\n\\n  mkdir           D  start_creating+0x65/0xb0\\n                     ovl_start_creating_temp+0xb0/0xe0 [overlay]\\n                     ovl_create_temp+0xa3/0x1d0 [overlay]\\n                     ovl_copy_up_one+0x1f1c/0x21c0 [overlay]\\n                     ovl_copy_up_flags+0xf5/0x140 [overlay]\\n                     ovl_create_object+0xb7/0x220 [overlay]\\n                     ovl_mkdir+0x23/0x40 [overlay]\\n\\nDrop the end_creating() from the branch and let out: own the cleanup,\\nwhich is what every other error path in this function already does.\"}],\"affected\":[{\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"affectedData\":[{\"vendor\":\"Linux\",\"product\":\"Linux\",\"defaultStatus\":\"unaffected\",\"programFiles\":[\"fs/overlayfs/dir.c\"],\"repo\":\"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\"versions\":[{\"version\":\"dfc7da402ccc92d6e4b01a4778a3f15f2496b9af\",\"lessThan\":\"2fa220bc0f84597cb6de665e5b5021c5901ddf00\",\"versionType\":\"git\",\"status\":\"affected\"},{\"version\":\"dfc7da402ccc92d6e4b01a4778a3f15f2496b9af\",\"lessThan\":\"b1aa8ab78a8e87aee9e306971465408e059f839a\",\"versionType\":\"git\",\"status\":\"affected\"},{\"version\":\"dfc7da402ccc92d6e4b01a4778a3f15f2496b9af\",\"lessThan\":\"077ab8985ee278c3d8618182d335b0f0cd919e16\",\"versionType\":\"git\",\"status\":\"affected\"}]},{\"vendor\":\"Linux\",\"product\":\"Linux\",\"defaultStatus\":\"affected\",\"programFiles\":[\"fs/overlayfs/dir.c\"],\"repo\":\"https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git\",\"versions\":[{\"version\":\"6.18\",\"status\":\"affected\"},{\"version\":\"0\",\"lessThan\":\"6.18\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"6.18.51\",\"lessThanOrEqual\":\"6.18.*\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"7.2.4\",\"lessThanOrEqual\":\"7.2.*\",\"versionType\":\"semver\",\"status\":\"unaffected\"},{\"version\":\"7.3-rc1\",\"lessThanOrEqual\":\"*\",\"versionType\":\"original_commit_for_fix\",\"status\":\"unaffected\"}]}]}],\"metrics\":{\"cvssMetricV31\":[{\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\",\"type\":\"Secondary\",\"cvssData\":{\"version\":\"3.1\",\"vectorString\":\"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H\",\"baseScore\":7.8,\"baseSeverity\":\"HIGH\",\"attackVector\":\"LOCAL\",\"attackComplexity\":\"LOW\",\"privilegesRequired\":\"LOW\",\"userInteraction\":\"NONE\",\"scope\":\"UNCHANGED\",\"confidentialityImpact\":\"HIGH\",\"integrityImpact\":\"HIGH\",\"availabilityImpact\":\"HIGH\"},\"exploitabilityScore\":1.8,\"impactScore\":5.9}]},\"references\":[{\"url\":\"https://git.kernel.org/stable/c/077ab8985ee278c3d8618182d335b0f0cd919e16\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/2fa220bc0f84597cb6de665e5b5021c5901ddf00\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"},{\"url\":\"https://git.kernel.org/stable/c/b1aa8ab78a8e87aee9e306971465408e059f839a\",\"source\":\"416baaa9-dc9f-4396-8d5f-8c081fb06d67\"}]}}",
    "redhat_vex": {
      "aggregate_severity": "Moderate",
      "current_release_date": "2026-09-15T10:22:20+00:00",
      "cve": "CVE-2026-89767",
      "id": "CVE-2026-89767",
      "initial_release_date": "2026-09-11T00:00:00+00:00",
      "product_status:known_not_affected": "276",
      "source": "Red Hat CSAF VEX",
      "status": "final",
      "title": "kernel: ovl: fix double end_creating() on the casefold-mismatch path",
      "url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-89767.json",
      "version": "3"
    },
    "suse_vex": {
      "aggregate_severity": "not set",
      "current_release_date": "2026-09-12T16:21:52Z",
      "cve": "CVE-2026-89767",
      "id": "CVE-2026-89767",
      "initial_release_date": "2026-09-12T16:21:52Z",
      "source": "SUSE CSAF VEX",
      "status": "interim",
      "title": "SUSE CVE CVE-2026-89767",
      "url": "https://ftp.suse.com/pub/projects/security/csaf-vex/cve-2026-89767.json",
      "version": "2"
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

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.

Loading…

Detection rules are retrieved from Rulezet.

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.


Loading…