{ "dataType": "CVE_RECORD", "dataVersion": "5.2", "cveMetadata": { "cveId": "CVE-2024-56788", "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "state": "PUBLISHED", "assignerShortName": "Linux", "dateReserved": "2024-12-29T11:26:39.770Z", "datePublished": "2025-01-11T12:35:47.985Z", "dateUpdated": "2026-08-05T11:46:29.921Z" }, "containers": { "cna": { "providerMetadata": { "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67", "shortName": "Linux", "dateUpdated": "2026-08-05T11:46:29.921Z" }, "descriptions": [ { "lang": "en", "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nnet: ethernet: oa_tc6: fix tx skb race condition between reference pointers\n\nThere are two skb pointers to manage tx skb's enqueued from n/w stack.\nwaiting_tx_skb pointer points to the tx skb which needs to be processed\nand ongoing_tx_skb pointer points to the tx skb which is being processed.\n\nSPI thread prepares the tx data chunks from the tx skb pointed by the\nongoing_tx_skb pointer. When the tx skb pointed by the ongoing_tx_skb is\nprocessed, the tx skb pointed by the waiting_tx_skb is assigned to\nongoing_tx_skb and the waiting_tx_skb pointer is assigned with NULL.\nWhenever there is a new tx skb from n/w stack, it will be assigned to\nwaiting_tx_skb pointer if it is NULL. Enqueuing and processing of a tx skb\nhandled in two different threads.\n\nConsider a scenario where the SPI thread processed an ongoing_tx_skb and\nit moves next tx skb from waiting_tx_skb pointer to ongoing_tx_skb pointer\nwithout doing any NULL check. At this time, if the waiting_tx_skb pointer\nis NULL then ongoing_tx_skb pointer is also assigned with NULL. After\nthat, if a new tx skb is assigned to waiting_tx_skb pointer by the n/w\nstack and there is a chance to overwrite the tx skb pointer with NULL in\nthe SPI thread. Finally one of the tx skb will be left as unhandled,\nresulting packet missing and memory leak.\n\n- Consider the below scenario where the TXC reported from the previous\ntransfer is 10 and ongoing_tx_skb holds an tx ethernet frame which can be\ntransported in 20 TXCs and waiting_tx_skb is still NULL.\n\ttx_credits = 10; /* 21 are filled in the previous transfer */\n\tongoing_tx_skb = 20;\n\twaiting_tx_skb = NULL; /* Still NULL */\n- So, (tc6->ongoing_tx_skb || tc6->waiting_tx_skb) becomes true.\n- After oa_tc6_prepare_spi_tx_buf_for_tx_skbs()\n\tongoing_tx_skb = 10;\n\twaiting_tx_skb = NULL; /* Still NULL */\n- Perform SPI transfer.\n- Process SPI rx buffer to get the TXC from footers.\n- Now let's assume previously filled 21 TXCs are freed so we are good to\ntransport the next remaining 10 tx chunks from ongoing_tx_skb.\n\ttx_credits = 21;\n\tongoing_tx_skb = 10;\n\twaiting_tx_skb = NULL;\n- So, (tc6->ongoing_tx_skb || tc6->waiting_tx_skb) becomes true again.\n- In the oa_tc6_prepare_spi_tx_buf_for_tx_skbs()\n\tongoing_tx_skb = NULL;\n\twaiting_tx_skb = NULL;\n\n- Now the below bad case might happen,\n\nThread1 (oa_tc6_start_xmit)\tThread2 (oa_tc6_spi_thread_handler)\n---------------------------\t-----------------------------------\n- if waiting_tx_skb is NULL\n\t\t\t\t- if ongoing_tx_skb is NULL\n\t\t\t\t- ongoing_tx_skb = waiting_tx_skb\n- waiting_tx_skb = skb\n\t\t\t\t- waiting_tx_skb = NULL\n\t\t\t\t...\n\t\t\t\t- ongoing_tx_skb = NULL\n- if waiting_tx_skb is NULL\n- waiting_tx_skb = skb\n\nTo overcome the above issue, protect the moving of tx skb reference from\nwaiting_tx_skb pointer to ongoing_tx_skb pointer and assigning new tx skb\nto waiting_tx_skb pointer, so that the other thread can't access the\nwaiting_tx_skb pointer until the current thread completes moving the tx\nskb reference safely." } ], "metrics": [ { "cvssV3_1": { "version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", "baseScore": 7.5, "baseSeverity": "HIGH" }, "scenarios": [ { "lang": "en", "value": "AV:N - The race is driven by the interface transmit path, which an unauthenticated remote host drives by sending traffic that this device replies to, routes, or bridges out the 10BASE-T1S port — a common role for LAN865x gateways in automotive and industrial deployments.\nAC:L - The attacker controls both sides of the race: their packet flood drives `oa_tc6_start_xmit()` and simultaneously wakes the SPI kthread that races it, so sustained traffic hits the unsynchronized window repeatedly rather than depending on any condition outside the attacker's influence.\nPR:N - There is no capability check, authentication gate, or privileged interface anywhere on the path — merely causing frames to be transmitted out the interface is enough, which a remote unauthenticated peer accomplishes with ordinary traffic.\nUI:N - No victim action is required; the race triggers on normal packet transmission driven entirely by the attacker.\nS:U - The lost skb and the resulting memory exhaustion stay within the kernel's own security authority, with no crossing of a VM, IOMMU, or sandbox boundary.\nC:N - The defect destroys a pointer rather than dereferencing an invalid one; no freed, out-of-bounds, or uninitialized memory is ever read, and no kernel address is disclosed to userspace or the wire.\nI:N - No memory is corrupted and no attacker-controlled write primitive exists — I confirmed the two pointers can never alias, so there is no double-free or use-after-free; the dropped frame is data loss, which counts under availability.\nA:H - Every occurrence permanently leaks a full skb with no reclaim path, and a remote attacker can drive it indefinitely, exhausting memory on the RAM-constrained embedded targets this driver ships on and leading to OOM; frames are also silently dropped without even a `tx_dropped` accounting bump." } ] } ], "affected": [ { "product": "Linux", "vendor": "Linux", "defaultStatus": "unaffected", "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git", "programFiles": [ "drivers/net/ethernet/oa_tc6.c" ], "versions": [ { "version": "53fbde8ab21e8c2c6187159cc17fc10cbf20900a", "lessThan": "1f2eb6c32bae04b375bb7a0aedbeefb6dbbcb775", "status": "affected", "versionType": "git" }, { "version": "53fbde8ab21e8c2c6187159cc17fc10cbf20900a", "lessThan": "e592b5110b3e9393881b0a019d86832bbf71a47f", "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/net/ethernet/oa_tc6.c" ], "versions": [ { "version": "6.12", "status": "affected" }, { "version": "0", "lessThan": "6.12", "status": "unaffected", "versionType": "semver" }, { "version": "6.12.7", "lessThanOrEqual": "6.12.*", "status": "unaffected", "versionType": "semver" }, { "version": "6.13", "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.12", "versionEndExcluding": "6.12.7" }, { "vulnerable": true, "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*", "versionStartIncluding": "6.12", "versionEndExcluding": "6.13" } ] } ] } ], "references": [ { "url": "https://git.kernel.org/stable/c/1f2eb6c32bae04b375bb7a0aedbeefb6dbbcb775" }, { "url": "https://git.kernel.org/stable/c/e592b5110b3e9393881b0a019d86832bbf71a47f" } ], "title": "net: ethernet: oa_tc6: fix tx skb race condition between reference pointers", "x_generator": { "engine": "bippy-1.2.0" } } } }