159 lines
10 KiB
JSON
159 lines
10 KiB
JSON
{
|
||
"dataType": "CVE_RECORD",
|
||
"dataVersion": "5.2",
|
||
"cveMetadata": {
|
||
"cveId": "CVE-2026-80975",
|
||
"assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
|
||
"state": "PUBLISHED",
|
||
"assignerShortName": "Linux",
|
||
"dateReserved": "2026-08-26T14:34:25.810Z",
|
||
"datePublished": "2026-09-11T19:42:37.086Z",
|
||
"dateUpdated": "2026-10-19T08:45:59.772Z"
|
||
},
|
||
"containers": {
|
||
"cna": {
|
||
"providerMetadata": {
|
||
"orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
|
||
"shortName": "Linux",
|
||
"dateUpdated": "2026-10-19T08:45:59.772Z"
|
||
},
|
||
"descriptions": [
|
||
{
|
||
"lang": "en",
|
||
"value": "In the Linux kernel, the following vulnerability has been resolved:\n\nmfd: qnap-mcu: keep the reply buffer alive past a command timeout\n\nqnap_mcu_exec() publishes an on-stack buffer to the receive path:\n\n\tunsigned char rx[QNAP_MCU_RX_BUFFER_SIZE];\n\t...\n\treply->data = rx;\n\treply->length = length;\n\nand qnap_mcu_receive_buf() writes into it from the serdev receive path,\nwhich runs out of flush_to_ldisc() and is not serialized against\nqnap_mcu_exec() at all. bus_lock cannot cover it, because qnap_mcu_exec()\nholds that mutex across wait_for_completion_timeout().\n\nOn a timeout qnap_mcu_exec() returns with reply->data still pointing at\nits own frame. A reply that arrives late, or an unsolicited message from\nthe MCU, is then written into a stack frame that has been left, corrupting\nwhatever runs next on that stack. The same applies when qnap_mcu_write()\nfails, since that path returns without touching the reply state either.\n\nMove the receive buffer into struct qnap_mcu. It is 37 bytes and the\nstructure is devm_kzalloc()ed, so it lives as long as the driver, and a\nlate write lands in memory that is still valid and is reinitialized by the\nnext command. bus_lock keeps commands from sharing it.\n\nThis deliberately does not clear reply->data or reply->length on the\ntimeout path. Doing so races with qnap_mcu_receive_buf(), which reads both\nafter its\n\n\tif (!reply->length)\n\t\treturn size;\n\ncheck: clearing reply->data gives a NULL dereference, and clearing\nreply->length alone removes the reply->received == reply->length exit\ncondition, so the copy loop runs until the uart chunk is consumed and\noverruns the buffer. Leaving both set keeps the write bounded by\nreply->length, which qnap_mcu_exec() has already checked against\nsizeof(mcu->rx)."
|
||
}
|
||
],
|
||
"metrics": [
|
||
{
|
||
"cvssV3_1": {
|
||
"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"
|
||
},
|
||
"scenarios": [
|
||
{
|
||
"lang": "en",
|
||
"value": "AV:L - The bug is reached only through local qnap_mcu_exec() calls from hwmon/nvmem/LED/input/thermal sysfs on QNAP NAS devices whose MCU is a soldered UART serdev child, not a network protocol or a user-pluggable USB device, so the vector is Local rather than Physical.\nAC:L - This is use-after-return of an on-stack RX buffer published to qnap_mcu_receive_buf(), which runs from flush_to_ldisc() with no lock shared with qnap_mcu_exec(); an attacker issues commands via sysfs, retries at will, and after the 500 ms timeout reply->data still points at their kernel stack so a late or unsolicited MCU chunk writes into that frame.\nPR:L - Fan/temp hwmon attributes are mode 0444 and pwm is 0644, and the EEPROM nvmem is registered with root_only=false (0444), so any unprivileged local user can invoke qnap_mcu_exec() by reading those sysfs files without capabilities or init-namespace root.\nUI:N - Exploitation uses the attacker’s own reads of already-present hwmon and nvmem sysfs; no victim must mount a filesystem, plug in hardware, or otherwise act, and thermal cooling plus input polling can also enter the same path automatically.\nS:U - The use-after-return corrupts the kernel stack of the task or kworker that called qnap_mcu_exec() on the same host; it does not cross a VM, IOMMU, or sandbox boundary into a separate security authority.\nC:H - A late UART write of up to 37 bytes into a returned kernel stack frame is use-after-return memory corruption; the attacker can groom that stack with a follow-up syscall so the overwrite becomes a kernel read primitive, which per UAF guidance is High confidentiality impact.\nI:H - The same write into the abandoned stack can smash return addresses, saved registers, and pointers of the next function on that stack, including after attacker-controlled syscall grooming, yielding control-flow hijack; use-after-return stack corruption is High integrity impact.\nA:H - Writing MCU UART bytes into a kernel stack frame that has already been left corrupts in-use stack state and causes an oops or panic even when not turned into a full exploit, fully denying availability."
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"affected": [
|
||
{
|
||
"product": "Linux",
|
||
"vendor": "Linux",
|
||
"defaultStatus": "unaffected",
|
||
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
|
||
"programFiles": [
|
||
"drivers/mfd/qnap-mcu.c"
|
||
],
|
||
"versions": [
|
||
{
|
||
"version": "998f70d1806bb718a7565f350283e4a79c8cbb4b",
|
||
"lessThan": "0b6680e306397097a97767447368221fac753809",
|
||
"status": "affected",
|
||
"versionType": "git"
|
||
},
|
||
{
|
||
"version": "998f70d1806bb718a7565f350283e4a79c8cbb4b",
|
||
"lessThan": "8391ee06d08845a0a165b5fe679ba326915166b2",
|
||
"status": "affected",
|
||
"versionType": "git"
|
||
},
|
||
{
|
||
"version": "998f70d1806bb718a7565f350283e4a79c8cbb4b",
|
||
"lessThan": "47504742cea7878ebd1bf1491bbed923df6b90b1",
|
||
"status": "affected",
|
||
"versionType": "git"
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"product": "Linux",
|
||
"vendor": "Linux",
|
||
"defaultStatus": "affected",
|
||
"repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
|
||
"programFiles": [
|
||
"drivers/mfd/qnap-mcu.c"
|
||
],
|
||
"versions": [
|
||
{
|
||
"version": "6.14",
|
||
"status": "affected"
|
||
},
|
||
{
|
||
"version": "0",
|
||
"lessThan": "6.14",
|
||
"status": "unaffected",
|
||
"versionType": "semver"
|
||
},
|
||
{
|
||
"version": "6.18.51",
|
||
"lessThanOrEqual": "6.18.*",
|
||
"status": "unaffected",
|
||
"versionType": "semver"
|
||
},
|
||
{
|
||
"version": "7.2.4",
|
||
"lessThanOrEqual": "7.2.*",
|
||
"status": "unaffected",
|
||
"versionType": "semver"
|
||
},
|
||
{
|
||
"version": "7.3",
|
||
"lessThanOrEqual": "*",
|
||
"status": "unaffected",
|
||
"versionType": "original_commit_for_fix"
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"cpeApplicability": [
|
||
{
|
||
"nodes": [
|
||
{
|
||
"operator": "OR",
|
||
"negate": false,
|
||
"cpeMatch": [
|
||
{
|
||
"vulnerable": true,
|
||
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
||
"versionStartIncluding": "6.14",
|
||
"versionEndExcluding": "6.18.51"
|
||
},
|
||
{
|
||
"vulnerable": true,
|
||
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
||
"versionStartIncluding": "6.14",
|
||
"versionEndExcluding": "7.2.4"
|
||
},
|
||
{
|
||
"vulnerable": true,
|
||
"criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
|
||
"versionStartIncluding": "6.14",
|
||
"versionEndExcluding": "7.3"
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"references": [
|
||
{
|
||
"url": "https://git.kernel.org/stable/c/0b6680e306397097a97767447368221fac753809"
|
||
},
|
||
{
|
||
"url": "https://git.kernel.org/stable/c/8391ee06d08845a0a165b5fe679ba326915166b2"
|
||
},
|
||
{
|
||
"url": "https://git.kernel.org/stable/c/47504742cea7878ebd1bf1491bbed923df6b90b1"
|
||
}
|
||
],
|
||
"title": "mfd: qnap-mcu: keep the reply buffer alive past a command timeout",
|
||
"x_generator": {
|
||
"engine": "bippy-1.2.0"
|
||
}
|
||
}
|
||
}
|
||
} |