{
  "affected": [
    {
      "ranges": [
        {
          "events": [
            {
              "introduced": "7b07a2a7ca02a20124b552be96c5a56910795488"
            },
            {
              "fixed": "c872d8a065b3b499ce4c3ad168b5d34b68524f66"
            },
            {
              "fixed": "c7d421123b98d5e9c1c84bd9957aba36f1cbb4ca"
            },
            {
              "fixed": "552dae28dbeb5f7c4fafcda43962dc46569f58a0"
            },
            {
              "fixed": "2796646f6d892c1eb6818c7ca41fdfa12568e8d1"
            }
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "type": "GIT"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Linux",
        "name": "Kernel"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "6.9.0"
            },
            {
              "fixed": "6.12.93"
            }
          ],
          "type": "ECOSYSTEM"
        },
        {
          "events": [
            {
              "introduced": "6.13.0"
            },
            {
              "fixed": "6.18.35"
            }
          ],
          "type": "ECOSYSTEM"
        },
        {
          "events": [
            {
              "introduced": "6.19.0"
            },
            {
              "fixed": "7.0.12"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "database_specific": {
    "cna_assigner": "Linux",
    "osv_generated_from": "https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/63xxx/CVE-2026-63894.json"
  },
  "details": "In the Linux kernel, the following vulnerability has been resolved:\n\nusb: gadget: f_fs: serialize DMABUF cancel against request completion\n\nffs_epfile_dmabuf_io_complete() calls usb_ep_free_request() on the\ncompleted request but leaves priv-\u003ereq, the back-pointer that\nffs_dmabuf_transfer() set on submission, pointing at the freed\nmemory.  A later FUNCTIONFS_DMABUF_DETACH ioctl or\nffs_epfile_release() on the close path still sees priv-\u003ereq\nnon-NULL under ffs-\u003eeps_lock:\n\n    if (priv-\u003eep \u0026\u0026 priv-\u003ereq)\n            usb_ep_dequeue(priv-\u003eep, priv-\u003ereq);\n\nso usb_ep_dequeue() is called on a freed usb_request.\n\nOn dummy_hcd the dequeue path only walks a live queue and\npointer-compares, so the freed pointer reads without faulting and\nKASAN requires an explicit check at the FunctionFS call site to\nsurface the use-after-free.  On SG-capable in-tree UDCs the\ndequeue path dereferences the supplied request immediately:\n\n  * chipidea's ep_dequeue() does\n    container_of(req, struct ci_hw_req, req) and reads\n    hwreq-\u003ereq.status before acquiring its own lock.\n  * cdnsp's cdnsp_gadget_ep_dequeue() reads request-\u003estatus first.\n\nThe narrower option of clearing priv-\u003ereq via cmpxchg() in the\ncompletion does not close the race: the completion runs without\neps_lock, so a cancel path holding eps_lock can still observe\npriv-\u003ereq non-NULL, race a concurrent completion that clears and\nfrees, and pass the freed pointer to usb_ep_dequeue().  A slightly\nlonger fix that moves the free into the cleanup work is needed.\n\nSame class of lifetime race as the recent usbip-vudc timer fix [1].\n\nTake eps_lock in the sole place that mutates priv-\u003ereq from the\ncallback direction by moving usb_ep_free_request() out of the\ncompletion into ffs_dmabuf_cleanup(), the existing work handler\nscheduled by ffs_dmabuf_signal_done() on\nffs-\u003eio_completion_wq.  Clear priv-\u003ereq there under eps_lock\nbefore freeing, and only clear if priv-\u003ereq still names our\nrequest (a subsequent ffs_dmabuf_transfer() on the same\nattachment may have queued a new one).\n\nThis keeps the existing dummy_hcd sync-dequeue invariant: the\ncompletion callback is still invoked by the UDC without\neps_lock held (dummy_hcd drops its own lock before calling the\ncallback), and the callback now takes no f_fs lock at all.\nSerialization against the cancel path happens in cleanup, which\nruns from the workqueue with no f_fs lock held on entry.\n\nThe priv ref count protects the containing ffs_dmabuf_priv:\nffs_dmabuf_transfer() takes a ref via ffs_dmabuf_get(), cleanup\ndrops it via ffs_dmabuf_put(), so priv stays live for the\ncleanup even after the cancel path's list_del + ffs_dmabuf_put.\n\nThe ffs_dmabuf_transfer() error path no longer frees usb_req\ninline: fence-\u003ereq and fence-\u003eep are set before usb_ep_queue(),\nso ffs_dmabuf_cleanup() (scheduled by the error-path\nffs_dmabuf_signal_done()) owns the free regardless of whether\nthe queue succeeded.\n\nReproduced under KASAN on both detach and close paths against\ndummy_hcd with an observability hook\n(kasan_check_byte(priv-\u003ereq) immediately before usb_ep_dequeue)\nat the two FunctionFS cancel sites to surface the stale-pointer\naccess; the hook is not part of this patch.  The KASAN\nallocator / free stacks in the captured splats identify the\nsame request: alloc in dummy_alloc_request, free in\ndummy_timer, fault reached from ffs_epfile_release (close) and\nfrom the FUNCTIONFS_DMABUF_DETACH ioctl (detach).  With the\npatch applied, both paths are silent under the same hook.\n\nThe bug is reached from the FunctionFS device node, which in\nreal deployments is owned by the privileged gadget daemon\n(adbd, UMS, composite gadget services, etc.); it is not\nreachable from unprivileged userspace or from a USB host on the\ncable.  FunctionFS mounts default to GLOBAL_ROOT_UID, but the\nfilesystem supports uid=, gid=, and fmode= delegation to a\nnon-root gadget daemon, so on real deployments the attacker may\nbe a less-privileged service rather than root.",
  "id": "CVE-2026-63894",
  "modified": "2026-07-22T05:30:07.797793463Z",
  "published": "2026-07-19T14:55:04.882Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://git.kernel.org/stable/c/2796646f6d892c1eb6818c7ca41fdfa12568e8d1"
    },
    {
      "type": "WEB",
      "url": "https://git.kernel.org/stable/c/552dae28dbeb5f7c4fafcda43962dc46569f58a0"
    },
    {
      "type": "WEB",
      "url": "https://git.kernel.org/stable/c/c7d421123b98d5e9c1c84bd9957aba36f1cbb4ca"
    },
    {
      "type": "WEB",
      "url": "https://git.kernel.org/stable/c/c872d8a065b3b499ce4c3ad168b5d34b68524f66"
    },
    {
      "type": "ADVISORY",
      "url": "https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/63xxx/CVE-2026-63894.json"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-63894"
    },
    {
      "type": "PACKAGE",
      "url": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git"
    }
  ],
  "schema_version": "1.8.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "usb: gadget: f_fs: serialize DMABUF cancel against request completion"
}