{
  "schema_version": "1.6.1",
  "id": "RPI-CVE-2026-90091",
  "modified": "2026-10-09T11:39:44Z",
  "upstream": [
    "CVE-2026-90091"
  ],
  "published": "2026-09-17T16:10:40Z",
  "summary": "Bluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan",
  "details": "In the Linux kernel, the following vulnerability has been resolved:\n\nBluetooth: L2CAP: fix race l2cap_sock_cleanup_listen() vs. put_chan\n\nFor L2CAP sockets without owning sk->sk_socket, reading\nl2cap_pi(sk)->chan may race against concurrent l2cap_sock_kill() ->\nl2cap_sock_put_chan().  This excludes simultaneous proto_ops callbacks,\nbut access in l2cap_sock_cleanup_listen() has unsafe lockless read.\n\n [Task 1]                         [Task 2 (hdev->workqueue)]\n l2cap_sock_release(parent)       l2cap_disconn_cfm\n   l2cap_sock_cleanup_listen        l2cap_conn_del\n     bt_accept_dequeue                l2cap_chan_del\n       lock_sock(sk)                    l2cap_sock_teardown_cb\n       bt_accept_unlink\n         bt_sk(sk)->parent = NULL\n       release_sock(sk) ----------------> lock_sock(sk)\n                                          parent = /* NULL */\n     lock_sock(sk) <--------------------- release_sock(sk)\n                                          sock_set_flag(sk, SOCK_ZAPPED)\n                                      l2cap_sock_close_cb\n                                        l2cap_sock_kill(sk)\n                                          l2cap_sock_put_chan\n     chan = READ l2cap_pi(sk)->chan         l2cap_pi(sk)->chan = NULL\n     l2cap_chan_hold_unless_zero            l2cap_put_chan(chan)\n       kref_get_unless_zero(&chan->ref)\n\nTask 1 may observe NULL which causes null-ptr-deref.\n\nFix the race by taking lock_sock() in l2cap_sock_kill() to\nsynchronize with l2cap_sock_cleanup_listen().  hold_unless_zero() is not\nneeded here, l2cap_pi(sk)->chan owns reference if it is non-NULL.\n\nClarify code comments vs. locking.",
  "severity": [
    {
      "type": "CVSS_V3",
      "score": "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
    }
  ],
  "affected": [
    {
      "package": {
        "ecosystem": "Raspberry Pi OS:12",
        "name": "linux"
      },
      "versions": [
        "1:6.12.109-1+rpt1"
      ],
      "ecosystem_specific": {
        "binaries": [
          {
            "binary_name": "linux-image-6.12.109+rpt-rpi-2712",
            "binary_version": "1:6.12.109-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.12.109+rpt-rpi-v6",
            "binary_version": "1:6.12.109-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.12.109+rpt-rpi-v7",
            "binary_version": "1:6.12.109-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.12.109+rpt-rpi-v7l",
            "binary_version": "1:6.12.109-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.12.109+rpt-rpi-v8",
            "binary_version": "1:6.12.109-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.12.109+rpt-rpi-v8-rt",
            "binary_version": "1:6.12.109-1+rpt1"
          }
        ]
      },
      "database_specific": {
        "per_version": {
          "1:6.12.109-1+rpt1": {
            "linux_commit": "7d1826930811232688a50c99c540fbb137aed081",
            "upstream_version": "6.12.109",
            "assessment": "commit ancestry (strak rule)",
            "upstream_fixed": "6.12.110"
          }
        }
      }
    },
    {
      "package": {
        "ecosystem": "Raspberry Pi OS:13",
        "name": "linux"
      },
      "versions": [
        "1:6.18.50-1+rpt1"
      ],
      "ecosystem_specific": {
        "binaries": [
          {
            "binary_name": "linux-image-6.18.50+rpt-rpi-2712",
            "binary_version": "1:6.18.50-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.18.50+rpt-rpi-v6",
            "binary_version": "1:6.18.50-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.18.50+rpt-rpi-v7",
            "binary_version": "1:6.18.50-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.18.50+rpt-rpi-v8",
            "binary_version": "1:6.18.50-1+rpt1"
          },
          {
            "binary_name": "linux-image-6.18.50+rpt-rpi-v8-rt",
            "binary_version": "1:6.18.50-1+rpt1"
          }
        ]
      },
      "database_specific": {
        "per_version": {
          "1:6.18.50-1+rpt1": {
            "linux_commit": "cff533aec2fa601846766b32ff57204e0a61bed7",
            "upstream_version": "6.18.50",
            "assessment": "commit ancestry (strak rule)",
            "upstream_fixed": "6.18.52"
          }
        }
      }
    }
  ],
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://www.cve.org/CVERecord?id=CVE-2026-90091"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/827de6bd2865b22aaabd554540def3b8a33018ab"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/7c7ac736b50fa259ed1bdddc18d79523f07c0442"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/4f8c63fe0097c9f6ea34409f82f79b3894903d91"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/61d5ddbd524c715b224cbe7e9f01da4e05098b19"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/32a7bc6e93be36b37fe61f351d312d358195bd61"
    },
    {
      "type": "FIX",
      "url": "https://git.kernel.org/stable/c/66d6ef18548ae6d7dd452b84115fc82c0a73a4ea"
    }
  ],
  "database_specific": {
    "source": "https://git.kernel.org/pub/scm/linux/security/vulns.git",
    "upstream_modified": "2026-09-18T17:55:42Z",
    "severity": {
      "source": "kernel CNA",
      "cvss_v3_score": 8.0,
      "cvss_v3_severity": "High",
      "scenario": "AV:A - A nearby peer's HCI Disconnection Complete (hci_disconn_complete_evt \u2192 hci_disconn_cfm \u2192 l2cap_disconn_cfm on hdev->rx_work) or L2CAP_DISCONN_REQ (l2cap_disconnect_req) runs l2cap_sock_put_chan on an unaccepted child created by L2CAP_CONN_REQ; the transport is Bluetooth radio range, so Adjacent not Network.\nAC:L - The attacker drives both sides: close() of their listening socket runs l2cap_sock_release \u2192 l2cap_sock_cleanup_listen \u2192 bt_accept_dequeue, while the peer's disconnect concurrently runs l2cap_sock_kill \u2192 l2cap_sock_put_chan on that child without lock_sock; repeating connect/disconnect/close hits the window.\nPR:L - l2cap_sock_create() allows unprivileged SOCK_SEQPACKET/SOCK_STREAM (only SOCK_RAW needs CAP_NET_RAW), and l2cap_validate_bredr_psm() permits dynamic PSM >= 0x1001 without CAP_NET_BIND_SERVICE, so listen()+close() needs only a normal local account; AF_BLUETOOTH is init_net-only (bt_sock_create), not a userns CAP_NET_ADMIN path.\nUI:N - The attacker closes their own listening L2CAP socket and, from a radio they control, sends L2CAP_CONN_REQ then disconnect; no other user must pair, accept, or confirm during the race.\nS:U - The race corrupts the host kernel l2cap_chan stored in l2cap_pi(sk)->chan of the unaccepted child; it does not escape a VM, bypass an IOMMU, or leave the kernel's own authority.\nC:H - cleanup_listen loads l2cap_pi(sk)->chan then calls l2cap_chan_hold_unless_zero(); concurrent l2cap_sock_put_chan plus l2cap_conn_del's final l2cap_chan_put can kfree that object first, so kref_get_unless_zero and later l2cap_chan_lock/__set_chan_timer run on a freed kmalloc l2cap_chan that can be sprayed for disclosure.\nI:H - Winning that UAF lets cleanup_listen take l2cap_chan_lock, arm __set_chan_timer, and l2cap_chan_put on a reclaimed fake chan, corrupting mutex/timer/kref state and invoking chan->ops from sprayed memory for hijack.\nA:H - If cleanup_listen observes the NULL stored by l2cap_sock_put_chan, l2cap_chan_hold_unless_zero() calls kref_get_unless_zero(&c->kref) with c==NULL and oopses; the UAF interleaving likewise panics on poisoned slab or a corrupted chan mutex."
    }
  }
}
