FKIE_CVE-2025-68756

Vulnerability from fkie_nvd - Published: 2026-01-05 10:15 - Updated: 2026-10-14 19:10
Severity
Summary
In the Linux kernel, the following vulnerability has been resolved: block: Use RCU in blk_mq_[un]quiesce_tagset() instead of set->tag_list_lock blk_mq_{add,del}_queue_tag_set() functions add and remove queues from tagset, the functions make sure that tagset and queues are marked as shared when two or more queues are attached to the same tagset. Initially a tagset starts as unshared and when the number of added queues reaches two, blk_mq_add_queue_tag_set() marks it as shared along with all the queues attached to it. When the number of attached queues drops to 1 blk_mq_del_queue_tag_set() need to mark both the tagset and the remaining queues as unshared. Both functions need to freeze current queues in tagset before setting on unsetting BLK_MQ_F_TAG_QUEUE_SHARED flag. While doing so, both functions hold set->tag_list_lock mutex, which makes sense as we do not want queues to be added or deleted in the process. This used to work fine until commit 98d81f0df70c ("nvme: use blk_mq_[un]quiesce_tagset") made the nvme driver quiesce tagset instead of quiscing individual queues. blk_mq_quiesce_tagset() does the job and quiesce the queues in set->tag_list while holding set->tag_list_lock also. This results in deadlock between two threads with these stacktraces: __schedule+0x47c/0xbb0 ? timerqueue_add+0x66/0xb0 schedule+0x1c/0xa0 schedule_preempt_disabled+0xa/0x10 __mutex_lock.constprop.0+0x271/0x600 blk_mq_quiesce_tagset+0x25/0xc0 nvme_dev_disable+0x9c/0x250 nvme_timeout+0x1fc/0x520 blk_mq_handle_expired+0x5c/0x90 bt_iter+0x7e/0x90 blk_mq_queue_tag_busy_iter+0x27e/0x550 ? __blk_mq_complete_request_remote+0x10/0x10 ? __blk_mq_complete_request_remote+0x10/0x10 ? __call_rcu_common.constprop.0+0x1c0/0x210 blk_mq_timeout_work+0x12d/0x170 process_one_work+0x12e/0x2d0 worker_thread+0x288/0x3a0 ? rescuer_thread+0x480/0x480 kthread+0xb8/0xe0 ? kthread_park+0x80/0x80 ret_from_fork+0x2d/0x50 ? kthread_park+0x80/0x80 ret_from_fork_asm+0x11/0x20 __schedule+0x47c/0xbb0 ? xas_find+0x161/0x1a0 schedule+0x1c/0xa0 blk_mq_freeze_queue_wait+0x3d/0x70 ? destroy_sched_domains_rcu+0x30/0x30 blk_mq_update_tag_set_shared+0x44/0x80 blk_mq_exit_queue+0x141/0x150 del_gendisk+0x25a/0x2d0 nvme_ns_remove+0xc9/0x170 nvme_remove_namespaces+0xc7/0x100 nvme_remove+0x62/0x150 pci_device_remove+0x23/0x60 device_release_driver_internal+0x159/0x200 unbind_store+0x99/0xa0 kernfs_fop_write_iter+0x112/0x1e0 vfs_write+0x2b1/0x3d0 ksys_write+0x4e/0xb0 do_syscall_64+0x5b/0x160 entry_SYSCALL_64_after_hwframe+0x4b/0x53 The top stacktrace is showing nvme_timeout() called to handle nvme command timeout. timeout handler is trying to disable the controller and as a first step, it needs to blk_mq_quiesce_tagset() to tell blk-mq not to call queue callback handlers. The thread is stuck waiting for set->tag_list_lock as it tries to walk the queues in set->tag_list. The lock is held by the second thread in the bottom stack which is waiting for one of queues to be frozen. The queue usage counter will drop to zero after nvme_timeout() finishes, and this will not happen because the thread will wait for this mutex forever. Given that [un]quiescing queue is an operation that does not need to sleep, update blk_mq_[un]quiesce_tagset() to use RCU instead of taking set->tag_list_lock, update blk_mq_{add,del}_queue_tag_set() to use RCU safe list operations. Also, delete INIT_LIST_HEAD(&q->tag_set_list) in blk_mq_del_queue_tag_set() because we can not re-initialize it while the list is being traversed under RCU. The deleted queue will not be added/deleted to/from a tagset and it will be freed in blk_free_queue() after the end of RCU grace period.
Impacted products
Vendor Product Version

{
  "affected": [
    {
      "affectedData": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "block/blk-mq.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "ca8764c0ea1fb825f17f19704af55e9e02c9f768",
              "status": "affected",
              "version": "98d81f0df70ce6fc48517d938026e3c684b9051a",
              "versionType": "git"
            },
            {
              "lessThan": "3baeec23a82e7ee9691f434c6ab0ab1387326108",
              "status": "affected",
              "version": "98d81f0df70ce6fc48517d938026e3c684b9051a",
              "versionType": "git"
            },
            {
              "lessThan": "6e8d363786765a81e35083e0909e076796468edf",
              "status": "affected",
              "version": "98d81f0df70ce6fc48517d938026e3c684b9051a",
              "versionType": "git"
            },
            {
              "lessThan": "ef0cd7b694928573f6569e61c14f5f059253162e",
              "status": "affected",
              "version": "98d81f0df70ce6fc48517d938026e3c684b9051a",
              "versionType": "git"
            },
            {
              "lessThan": "59e25ef2b413c72da6686d431e7759302cfccafa",
              "status": "affected",
              "version": "98d81f0df70ce6fc48517d938026e3c684b9051a",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "block/blk-mq.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "6.2"
            },
            {
              "lessThan": "6.2",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.6.*",
              "status": "unaffected",
              "version": "6.6.120",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.12.*",
              "status": "unaffected",
              "version": "6.12.63",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.17.*",
              "status": "unaffected",
              "version": "6.17.13",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "6.18.*",
              "status": "unaffected",
              "version": "6.18.2",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "6.19",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
    }
  ],
  "cveTags": [],
  "descriptions": [
    {
      "lang": "en",
      "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nblock: Use RCU in blk_mq_[un]quiesce_tagset() instead of set-\u003etag_list_lock\n\nblk_mq_{add,del}_queue_tag_set() functions add and remove queues from\ntagset, the functions make sure that tagset and queues are marked as\nshared when two or more queues are attached to the same tagset.\nInitially a tagset starts as unshared and when the number of added\nqueues reaches two, blk_mq_add_queue_tag_set() marks it as shared along\nwith all the queues attached to it. When the number of attached queues\ndrops to 1 blk_mq_del_queue_tag_set() need to mark both the tagset and\nthe remaining queues as unshared.\n\nBoth functions need to freeze current queues in tagset before setting on\nunsetting BLK_MQ_F_TAG_QUEUE_SHARED flag. While doing so, both functions\nhold set-\u003etag_list_lock mutex, which makes sense as we do not want\nqueues to be added or deleted in the process. This used to work fine\nuntil commit 98d81f0df70c (\"nvme: use blk_mq_[un]quiesce_tagset\")\nmade the nvme driver quiesce tagset instead of quiscing individual\nqueues. blk_mq_quiesce_tagset() does the job and quiesce the queues in\nset-\u003etag_list while holding set-\u003etag_list_lock also.\n\nThis results in deadlock between two threads with these stacktraces:\n\n  __schedule+0x47c/0xbb0\n  ? timerqueue_add+0x66/0xb0\n  schedule+0x1c/0xa0\n  schedule_preempt_disabled+0xa/0x10\n  __mutex_lock.constprop.0+0x271/0x600\n  blk_mq_quiesce_tagset+0x25/0xc0\n  nvme_dev_disable+0x9c/0x250\n  nvme_timeout+0x1fc/0x520\n  blk_mq_handle_expired+0x5c/0x90\n  bt_iter+0x7e/0x90\n  blk_mq_queue_tag_busy_iter+0x27e/0x550\n  ? __blk_mq_complete_request_remote+0x10/0x10\n  ? __blk_mq_complete_request_remote+0x10/0x10\n  ? __call_rcu_common.constprop.0+0x1c0/0x210\n  blk_mq_timeout_work+0x12d/0x170\n  process_one_work+0x12e/0x2d0\n  worker_thread+0x288/0x3a0\n  ? rescuer_thread+0x480/0x480\n  kthread+0xb8/0xe0\n  ? kthread_park+0x80/0x80\n  ret_from_fork+0x2d/0x50\n  ? kthread_park+0x80/0x80\n  ret_from_fork_asm+0x11/0x20\n\n  __schedule+0x47c/0xbb0\n  ? xas_find+0x161/0x1a0\n  schedule+0x1c/0xa0\n  blk_mq_freeze_queue_wait+0x3d/0x70\n  ? destroy_sched_domains_rcu+0x30/0x30\n  blk_mq_update_tag_set_shared+0x44/0x80\n  blk_mq_exit_queue+0x141/0x150\n  del_gendisk+0x25a/0x2d0\n  nvme_ns_remove+0xc9/0x170\n  nvme_remove_namespaces+0xc7/0x100\n  nvme_remove+0x62/0x150\n  pci_device_remove+0x23/0x60\n  device_release_driver_internal+0x159/0x200\n  unbind_store+0x99/0xa0\n  kernfs_fop_write_iter+0x112/0x1e0\n  vfs_write+0x2b1/0x3d0\n  ksys_write+0x4e/0xb0\n  do_syscall_64+0x5b/0x160\n  entry_SYSCALL_64_after_hwframe+0x4b/0x53\n\nThe top stacktrace is showing nvme_timeout() called to handle nvme\ncommand timeout. timeout handler is trying to disable the controller and\nas a first step, it needs to blk_mq_quiesce_tagset() to tell blk-mq not\nto call queue callback handlers. The thread is stuck waiting for\nset-\u003etag_list_lock as it tries to walk the queues in set-\u003etag_list.\n\nThe lock is held by the second thread in the bottom stack which is\nwaiting for one of queues to be frozen. The queue usage counter will\ndrop to zero after nvme_timeout() finishes, and this will not happen\nbecause the thread will wait for this mutex forever.\n\nGiven that [un]quiescing queue is an operation that does not need to\nsleep, update blk_mq_[un]quiesce_tagset() to use RCU instead of taking\nset-\u003etag_list_lock, update blk_mq_{add,del}_queue_tag_set() to use RCU\nsafe list operations. Also, delete INIT_LIST_HEAD(\u0026q-\u003etag_set_list)\nin blk_mq_del_queue_tag_set() because we can not re-initialize it while\nthe list is being traversed under RCU. The deleted queue will not be\nadded/deleted to/from a tagset and it will be freed in blk_free_queue()\nafter the end of RCU grace period."
    },
    {
      "lang": "es",
      "value": "En el kernel de Linux, la siguiente vulnerabilidad ha sido resuelta:\n\nblock: Usar RCU en blk_mq_[un]quiesce_tagset() en lugar de set -\u003e tag_list_lock\n\nLas funciones blk_mq_{add,del}_queue_tag_set() a\u00f1aden y eliminan colas de tagset; las funciones se aseguran de que tagset y las colas est\u00e9n marcadas como compartidas cuando dos o m\u00e1s colas est\u00e1n adjuntas al mismo tagset. Inicialmente, un tagset comienza como no compartido y cuando el n\u00famero de colas a\u00f1adidas llega a dos, blk_mq_add_queue_tag_set() lo marca como compartido junto con todas las colas adjuntas a \u00e9l. Cuando el n\u00famero de colas adjuntas cae a 1, blk_mq_del_queue_tag_set() necesita marcar tanto el tagset como las colas restantes como no compartidas.\n\nAmbas funciones necesitan congelar las colas actuales en tagset antes de establecer o desestablecer el flag BLK_MQ_F_TAG_QUEUE_SHARED. Al hacerlo, ambas funciones mantienen el mutex set -\u003e tag_list_lock, lo cual tiene sentido ya que no queremos que se a\u00f1adan o eliminen colas en el proceso. Esto funcionaba bien hasta que el commit 98d81f0df70c (\u0027nvme: use blk_mq_[un]quiesce_tagset\u0027) hizo que el driver nvme quiesciera el tagset en lugar de quiescer colas individuales. blk_mq_quiesce_tagset() hace el trabajo y quiesce las colas en set -\u003e tag_list mientras tambi\u00e9n mantiene set -\u003e tag_list_lock.\n\nEsto resulta en un interbloqueo entre dos hilos con estas trazas de pila:\n\n  __schedule+0x47c/0xbb0\n  ? timerqueue_add+0x66/0xb0\n  schedule+0x1c/0xa0\n  schedule_preempt_disabled+0xa/0x10\n  __mutex_lock.constprop.0+0x271/0x600\n  blk_mq_quiesce_tagset+0x25/0xc0\n  nvme_dev_disable+0x9c/0x250\n  nvme_timeout+0x1fc/0x520\n  blk_mq_handle_expired+0x5c/0x90\n  bt_iter+0x7e/0x90\n  blk_mq_queue_tag_busy_iter+0x27e/0x550\n  ? __blk_mq_complete_request_remote+0x10/0x10\n  ? __blk_mq_complete_request_remote+0x10/0x10\n  ? __call_rcu_common.constprop.0+0x1c0/0x210\n  blk_mq_timeout_work+0x12d/0x170\n  process_one_work+0x12e/0x2d0\n  worker_thread+0x288/0x3a0\n  ? rescuer_thread+0x480/0x480\n  kthread+0xb8/0xe0\n  ? kthread_park+0x80/0x80\n  ret_from_fork+0x2d/0x50\n  ? kthread_park+0x80/0x80\n  ret_from_fork_asm+0x11/0x20\n\n  __schedule+0x47c/0xbb0\n  ? xas_find+0x161/0x1a0\n  schedule+0x1c/0xa0\n  blk_mq_freeze_queue_wait+0x3d/0x70\n  ? destroy_sched_domains_rcu+0x30/0x30\n  blk_mq_update_tag_set_shared+0x44/0x80\n  blk_mq_exit_queue+0x141/0x150\n  del_gendisk+0x25a/0x2d0\n  nvme_ns_remove+0xc9/0x170\n  nvme_remove_namespaces+0xc7/0x100\n  nvme_remove+0x62/0x150\n  pci_device_remove+0x23/0x60\n  device_release_driver_internal+0x159/0x200\n  unbind_store+0x99/0xa0\n  kernfs_fop_write_iter+0x112/0x1e0\n  vfs_write+0x2b1/0x3d0\n  ksys_write+0x4e/0xb0\n  do_syscall_64+0x5b/0x160\n  entry_SYSCALL_64_after_hwframe+0x4b/0x53\n\nLa traza de pila superior muestra nvme_timeout() siendo llamada para manejar el tiempo de espera de un comando nvme. El manejador de tiempo de espera est\u00e1 intentando deshabilitar el controlador y, como primer paso, necesita blk_mq_quiesce_tagset() para indicarle a blk-mq que no llame a los manejadores de callback de cola. El hilo est\u00e1 atascado esperando por set -\u003e tag_list_lock mientras intenta recorrer las colas en set -\u003e tag_list.\n\nEl bloqueo es mantenido por el segundo hilo en la pila inferior, que est\u00e1 esperando que una de las colas sea congelada. El contador de uso de la cola caer\u00e1 a cero despu\u00e9s de que nvme_timeout() termine, y esto no suceder\u00e1 porque el hilo esperar\u00e1 por este mutex para siempre.\n\nDado que [des]quiescer una cola es una operaci\u00f3n que no necesita dormir, se actualiza blk_mq_[un]quiesce_tagset() para usar RCU en lugar de tomar set -\u003e tag_list_lock, y se actualiza blk_mq_{add,del}_queue_tag_set() para usar operaciones de lista seguras para RCU. Adem\u00e1s, se elimina INIT_LIST_HEAD(\u0026q -\u003e tag_set_list) en blk_mq_del_queue_tag_set() porque no podemos reinicializarla mientras la lista est\u00e1 siendo recorrida bajo RCU. La cola eliminada no ser\u00e1 a\u00f1adida/eliminada a/de un tagset y ser\u00e1 liberada en blk_free_queue() despu\u00e9s del final del per\u00edodo de gracia de RCU."
    }
  ],
  "id": "CVE-2025-68756",
  "lastModified": "2026-10-14T19:10:00.297",
  "metrics": {},
  "published": "2026-01-05T10:15:56.657",
  "references": [
    {
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
      "url": "https://git.kernel.org/stable/c/3baeec23a82e7ee9691f434c6ab0ab1387326108"
    },
    {
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
      "url": "https://git.kernel.org/stable/c/59e25ef2b413c72da6686d431e7759302cfccafa"
    },
    {
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
      "url": "https://git.kernel.org/stable/c/6e8d363786765a81e35083e0909e076796468edf"
    },
    {
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
      "url": "https://git.kernel.org/stable/c/ca8764c0ea1fb825f17f19704af55e9e02c9f768"
    },
    {
      "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
      "url": "https://git.kernel.org/stable/c/ef0cd7b694928573f6569e61c14f5f059253162e"
    }
  ],
  "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
  "vulnStatus": "Deferred"
}



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.