GHSA-WCCC-2QV8-6647
Vulnerability from github – Published: 2024-07-06 12:31 – Updated: 2024-08-22 15:31In the Linux kernel, the following vulnerability has been resolved:
drm/drm_file: Fix pid refcounting race
filp->pid is supposed to be a refcounted pointer; however, before this patch, drm_file_update_pid() only increments the refcount of a struct pid after storing a pointer to it in filp->pid and dropping the dev->filelist_mutex, making the following race possible:
process A process B ========= ========= begin drm_file_update_pid mutex_lock(&dev->filelist_mutex) rcu_replace_pointer(filp->pid, , 1) mutex_unlock(&dev->filelist_mutex) begin drm_file_update_pid mutex_lock(&dev->filelist_mutex) rcu_replace_pointer(filp->pid, , 1) mutex_unlock(&dev->filelist_mutex) get_pid() synchronize_rcu() put_pid() *** pid B reaches refcount 0 and is freed here *** get_pid() *** UAF *** synchronize_rcu() put_pid()
As far as I know, this race can only occur with CONFIG_PREEMPT_RCU=y because it requires RCU to detect a quiescent state in code that is not explicitly calling into the scheduler.
This race leads to use-after-free of a "struct pid". It is probably somewhat hard to hit because process A has to pass through a synchronize_rcu() operation while process B is between mutex_unlock() and get_pid().
Fix it by ensuring that by the time a pointer to the current task's pid is stored in the file, an extra reference to the pid has been taken.
This fix also removes the condition for synchronize_rcu(); I think that optimization is unnecessary complexity, since in that case we would usually have bailed out on the lockless check above.
{
"affected": [],
"aliases": [
"CVE-2024-39486"
],
"database_specific": {
"cwe_ids": [
"CWE-416"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-07-06T10:15:03Z",
"severity": "HIGH"
},
"details": "In the Linux kernel, the following vulnerability has been resolved:\n\ndrm/drm_file: Fix pid refcounting race\n\n\nfilp-\u003epid is supposed to be a refcounted pointer; however, before this\npatch, drm_file_update_pid() only increments the refcount of a struct\npid after storing a pointer to it in filp-\u003epid and dropping the\ndev-\u003efilelist_mutex, making the following race possible:\n\nprocess A process B\n========= =========\n begin drm_file_update_pid\n mutex_lock(\u0026dev-\u003efilelist_mutex)\n rcu_replace_pointer(filp-\u003epid, \u003cpid B\u003e, 1)\n mutex_unlock(\u0026dev-\u003efilelist_mutex)\nbegin drm_file_update_pid\nmutex_lock(\u0026dev-\u003efilelist_mutex)\nrcu_replace_pointer(filp-\u003epid, \u003cpid A\u003e, 1)\nmutex_unlock(\u0026dev-\u003efilelist_mutex)\nget_pid(\u003cpid A\u003e)\nsynchronize_rcu()\nput_pid(\u003cpid B\u003e) *** pid B reaches refcount 0 and is freed here ***\n get_pid(\u003cpid B\u003e) *** UAF ***\n synchronize_rcu()\n put_pid(\u003cpid A\u003e)\n\nAs far as I know, this race can only occur with CONFIG_PREEMPT_RCU=y\nbecause it requires RCU to detect a quiescent state in code that is not\nexplicitly calling into the scheduler.\n\nThis race leads to use-after-free of a \"struct pid\".\nIt is probably somewhat hard to hit because process A has to pass\nthrough a synchronize_rcu() operation while process B is between\nmutex_unlock() and get_pid().\n\nFix it by ensuring that by the time a pointer to the current task\u0027s pid\nis stored in the file, an extra reference to the pid has been taken.\n\nThis fix also removes the condition for synchronize_rcu(); I think\nthat optimization is unnecessary complexity, since in that case we\nwould usually have bailed out on the lockless check above.",
"id": "GHSA-wccc-2qv8-6647",
"modified": "2024-08-22T15:31:16Z",
"published": "2024-07-06T12:31:05Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-39486"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/0acce2a5c619ef1abdee783d7fea5eac78ce4844"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/16682588ead4a593cf1aebb33b36df4d1e9e4ffa"
},
{
"type": "WEB",
"url": "https://git.kernel.org/stable/c/4f2a129b33a2054e62273edd5a051c34c08d96e9"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
Sightings
| Author | Source | Type | Date |
|---|
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.